// 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 at the lesser of 30 days or
// 1/3 of the certificate lifetime.
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) {
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.NotBefore, 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.NotBefore, 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, notBefore, notAfter 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(notBefore, notAfter)
}
// 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) 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"
)
// 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(notBefore, notAfter time.Time) {
dr.timerMu.Lock()
defer dr.timerMu.Unlock()
if dr.timer != nil {
return
}
dr.timer = time.AfterFunc(dr.next(notBefore, notAfter), 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 = time.Hour / 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.NotBefore, tlscert.Leaf.NotAfter)
if next > 0 {
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.NotBefore, leaf.NotAfter), nil
}
// next returns the wait time before the next renewal should start.
// If manager.RenewBefore is set, it uses that capped at 30 days,
// otherwise it uses a default of 1/3 of the cert lifetime.
// It builds in a jitter of 10% of the renew threshold, capped at 1 hour.
func (dr *domainRenewal) next(notBefore, notAfter time.Time) time.Duration {
threshold := min(notAfter.Sub(notBefore)/3, 30*24*time.Hour)
if dr.m.RenewBefore > 0 {
threshold = min(dr.m.RenewBefore, 30*24*time.Hour)
}
maxJitter := min(threshold/10, time.Hour)
jitter := pseudoRand.int63n(int64(maxJitter))
renewAt := notAfter.Add(-(threshold - time.Duration(jitter)))
renewWait := renewAt.Sub(dr.m.now())
return max(0, renewWait)
}
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 != "" {
if prompt == nil {
return nil, errors.New("acme: missing Manager.Prompt to accept server's terms of service")
}
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 fips140Enforced() {
return nil, errors.New("chacha20poly1305: use of ChaCha20Poly1305 is not allowed in FIPS 140-only mode")
}
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 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 chacha20poly1305
import "crypto/fips140"
func fips140Enforced() bool { return fips140.Enforced() }
// 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 fips140Enforced() {
return nil, errors.New("chacha20poly1305: use of ChaCha20Poly1305 is not allowed in FIPS 140-only mode")
}
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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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 PrivateKeyResults []*ed25519.PrivateKey
PrivateKeyResultsIndex := 0
var PublicKeyResults []*ed25519.PublicKey
PublicKeyResultsIndex := 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) {
PrivateKeyNb := 0
PrivateKeyResultsIndex := 0
PublicKeyNb := 0
PublicKeyResultsIndex := 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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 r <= 0 || p <= 0 {
return nil, errors.New("scrypt: parameters must be > 0")
}
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")
}
// Each ASN.1 encoded OID must have a minimum
// of 2 bytes; 64 maximum mechanisms is an
// arbitrary, but reasonable ceiling.
const maxMechs = 64
if n > maxMechs || int(n)*2 > len(rest) {
return nil, errors.New("invalid mechanism count")
}
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.11
// 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.11
// 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.11
// 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 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
var Rectangle52_12Results []*fixed.Rectangle52_12
Rectangle52_12ResultsIndex := 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) {
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
Rectangle52_12Nb := 0
Rectangle52_12ResultsIndex := 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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 (
"slices"
)
// 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 {
b := []byte("dnsmessage.SVCBResource{" +
"Priority: " + printUint16(r.Priority) + ", " +
"Target: " + r.Target.GoString() + ", " +
"Params: []dnsmessage.SVCParam{")
if len(r.Params) > 0 {
b = append(b, r.Params[0].GoString()...)
for _, p := range r.Params[1:] {
b = append(b, ", "+p.GoString()...)
}
}
b = append(b, "}}"...)
return string(b)
}
// 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) > (1<<16)-1 {
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.11
// 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 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 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 OptionNewFromFuzz(p *OptionStruct) *dnsmessage.Option{
if p == nil {
return nil
}
return &dnsmessage.Option{
Code: uint16(p.Code),
Data: p.Data,
}
}
func SVCParamNewFromFuzz(p *SVCParamStruct) *dnsmessage.SVCParam{
if p == nil {
return nil
}
return &dnsmessage.SVCParam{
Key: SVCParamKeyNewFromFuzz(p.Key),
Value: p.Value,
}
}
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 SOAResourceResults []*dnsmessage.SOAResource
SOAResourceResultsIndex := 0
var SRVResourceResults []*dnsmessage.SRVResource
SRVResourceResultsIndex := 0
var HeaderResults []*dnsmessage.Header
HeaderResultsIndex := 0
var ResourceHeaderResults []*dnsmessage.ResourceHeader
ResourceHeaderResultsIndex := 0
var UnknownResourceResults []*dnsmessage.UnknownResource
UnknownResourceResultsIndex := 0
var SVCBResourceResults []*dnsmessage.SVCBResource
SVCBResourceResultsIndex := 0
var NameResults []*dnsmessage.Name
NameResultsIndex := 0
var QuestionResults []*dnsmessage.Question
QuestionResultsIndex := 0
var CNAMEResourceResults []*dnsmessage.CNAMEResource
CNAMEResourceResultsIndex := 0
var NSResourceResults []*dnsmessage.NSResource
NSResourceResultsIndex := 0
var PTRResourceResults []*dnsmessage.PTRResource
PTRResourceResultsIndex := 0
var TXTResourceResults []*dnsmessage.TXTResource
TXTResourceResultsIndex := 0
var AAAAResourceResults []*dnsmessage.AAAAResource
AAAAResourceResultsIndex := 0
var BuilderResults []*dnsmessage.Builder
BuilderResultsIndex := 0
var AResourceResults []*dnsmessage.AResource
AResourceResultsIndex := 0
var OPTResourceResults []*dnsmessage.OPTResource
OPTResourceResultsIndex := 0
var HTTPSResourceResults []*dnsmessage.HTTPSResource
HTTPSResourceResultsIndex := 0
var RCodeResults []*dnsmessage.RCode
RCodeResultsIndex := 0
var ResourceResults []*dnsmessage.Resource
ResourceResultsIndex := 0
var MXResourceResults []*dnsmessage.MXResource
MXResourceResultsIndex := 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) {
SOAResourceNb := 0
SOAResourceResultsIndex := 0
SRVResourceNb := 0
SRVResourceResultsIndex := 0
HeaderNb := 0
HeaderResultsIndex := 0
ResourceHeaderNb := 0
ResourceHeaderResultsIndex := 0
UnknownResourceNb := 0
UnknownResourceResultsIndex := 0
SVCBResourceNb := 0
SVCBResourceResultsIndex := 0
NameNb := 0
NameResultsIndex := 0
QuestionNb := 0
QuestionResultsIndex := 0
CNAMEResourceNb := 0
CNAMEResourceResultsIndex := 0
NSResourceNb := 0
NSResourceResultsIndex := 0
PTRResourceNb := 0
PTRResourceResultsIndex := 0
TXTResourceNb := 0
TXTResourceResultsIndex := 0
AAAAResourceNb := 0
AAAAResourceResultsIndex := 0
BuilderNb := 0
BuilderResultsIndex := 0
AResourceNb := 0
AResourceResultsIndex := 0
OPTResourceNb := 0
OPTResourceResultsIndex := 0
HTTPSResourceNb := 0
HTTPSResourceResultsIndex := 0
RCodeNb := 0
RCodeResultsIndex := 0
ResourceNb := 0
ResourceResultsIndex := 0
MXResourceNb := 0
MXResourceResultsIndex := 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.11
// 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 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[1].Descriptor()
}
func (TypeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
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{1}
}
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[2].Descriptor()
}
func (ClassEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[2]
}
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{2}
}
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[0]
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[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 OptionStruct.ProtoReflect.Descriptor instead.
func (*OptionStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
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 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[1]
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[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 SVCParamStruct.ProtoReflect.Descriptor instead.
func (*SVCParamStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
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 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\"6\n" +
"\fOptionStruct\x12\x12\n" +
"\x04Code\x18\x01 \x01(\rR\x04Code\x12\x12\n" +
"\x04Data\x18\x02 \x01(\fR\x04Data\"T\n" +
"\x0eSVCParamStruct\x12,\n" +
"\x03Key\x18\x01 \x01(\x0e2\x1a.ngolofuzz.SVCParamKeyEnumR\x03Key\x12\x14\n" +
"\x05Value\x18\x02 \x01(\fR\x05Value\"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*\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\x10*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\x04B!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
(TypeEnum)(0), // 1: ngolofuzz.TypeEnum
(ClassEnum)(0), // 2: ngolofuzz.ClassEnum
(*OptionStruct)(nil), // 3: ngolofuzz.OptionStruct
(*SVCParamStruct)(nil), // 4: ngolofuzz.SVCParamStruct
(*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
1, // 1: ngolofuzz.TypeNgdotStringArgs.t:type_name -> ngolofuzz.TypeEnum
1, // 2: ngolofuzz.TypeNgdotGoStringArgs.t:type_name -> ngolofuzz.TypeEnum
2, // 3: ngolofuzz.ClassNgdotStringArgs.c:type_name -> ngolofuzz.ClassEnum
2, // 4: ngolofuzz.ClassNgdotGoStringArgs.c:type_name -> ngolofuzz.ClassEnum
3, // 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
4, // 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 NodeTypeNewFromFuzz(p NodeTypeEnum) html.NodeType{
switch p {
case 1:
return html.TextNode
case 2:
return html.DocumentNode
case 3:
return html.ElementNode
case 4:
return html.CommentNode
case 5:
return html.DoctypeNode
case 6:
return html.RawNode
}
return html.ErrorNode
}
func ConvertNodeTypeNewFromFuzz(a []NodeTypeEnum) []html.NodeType{
r := make([]html.NodeType, len(a))
for i := range a {
r[i] = NodeTypeNewFromFuzz(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 TokenTypeResults []*html.TokenType
TokenTypeResultsIndex := 0
var TokenResults []*html.Token
TokenResultsIndex := 0
var TokenizerResults []*html.Tokenizer
TokenizerResultsIndex := 0
var NodeResults []*html.Node
NodeResultsIndex := 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_NodeTypeNgdotString:
arg0 := NodeTypeNewFromFuzz(a.NodeTypeNgdotString.I)
arg0.String()
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) {
TokenTypeNb := 0
TokenTypeResultsIndex := 0
TokenNb := 0
TokenResultsIndex := 0
TokenizerNb := 0
TokenizerResultsIndex := 0
NodeNb := 0
NodeResultsIndex := 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_NodeTypeNgdotString:
w.WriteString(fmt.Sprintf("NodeTypeNewFromFuzz(%#+v).String()\n", a.NodeTypeNgdotString.I))
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.11
// 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 NodeTypeEnum int32
const (
NodeTypeEnum_ErrorNode NodeTypeEnum = 0
NodeTypeEnum_TextNode NodeTypeEnum = 1
NodeTypeEnum_DocumentNode NodeTypeEnum = 2
NodeTypeEnum_ElementNode NodeTypeEnum = 3
NodeTypeEnum_CommentNode NodeTypeEnum = 4
NodeTypeEnum_DoctypeNode NodeTypeEnum = 5
NodeTypeEnum_RawNode NodeTypeEnum = 6
)
// Enum value maps for NodeTypeEnum.
var (
NodeTypeEnum_name = map[int32]string{
0: "ErrorNode",
1: "TextNode",
2: "DocumentNode",
3: "ElementNode",
4: "CommentNode",
5: "DoctypeNode",
6: "RawNode",
}
NodeTypeEnum_value = map[string]int32{
"ErrorNode": 0,
"TextNode": 1,
"DocumentNode": 2,
"ElementNode": 3,
"CommentNode": 4,
"DoctypeNode": 5,
"RawNode": 6,
}
)
func (x NodeTypeEnum) Enum() *NodeTypeEnum {
p := new(NodeTypeEnum)
*p = x
return p
}
func (x NodeTypeEnum) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (NodeTypeEnum) Descriptor() protoreflect.EnumDescriptor {
return file_ngolofuzz_proto_enumTypes[0].Descriptor()
}
func (NodeTypeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
func (x NodeTypeEnum) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use NodeTypeEnum.Descriptor instead.
func (NodeTypeEnum) EnumDescriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{0}
}
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 NodeTypeNgdotStringArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
I NodeTypeEnum `protobuf:"varint,1,opt,name=i,proto3,enum=ngolofuzz.NodeTypeEnum" json:"i,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *NodeTypeNgdotStringArgs) Reset() {
*x = NodeTypeNgdotStringArgs{}
mi := &file_ngolofuzz_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *NodeTypeNgdotStringArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NodeTypeNgdotStringArgs) ProtoMessage() {}
func (x *NodeTypeNgdotStringArgs) 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 NodeTypeNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*NodeTypeNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{8}
}
func (x *NodeTypeNgdotStringArgs) GetI() NodeTypeEnum {
if x != nil {
return x.I
}
return NodeTypeEnum_ErrorNode
}
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[9]
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[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 ParseArgs.ProtoReflect.Descriptor instead.
func (*ParseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{9}
}
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[10]
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[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 ParseFragmentArgs.ProtoReflect.Descriptor instead.
func (*ParseFragmentArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{10}
}
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[11]
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[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 ParseOptionEnableScriptingArgs.ProtoReflect.Descriptor instead.
func (*ParseOptionEnableScriptingArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{11}
}
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[12]
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[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 RenderArgs.ProtoReflect.Descriptor instead.
func (*RenderArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{12}
}
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[13]
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[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 TokenTypeNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*TokenTypeNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{13}
}
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[14]
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[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 TokenNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*TokenNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{14}
}
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[15]
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[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 TokenizerNgdotAllowCDATAArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotAllowCDATAArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{15}
}
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[16]
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[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 TokenizerNgdotNextIsNotRawTextArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotNextIsNotRawTextArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{16}
}
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[17]
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[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 TokenizerNgdotErrArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotErrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{17}
}
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[18]
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[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 TokenizerNgdotBufferedArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotBufferedArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{18}
}
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[19]
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[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 TokenizerNgdotNextArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotNextArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{19}
}
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[20]
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[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 TokenizerNgdotRawArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotRawArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{20}
}
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[21]
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[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 TokenizerNgdotTextArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotTextArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{21}
}
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[22]
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[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 TokenizerNgdotTagNameArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotTagNameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{22}
}
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[23]
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[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 TokenizerNgdotTagAttrArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotTagAttrArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{23}
}
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[24]
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[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 TokenizerNgdotTokenArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotTokenArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{24}
}
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[25]
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[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 TokenizerNgdotSetMaxBufArgs.ProtoReflect.Descriptor instead.
func (*TokenizerNgdotSetMaxBufArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{25}
}
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[26]
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[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 NewTokenizerArgs.ProtoReflect.Descriptor instead.
func (*NewTokenizerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{26}
}
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[27]
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[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 NewTokenizerFragmentArgs.ProtoReflect.Descriptor instead.
func (*NewTokenizerFragmentArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{27}
}
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_NodeTypeNgdotString
// *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[28]
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[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 NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{28}
}
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) GetNodeTypeNgdotString() *NodeTypeNgdotStringArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_NodeTypeNgdotString); ok {
return x.NodeTypeNgdotString
}
}
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_NodeTypeNgdotString struct {
NodeTypeNgdotString *NodeTypeNgdotStringArgs `protobuf:"bytes,9,opt,name=NodeTypeNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_Parse struct {
Parse *ParseArgs `protobuf:"bytes,10,opt,name=Parse,proto3,oneof"`
}
type NgoloFuzzOne_ParseFragment struct {
ParseFragment *ParseFragmentArgs `protobuf:"bytes,11,opt,name=ParseFragment,proto3,oneof"`
}
type NgoloFuzzOne_ParseOptionEnableScripting struct {
ParseOptionEnableScripting *ParseOptionEnableScriptingArgs `protobuf:"bytes,12,opt,name=ParseOptionEnableScripting,proto3,oneof"`
}
type NgoloFuzzOne_Render struct {
Render *RenderArgs `protobuf:"bytes,13,opt,name=Render,proto3,oneof"`
}
type NgoloFuzzOne_TokenTypeNgdotString struct {
TokenTypeNgdotString *TokenTypeNgdotStringArgs `protobuf:"bytes,14,opt,name=TokenTypeNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_TokenNgdotString struct {
TokenNgdotString *TokenNgdotStringArgs `protobuf:"bytes,15,opt,name=TokenNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotAllowCDATA struct {
TokenizerNgdotAllowCDATA *TokenizerNgdotAllowCDATAArgs `protobuf:"bytes,16,opt,name=TokenizerNgdotAllowCDATA,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotNextIsNotRawText struct {
TokenizerNgdotNextIsNotRawText *TokenizerNgdotNextIsNotRawTextArgs `protobuf:"bytes,17,opt,name=TokenizerNgdotNextIsNotRawText,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotErr struct {
TokenizerNgdotErr *TokenizerNgdotErrArgs `protobuf:"bytes,18,opt,name=TokenizerNgdotErr,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotBuffered struct {
TokenizerNgdotBuffered *TokenizerNgdotBufferedArgs `protobuf:"bytes,19,opt,name=TokenizerNgdotBuffered,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotNext struct {
TokenizerNgdotNext *TokenizerNgdotNextArgs `protobuf:"bytes,20,opt,name=TokenizerNgdotNext,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotRaw struct {
TokenizerNgdotRaw *TokenizerNgdotRawArgs `protobuf:"bytes,21,opt,name=TokenizerNgdotRaw,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotText struct {
TokenizerNgdotText *TokenizerNgdotTextArgs `protobuf:"bytes,22,opt,name=TokenizerNgdotText,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotTagName struct {
TokenizerNgdotTagName *TokenizerNgdotTagNameArgs `protobuf:"bytes,23,opt,name=TokenizerNgdotTagName,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotTagAttr struct {
TokenizerNgdotTagAttr *TokenizerNgdotTagAttrArgs `protobuf:"bytes,24,opt,name=TokenizerNgdotTagAttr,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotToken struct {
TokenizerNgdotToken *TokenizerNgdotTokenArgs `protobuf:"bytes,25,opt,name=TokenizerNgdotToken,proto3,oneof"`
}
type NgoloFuzzOne_TokenizerNgdotSetMaxBuf struct {
TokenizerNgdotSetMaxBuf *TokenizerNgdotSetMaxBufArgs `protobuf:"bytes,26,opt,name=TokenizerNgdotSetMaxBuf,proto3,oneof"`
}
type NgoloFuzzOne_NewTokenizer struct {
NewTokenizer *NewTokenizerArgs `protobuf:"bytes,27,opt,name=NewTokenizer,proto3,oneof"`
}
type NgoloFuzzOne_NewTokenizerFragment struct {
NewTokenizerFragment *NewTokenizerFragmentArgs `protobuf:"bytes,28,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_NodeTypeNgdotString) 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[29]
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[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 NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{29}
}
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[30]
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[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 NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{30}
}
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\"@\n" +
"\x17NodeTypeNgdotStringArgs\x12%\n" +
"\x01i\x18\x01 \x01(\x0e2\x17.ngolofuzz.NodeTypeEnumR\x01i\"\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\"\xf7\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\x12V\n" +
"\x13NodeTypeNgdotString\x18\t \x01(\v2\".ngolofuzz.NodeTypeNgdotStringArgsH\x00R\x13NodeTypeNgdotString\x12,\n" +
"\x05Parse\x18\n" +
" \x01(\v2\x14.ngolofuzz.ParseArgsH\x00R\x05Parse\x12D\n" +
"\rParseFragment\x18\v \x01(\v2\x1c.ngolofuzz.ParseFragmentArgsH\x00R\rParseFragment\x12k\n" +
"\x1aParseOptionEnableScripting\x18\f \x01(\v2).ngolofuzz.ParseOptionEnableScriptingArgsH\x00R\x1aParseOptionEnableScripting\x12/\n" +
"\x06Render\x18\r \x01(\v2\x15.ngolofuzz.RenderArgsH\x00R\x06Render\x12Y\n" +
"\x14TokenTypeNgdotString\x18\x0e \x01(\v2#.ngolofuzz.TokenTypeNgdotStringArgsH\x00R\x14TokenTypeNgdotString\x12M\n" +
"\x10TokenNgdotString\x18\x0f \x01(\v2\x1f.ngolofuzz.TokenNgdotStringArgsH\x00R\x10TokenNgdotString\x12e\n" +
"\x18TokenizerNgdotAllowCDATA\x18\x10 \x01(\v2'.ngolofuzz.TokenizerNgdotAllowCDATAArgsH\x00R\x18TokenizerNgdotAllowCDATA\x12w\n" +
"\x1eTokenizerNgdotNextIsNotRawText\x18\x11 \x01(\v2-.ngolofuzz.TokenizerNgdotNextIsNotRawTextArgsH\x00R\x1eTokenizerNgdotNextIsNotRawText\x12P\n" +
"\x11TokenizerNgdotErr\x18\x12 \x01(\v2 .ngolofuzz.TokenizerNgdotErrArgsH\x00R\x11TokenizerNgdotErr\x12_\n" +
"\x16TokenizerNgdotBuffered\x18\x13 \x01(\v2%.ngolofuzz.TokenizerNgdotBufferedArgsH\x00R\x16TokenizerNgdotBuffered\x12S\n" +
"\x12TokenizerNgdotNext\x18\x14 \x01(\v2!.ngolofuzz.TokenizerNgdotNextArgsH\x00R\x12TokenizerNgdotNext\x12P\n" +
"\x11TokenizerNgdotRaw\x18\x15 \x01(\v2 .ngolofuzz.TokenizerNgdotRawArgsH\x00R\x11TokenizerNgdotRaw\x12S\n" +
"\x12TokenizerNgdotText\x18\x16 \x01(\v2!.ngolofuzz.TokenizerNgdotTextArgsH\x00R\x12TokenizerNgdotText\x12\\\n" +
"\x15TokenizerNgdotTagName\x18\x17 \x01(\v2$.ngolofuzz.TokenizerNgdotTagNameArgsH\x00R\x15TokenizerNgdotTagName\x12\\\n" +
"\x15TokenizerNgdotTagAttr\x18\x18 \x01(\v2$.ngolofuzz.TokenizerNgdotTagAttrArgsH\x00R\x15TokenizerNgdotTagAttr\x12V\n" +
"\x13TokenizerNgdotToken\x18\x19 \x01(\v2\".ngolofuzz.TokenizerNgdotTokenArgsH\x00R\x13TokenizerNgdotToken\x12b\n" +
"\x17TokenizerNgdotSetMaxBuf\x18\x1a \x01(\v2&.ngolofuzz.TokenizerNgdotSetMaxBufArgsH\x00R\x17TokenizerNgdotSetMaxBuf\x12A\n" +
"\fNewTokenizer\x18\x1b \x01(\v2\x1b.ngolofuzz.NewTokenizerArgsH\x00R\fNewTokenizer\x12Y\n" +
"\x14NewTokenizerFragment\x18\x1c \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\x04list*}\n" +
"\fNodeTypeEnum\x12\r\n" +
"\tErrorNode\x10\x00\x12\f\n" +
"\bTextNode\x10\x01\x12\x10\n" +
"\fDocumentNode\x10\x02\x12\x0f\n" +
"\vElementNode\x10\x03\x12\x0f\n" +
"\vCommentNode\x10\x04\x12\x0f\n" +
"\vDoctypeNode\x10\x05\x12\v\n" +
"\aRawNode\x10\x06B\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_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_ngolofuzz_proto_msgTypes = make([]protoimpl.MessageInfo, 31)
var file_ngolofuzz_proto_goTypes = []any{
(NodeTypeEnum)(0), // 0: ngolofuzz.NodeTypeEnum
(*EscapeStringArgs)(nil), // 1: ngolofuzz.EscapeStringArgs
(*UnescapeStringArgs)(nil), // 2: ngolofuzz.UnescapeStringArgs
(*NodeNgdotAncestorsArgs)(nil), // 3: ngolofuzz.NodeNgdotAncestorsArgs
(*NodeNgdotChildNodesArgs)(nil), // 4: ngolofuzz.NodeNgdotChildNodesArgs
(*NodeNgdotDescendantsArgs)(nil), // 5: ngolofuzz.NodeNgdotDescendantsArgs
(*NodeNgdotInsertBeforeArgs)(nil), // 6: ngolofuzz.NodeNgdotInsertBeforeArgs
(*NodeNgdotAppendChildArgs)(nil), // 7: ngolofuzz.NodeNgdotAppendChildArgs
(*NodeNgdotRemoveChildArgs)(nil), // 8: ngolofuzz.NodeNgdotRemoveChildArgs
(*NodeTypeNgdotStringArgs)(nil), // 9: ngolofuzz.NodeTypeNgdotStringArgs
(*ParseArgs)(nil), // 10: ngolofuzz.ParseArgs
(*ParseFragmentArgs)(nil), // 11: ngolofuzz.ParseFragmentArgs
(*ParseOptionEnableScriptingArgs)(nil), // 12: ngolofuzz.ParseOptionEnableScriptingArgs
(*RenderArgs)(nil), // 13: ngolofuzz.RenderArgs
(*TokenTypeNgdotStringArgs)(nil), // 14: ngolofuzz.TokenTypeNgdotStringArgs
(*TokenNgdotStringArgs)(nil), // 15: ngolofuzz.TokenNgdotStringArgs
(*TokenizerNgdotAllowCDATAArgs)(nil), // 16: ngolofuzz.TokenizerNgdotAllowCDATAArgs
(*TokenizerNgdotNextIsNotRawTextArgs)(nil), // 17: ngolofuzz.TokenizerNgdotNextIsNotRawTextArgs
(*TokenizerNgdotErrArgs)(nil), // 18: ngolofuzz.TokenizerNgdotErrArgs
(*TokenizerNgdotBufferedArgs)(nil), // 19: ngolofuzz.TokenizerNgdotBufferedArgs
(*TokenizerNgdotNextArgs)(nil), // 20: ngolofuzz.TokenizerNgdotNextArgs
(*TokenizerNgdotRawArgs)(nil), // 21: ngolofuzz.TokenizerNgdotRawArgs
(*TokenizerNgdotTextArgs)(nil), // 22: ngolofuzz.TokenizerNgdotTextArgs
(*TokenizerNgdotTagNameArgs)(nil), // 23: ngolofuzz.TokenizerNgdotTagNameArgs
(*TokenizerNgdotTagAttrArgs)(nil), // 24: ngolofuzz.TokenizerNgdotTagAttrArgs
(*TokenizerNgdotTokenArgs)(nil), // 25: ngolofuzz.TokenizerNgdotTokenArgs
(*TokenizerNgdotSetMaxBufArgs)(nil), // 26: ngolofuzz.TokenizerNgdotSetMaxBufArgs
(*NewTokenizerArgs)(nil), // 27: ngolofuzz.NewTokenizerArgs
(*NewTokenizerFragmentArgs)(nil), // 28: ngolofuzz.NewTokenizerFragmentArgs
(*NgoloFuzzOne)(nil), // 29: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 30: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 31: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
0, // 0: ngolofuzz.NodeTypeNgdotStringArgs.i:type_name -> ngolofuzz.NodeTypeEnum
1, // 1: ngolofuzz.NgoloFuzzOne.EscapeString:type_name -> ngolofuzz.EscapeStringArgs
2, // 2: ngolofuzz.NgoloFuzzOne.UnescapeString:type_name -> ngolofuzz.UnescapeStringArgs
3, // 3: ngolofuzz.NgoloFuzzOne.NodeNgdotAncestors:type_name -> ngolofuzz.NodeNgdotAncestorsArgs
4, // 4: ngolofuzz.NgoloFuzzOne.NodeNgdotChildNodes:type_name -> ngolofuzz.NodeNgdotChildNodesArgs
5, // 5: ngolofuzz.NgoloFuzzOne.NodeNgdotDescendants:type_name -> ngolofuzz.NodeNgdotDescendantsArgs
6, // 6: ngolofuzz.NgoloFuzzOne.NodeNgdotInsertBefore:type_name -> ngolofuzz.NodeNgdotInsertBeforeArgs
7, // 7: ngolofuzz.NgoloFuzzOne.NodeNgdotAppendChild:type_name -> ngolofuzz.NodeNgdotAppendChildArgs
8, // 8: ngolofuzz.NgoloFuzzOne.NodeNgdotRemoveChild:type_name -> ngolofuzz.NodeNgdotRemoveChildArgs
9, // 9: ngolofuzz.NgoloFuzzOne.NodeTypeNgdotString:type_name -> ngolofuzz.NodeTypeNgdotStringArgs
10, // 10: ngolofuzz.NgoloFuzzOne.Parse:type_name -> ngolofuzz.ParseArgs
11, // 11: ngolofuzz.NgoloFuzzOne.ParseFragment:type_name -> ngolofuzz.ParseFragmentArgs
12, // 12: ngolofuzz.NgoloFuzzOne.ParseOptionEnableScripting:type_name -> ngolofuzz.ParseOptionEnableScriptingArgs
13, // 13: ngolofuzz.NgoloFuzzOne.Render:type_name -> ngolofuzz.RenderArgs
14, // 14: ngolofuzz.NgoloFuzzOne.TokenTypeNgdotString:type_name -> ngolofuzz.TokenTypeNgdotStringArgs
15, // 15: ngolofuzz.NgoloFuzzOne.TokenNgdotString:type_name -> ngolofuzz.TokenNgdotStringArgs
16, // 16: ngolofuzz.NgoloFuzzOne.TokenizerNgdotAllowCDATA:type_name -> ngolofuzz.TokenizerNgdotAllowCDATAArgs
17, // 17: ngolofuzz.NgoloFuzzOne.TokenizerNgdotNextIsNotRawText:type_name -> ngolofuzz.TokenizerNgdotNextIsNotRawTextArgs
18, // 18: ngolofuzz.NgoloFuzzOne.TokenizerNgdotErr:type_name -> ngolofuzz.TokenizerNgdotErrArgs
19, // 19: ngolofuzz.NgoloFuzzOne.TokenizerNgdotBuffered:type_name -> ngolofuzz.TokenizerNgdotBufferedArgs
20, // 20: ngolofuzz.NgoloFuzzOne.TokenizerNgdotNext:type_name -> ngolofuzz.TokenizerNgdotNextArgs
21, // 21: ngolofuzz.NgoloFuzzOne.TokenizerNgdotRaw:type_name -> ngolofuzz.TokenizerNgdotRawArgs
22, // 22: ngolofuzz.NgoloFuzzOne.TokenizerNgdotText:type_name -> ngolofuzz.TokenizerNgdotTextArgs
23, // 23: ngolofuzz.NgoloFuzzOne.TokenizerNgdotTagName:type_name -> ngolofuzz.TokenizerNgdotTagNameArgs
24, // 24: ngolofuzz.NgoloFuzzOne.TokenizerNgdotTagAttr:type_name -> ngolofuzz.TokenizerNgdotTagAttrArgs
25, // 25: ngolofuzz.NgoloFuzzOne.TokenizerNgdotToken:type_name -> ngolofuzz.TokenizerNgdotTokenArgs
26, // 26: ngolofuzz.NgoloFuzzOne.TokenizerNgdotSetMaxBuf:type_name -> ngolofuzz.TokenizerNgdotSetMaxBufArgs
27, // 27: ngolofuzz.NgoloFuzzOne.NewTokenizer:type_name -> ngolofuzz.NewTokenizerArgs
28, // 28: ngolofuzz.NgoloFuzzOne.NewTokenizerFragment:type_name -> ngolofuzz.NewTokenizerFragmentArgs
29, // 29: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
30, // [30:30] is the sub-list for method output_type
30, // [30:30] is the sub-list for method input_type
30, // [30:30] is the sub-list for extension type_name
30, // [30:30] is the sub-list for extension extendee
0, // [0:30] 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[28].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_NodeTypeNgdotString)(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[29].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: 31,
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_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.11
// 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 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
case 10:
return http2.FramePriorityUpdate
}
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 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
case 7:
return http2.SettingNoRFC7540Priorities
}
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 PriorityParamNewFromFuzz(p *PriorityParamStruct) *http2.PriorityParam{
if p == nil {
return nil
}
return &http2.PriorityParam{
StreamDep: p.StreamDep,
Exclusive: p.Exclusive,
Weight: uint8(p.Weight),
}
}
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 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 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 FramerResults []*http2.Framer
FramerResultsIndex := 0
var SettingResults []*http2.Setting
SettingResultsIndex := 0
var FrameWriteRequestResults []*http2.FrameWriteRequest
FrameWriteRequestResultsIndex := 0
var FrameHeaderResults []*http2.FrameHeader
FrameHeaderResultsIndex := 0
var ClientConnResults []*http2.ClientConn
ClientConnResultsIndex := 0
var TransportResults []*http2.Transport
TransportResultsIndex := 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_FramerNgdotWritePriorityUpdate:
if len(FramerResults) == 0 {
continue
}
arg0 := FramerResults[FramerResultsIndex]
FramerResultsIndex = (FramerResultsIndex + 1) % len(FramerResults)
r0 := arg0.WritePriorityUpdate(a.FramerNgdotWritePriorityUpdate.StreamID, a.FramerNgdotWritePriorityUpdate.Priority)
if r0 != nil{
r0.Error()
return 0
}
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) {
FramerNb := 0
FramerResultsIndex := 0
SettingNb := 0
SettingResultsIndex := 0
FrameWriteRequestNb := 0
FrameWriteRequestResultsIndex := 0
FrameHeaderNb := 0
FrameHeaderResultsIndex := 0
ClientConnNb := 0
ClientConnResultsIndex := 0
TransportNb := 0
TransportResultsIndex := 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_FramerNgdotWritePriorityUpdate:
if FramerNb == 0 {
continue
}
w.WriteString(fmt.Sprintf("Framer%d.WritePriorityUpdate(%#+v, %#+v)\n", FramerResultsIndex, a.FramerNgdotWritePriorityUpdate.StreamID, a.FramerNgdotWritePriorityUpdate.Priority))
FramerResultsIndex = (FramerResultsIndex + 1) % FramerNb
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.11
// 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 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
FrameTypeEnum_FramePriorityUpdate FrameTypeEnum = 10
)
// 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",
10: "FramePriorityUpdate",
}
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,
"FramePriorityUpdate": 10,
}
)
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[0].Descriptor()
}
func (FrameTypeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
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{0}
}
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[1].Descriptor()
}
func (FlagsEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
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{1}
}
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[2].Descriptor()
}
func (ErrCodeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[2]
}
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{2}
}
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
SettingIDEnum_SettingNoRFC7540Priorities SettingIDEnum = 7
)
// 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",
7: "SettingNoRFC7540Priorities",
}
SettingIDEnum_value = map[string]int32{
"SettingHeaderTableSize": 0,
"SettingEnablePush": 1,
"SettingMaxConcurrentStreams": 2,
"SettingInitialWindowSize": 3,
"SettingMaxFrameSize": 4,
"SettingMaxHeaderListSize": 5,
"SettingEnableConnectProtocol": 6,
"SettingNoRFC7540Priorities": 7,
}
)
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[3].Descriptor()
}
func (SettingIDEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[3]
}
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{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 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[1]
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[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 PushPromiseParamStruct.ProtoReflect.Descriptor instead.
func (*PushPromiseParamStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{1}
}
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 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[2]
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[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 PriorityWriteSchedulerConfigStruct.ProtoReflect.Descriptor instead.
func (*PriorityWriteSchedulerConfigStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{2}
}
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[3]
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[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 GoAwayFrameStruct.ProtoReflect.Descriptor instead.
func (*GoAwayFrameStruct) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{3}
}
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 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 FramerNgdotWritePriorityUpdateArgs struct {
state protoimpl.MessageState `protogen:"open.v1"`
StreamID uint32 `protobuf:"varint,1,opt,name=streamID,proto3" json:"streamID,omitempty"`
Priority string `protobuf:"bytes,2,opt,name=priority,proto3" json:"priority,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *FramerNgdotWritePriorityUpdateArgs) Reset() {
*x = FramerNgdotWritePriorityUpdateArgs{}
mi := &file_ngolofuzz_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *FramerNgdotWritePriorityUpdateArgs) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*FramerNgdotWritePriorityUpdateArgs) ProtoMessage() {}
func (x *FramerNgdotWritePriorityUpdateArgs) 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 FramerNgdotWritePriorityUpdateArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWritePriorityUpdateArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{24}
}
func (x *FramerNgdotWritePriorityUpdateArgs) GetStreamID() uint32 {
if x != nil {
return x.StreamID
}
return 0
}
func (x *FramerNgdotWritePriorityUpdateArgs) GetPriority() string {
if x != nil {
return x.Priority
}
return ""
}
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[25]
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[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 FramerNgdotWriteRSTStreamArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteRSTStreamArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{25}
}
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[26]
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[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 FramerNgdotWriteContinuationArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteContinuationArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{26}
}
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[27]
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[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 FramerNgdotWriteRawFrameArgs.ProtoReflect.Descriptor instead.
func (*FramerNgdotWriteRawFrameArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{27}
}
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[28]
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[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 SettingNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*SettingNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{28}
}
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[29]
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[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 SettingNgdotValidArgs.ProtoReflect.Descriptor instead.
func (*SettingNgdotValidArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{29}
}
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[30]
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[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 SettingIDNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*SettingIDNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{30}
}
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[31]
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[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 TransportNgdotCloseIdleConnectionsArgs.ProtoReflect.Descriptor instead.
func (*TransportNgdotCloseIdleConnectionsArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{31}
}
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[32]
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[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 TransportNgdotNewClientConnArgs.ProtoReflect.Descriptor instead.
func (*TransportNgdotNewClientConnArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{32}
}
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[33]
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[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 ClientConnNgdotSetDoNotReuseArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotSetDoNotReuseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{33}
}
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[34]
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[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 ClientConnNgdotCanTakeNewRequestArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotCanTakeNewRequestArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{34}
}
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[35]
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[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 ClientConnNgdotReserveNewRequestArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotReserveNewRequestArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{35}
}
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[36]
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[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 ClientConnNgdotStateArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotStateArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{36}
}
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[37]
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[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 ClientConnNgdotCloseArgs.ProtoReflect.Descriptor instead.
func (*ClientConnNgdotCloseArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{37}
}
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[38]
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[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 FrameWriteRequestNgdotStreamIDArgs.ProtoReflect.Descriptor instead.
func (*FrameWriteRequestNgdotStreamIDArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{38}
}
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[39]
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[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 FrameWriteRequestNgdotDataSizeArgs.ProtoReflect.Descriptor instead.
func (*FrameWriteRequestNgdotDataSizeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{39}
}
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[40]
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[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 FrameWriteRequestNgdotConsumeArgs.ProtoReflect.Descriptor instead.
func (*FrameWriteRequestNgdotConsumeArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{40}
}
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[41]
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[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 FrameWriteRequestNgdotStringArgs.ProtoReflect.Descriptor instead.
func (*FrameWriteRequestNgdotStringArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{41}
}
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[42]
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[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 NewRandomWriteSchedulerArgs.ProtoReflect.Descriptor instead.
func (*NewRandomWriteSchedulerArgs) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{42}
}
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_FramerNgdotWritePriorityUpdate
// *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[43]
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[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 NgoloFuzzOne.ProtoReflect.Descriptor instead.
func (*NgoloFuzzOne) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{43}
}
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) GetFramerNgdotWritePriorityUpdate() *FramerNgdotWritePriorityUpdateArgs {
if x != nil {
if x, ok := x.Item.(*NgoloFuzzOne_FramerNgdotWritePriorityUpdate); ok {
return x.FramerNgdotWritePriorityUpdate
}
}
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_FramerNgdotWritePriorityUpdate struct {
FramerNgdotWritePriorityUpdate *FramerNgdotWritePriorityUpdateArgs `protobuf:"bytes,21,opt,name=FramerNgdotWritePriorityUpdate,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteRSTStream struct {
FramerNgdotWriteRSTStream *FramerNgdotWriteRSTStreamArgs `protobuf:"bytes,22,opt,name=FramerNgdotWriteRSTStream,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteContinuation struct {
FramerNgdotWriteContinuation *FramerNgdotWriteContinuationArgs `protobuf:"bytes,23,opt,name=FramerNgdotWriteContinuation,proto3,oneof"`
}
type NgoloFuzzOne_FramerNgdotWriteRawFrame struct {
FramerNgdotWriteRawFrame *FramerNgdotWriteRawFrameArgs `protobuf:"bytes,24,opt,name=FramerNgdotWriteRawFrame,proto3,oneof"`
}
type NgoloFuzzOne_SettingNgdotString struct {
SettingNgdotString *SettingNgdotStringArgs `protobuf:"bytes,25,opt,name=SettingNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_SettingNgdotValid struct {
SettingNgdotValid *SettingNgdotValidArgs `protobuf:"bytes,26,opt,name=SettingNgdotValid,proto3,oneof"`
}
type NgoloFuzzOne_SettingIDNgdotString struct {
SettingIDNgdotString *SettingIDNgdotStringArgs `protobuf:"bytes,27,opt,name=SettingIDNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_TransportNgdotCloseIdleConnections struct {
TransportNgdotCloseIdleConnections *TransportNgdotCloseIdleConnectionsArgs `protobuf:"bytes,28,opt,name=TransportNgdotCloseIdleConnections,proto3,oneof"`
}
type NgoloFuzzOne_TransportNgdotNewClientConn struct {
TransportNgdotNewClientConn *TransportNgdotNewClientConnArgs `protobuf:"bytes,29,opt,name=TransportNgdotNewClientConn,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotSetDoNotReuse struct {
ClientConnNgdotSetDoNotReuse *ClientConnNgdotSetDoNotReuseArgs `protobuf:"bytes,30,opt,name=ClientConnNgdotSetDoNotReuse,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotCanTakeNewRequest struct {
ClientConnNgdotCanTakeNewRequest *ClientConnNgdotCanTakeNewRequestArgs `protobuf:"bytes,31,opt,name=ClientConnNgdotCanTakeNewRequest,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotReserveNewRequest struct {
ClientConnNgdotReserveNewRequest *ClientConnNgdotReserveNewRequestArgs `protobuf:"bytes,32,opt,name=ClientConnNgdotReserveNewRequest,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotState struct {
ClientConnNgdotState *ClientConnNgdotStateArgs `protobuf:"bytes,33,opt,name=ClientConnNgdotState,proto3,oneof"`
}
type NgoloFuzzOne_ClientConnNgdotClose struct {
ClientConnNgdotClose *ClientConnNgdotCloseArgs `protobuf:"bytes,34,opt,name=ClientConnNgdotClose,proto3,oneof"`
}
type NgoloFuzzOne_FrameWriteRequestNgdotStreamID struct {
FrameWriteRequestNgdotStreamID *FrameWriteRequestNgdotStreamIDArgs `protobuf:"bytes,35,opt,name=FrameWriteRequestNgdotStreamID,proto3,oneof"`
}
type NgoloFuzzOne_FrameWriteRequestNgdotDataSize struct {
FrameWriteRequestNgdotDataSize *FrameWriteRequestNgdotDataSizeArgs `protobuf:"bytes,36,opt,name=FrameWriteRequestNgdotDataSize,proto3,oneof"`
}
type NgoloFuzzOne_FrameWriteRequestNgdotConsume struct {
FrameWriteRequestNgdotConsume *FrameWriteRequestNgdotConsumeArgs `protobuf:"bytes,37,opt,name=FrameWriteRequestNgdotConsume,proto3,oneof"`
}
type NgoloFuzzOne_FrameWriteRequestNgdotString struct {
FrameWriteRequestNgdotString *FrameWriteRequestNgdotStringArgs `protobuf:"bytes,38,opt,name=FrameWriteRequestNgdotString,proto3,oneof"`
}
type NgoloFuzzOne_NewRandomWriteScheduler struct {
NewRandomWriteScheduler *NewRandomWriteSchedulerArgs `protobuf:"bytes,39,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_FramerNgdotWritePriorityUpdate) 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[44]
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[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 NgoloFuzzAny.ProtoReflect.Descriptor instead.
func (*NgoloFuzzAny) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{44}
}
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[45]
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[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 NgoloFuzzList.ProtoReflect.Descriptor instead.
func (*NgoloFuzzList) Descriptor() ([]byte, []int) {
return file_ngolofuzz_proto_rawDescGZIP(), []int{45}
}
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\"\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\"\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\">\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\"\\\n" +
"\"FramerNgdotWritePriorityUpdateArgs\x12\x1a\n" +
"\bstreamID\x18\x01 \x01(\rR\bstreamID\x12\x1a\n" +
"\bpriority\x18\x02 \x01(\tR\bpriority\"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\"\xce\x1f\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\x12w\n" +
"\x1eFramerNgdotWritePriorityUpdate\x18\x15 \x01(\v2-.ngolofuzz.FramerNgdotWritePriorityUpdateArgsH\x00R\x1eFramerNgdotWritePriorityUpdate\x12h\n" +
"\x19FramerNgdotWriteRSTStream\x18\x16 \x01(\v2(.ngolofuzz.FramerNgdotWriteRSTStreamArgsH\x00R\x19FramerNgdotWriteRSTStream\x12q\n" +
"\x1cFramerNgdotWriteContinuation\x18\x17 \x01(\v2+.ngolofuzz.FramerNgdotWriteContinuationArgsH\x00R\x1cFramerNgdotWriteContinuation\x12e\n" +
"\x18FramerNgdotWriteRawFrame\x18\x18 \x01(\v2'.ngolofuzz.FramerNgdotWriteRawFrameArgsH\x00R\x18FramerNgdotWriteRawFrame\x12S\n" +
"\x12SettingNgdotString\x18\x19 \x01(\v2!.ngolofuzz.SettingNgdotStringArgsH\x00R\x12SettingNgdotString\x12P\n" +
"\x11SettingNgdotValid\x18\x1a \x01(\v2 .ngolofuzz.SettingNgdotValidArgsH\x00R\x11SettingNgdotValid\x12Y\n" +
"\x14SettingIDNgdotString\x18\x1b \x01(\v2#.ngolofuzz.SettingIDNgdotStringArgsH\x00R\x14SettingIDNgdotString\x12\x83\x01\n" +
"\"TransportNgdotCloseIdleConnections\x18\x1c \x01(\v21.ngolofuzz.TransportNgdotCloseIdleConnectionsArgsH\x00R\"TransportNgdotCloseIdleConnections\x12n\n" +
"\x1bTransportNgdotNewClientConn\x18\x1d \x01(\v2*.ngolofuzz.TransportNgdotNewClientConnArgsH\x00R\x1bTransportNgdotNewClientConn\x12q\n" +
"\x1cClientConnNgdotSetDoNotReuse\x18\x1e \x01(\v2+.ngolofuzz.ClientConnNgdotSetDoNotReuseArgsH\x00R\x1cClientConnNgdotSetDoNotReuse\x12}\n" +
" ClientConnNgdotCanTakeNewRequest\x18\x1f \x01(\v2/.ngolofuzz.ClientConnNgdotCanTakeNewRequestArgsH\x00R ClientConnNgdotCanTakeNewRequest\x12}\n" +
" ClientConnNgdotReserveNewRequest\x18 \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*\xe7\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\x12\x17\n" +
"\x13FramePriorityUpdate\x10\n" +
"*\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\r*\xfa\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\x12\x1e\n" +
"\x1aSettingNoRFC7540Priorities\x10\aB\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, 46)
var file_ngolofuzz_proto_goTypes = []any{
(FrameTypeEnum)(0), // 0: ngolofuzz.FrameTypeEnum
(FlagsEnum)(0), // 1: ngolofuzz.FlagsEnum
(ErrCodeEnum)(0), // 2: ngolofuzz.ErrCodeEnum
(SettingIDEnum)(0), // 3: ngolofuzz.SettingIDEnum
(*PriorityParamStruct)(nil), // 4: ngolofuzz.PriorityParamStruct
(*PushPromiseParamStruct)(nil), // 5: ngolofuzz.PushPromiseParamStruct
(*PriorityWriteSchedulerConfigStruct)(nil), // 6: ngolofuzz.PriorityWriteSchedulerConfigStruct
(*GoAwayFrameStruct)(nil), // 7: ngolofuzz.GoAwayFrameStruct
(*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
(*FramerNgdotWritePriorityUpdateArgs)(nil), // 28: ngolofuzz.FramerNgdotWritePriorityUpdateArgs
(*FramerNgdotWriteRSTStreamArgs)(nil), // 29: ngolofuzz.FramerNgdotWriteRSTStreamArgs
(*FramerNgdotWriteContinuationArgs)(nil), // 30: ngolofuzz.FramerNgdotWriteContinuationArgs
(*FramerNgdotWriteRawFrameArgs)(nil), // 31: ngolofuzz.FramerNgdotWriteRawFrameArgs
(*SettingNgdotStringArgs)(nil), // 32: ngolofuzz.SettingNgdotStringArgs
(*SettingNgdotValidArgs)(nil), // 33: ngolofuzz.SettingNgdotValidArgs
(*SettingIDNgdotStringArgs)(nil), // 34: ngolofuzz.SettingIDNgdotStringArgs
(*TransportNgdotCloseIdleConnectionsArgs)(nil), // 35: ngolofuzz.TransportNgdotCloseIdleConnectionsArgs
(*TransportNgdotNewClientConnArgs)(nil), // 36: ngolofuzz.TransportNgdotNewClientConnArgs
(*ClientConnNgdotSetDoNotReuseArgs)(nil), // 37: ngolofuzz.ClientConnNgdotSetDoNotReuseArgs
(*ClientConnNgdotCanTakeNewRequestArgs)(nil), // 38: ngolofuzz.ClientConnNgdotCanTakeNewRequestArgs
(*ClientConnNgdotReserveNewRequestArgs)(nil), // 39: ngolofuzz.ClientConnNgdotReserveNewRequestArgs
(*ClientConnNgdotStateArgs)(nil), // 40: ngolofuzz.ClientConnNgdotStateArgs
(*ClientConnNgdotCloseArgs)(nil), // 41: ngolofuzz.ClientConnNgdotCloseArgs
(*FrameWriteRequestNgdotStreamIDArgs)(nil), // 42: ngolofuzz.FrameWriteRequestNgdotStreamIDArgs
(*FrameWriteRequestNgdotDataSizeArgs)(nil), // 43: ngolofuzz.FrameWriteRequestNgdotDataSizeArgs
(*FrameWriteRequestNgdotConsumeArgs)(nil), // 44: ngolofuzz.FrameWriteRequestNgdotConsumeArgs
(*FrameWriteRequestNgdotStringArgs)(nil), // 45: ngolofuzz.FrameWriteRequestNgdotStringArgs
(*NewRandomWriteSchedulerArgs)(nil), // 46: ngolofuzz.NewRandomWriteSchedulerArgs
(*NgoloFuzzOne)(nil), // 47: ngolofuzz.NgoloFuzzOne
(*NgoloFuzzAny)(nil), // 48: ngolofuzz.NgoloFuzzAny
(*NgoloFuzzList)(nil), // 49: ngolofuzz.NgoloFuzzList
}
var file_ngolofuzz_proto_depIdxs = []int32{
2, // 0: ngolofuzz.GoAwayFrameStruct.ErrCode:type_name -> ngolofuzz.ErrCodeEnum
2, // 1: ngolofuzz.ErrCodeNgdotStringArgs.e:type_name -> ngolofuzz.ErrCodeEnum
0, // 2: ngolofuzz.FrameTypeNgdotStringArgs.t:type_name -> ngolofuzz.FrameTypeEnum
1, // 3: ngolofuzz.FlagsNgdotHasArgs.f:type_name -> ngolofuzz.FlagsEnum
1, // 4: ngolofuzz.FlagsNgdotHasArgs.v:type_name -> ngolofuzz.FlagsEnum
7, // 5: ngolofuzz.GoAwayFrameNgdotDebugDataArgs.f:type_name -> ngolofuzz.GoAwayFrameStruct
2, // 6: ngolofuzz.FramerNgdotWriteGoAwayArgs.code:type_name -> ngolofuzz.ErrCodeEnum
4, // 7: ngolofuzz.PriorityParamNgdotIsZeroArgs.p:type_name -> ngolofuzz.PriorityParamStruct
2, // 8: ngolofuzz.FramerNgdotWriteRSTStreamArgs.code:type_name -> ngolofuzz.ErrCodeEnum
0, // 9: ngolofuzz.FramerNgdotWriteRawFrameArgs.t:type_name -> ngolofuzz.FrameTypeEnum
1, // 10: ngolofuzz.FramerNgdotWriteRawFrameArgs.flags:type_name -> ngolofuzz.FlagsEnum
3, // 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.FramerNgdotWritePriorityUpdate:type_name -> ngolofuzz.FramerNgdotWritePriorityUpdateArgs
29, // 33: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteRSTStream:type_name -> ngolofuzz.FramerNgdotWriteRSTStreamArgs
30, // 34: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteContinuation:type_name -> ngolofuzz.FramerNgdotWriteContinuationArgs
31, // 35: ngolofuzz.NgoloFuzzOne.FramerNgdotWriteRawFrame:type_name -> ngolofuzz.FramerNgdotWriteRawFrameArgs
32, // 36: ngolofuzz.NgoloFuzzOne.SettingNgdotString:type_name -> ngolofuzz.SettingNgdotStringArgs
33, // 37: ngolofuzz.NgoloFuzzOne.SettingNgdotValid:type_name -> ngolofuzz.SettingNgdotValidArgs
34, // 38: ngolofuzz.NgoloFuzzOne.SettingIDNgdotString:type_name -> ngolofuzz.SettingIDNgdotStringArgs
35, // 39: ngolofuzz.NgoloFuzzOne.TransportNgdotCloseIdleConnections:type_name -> ngolofuzz.TransportNgdotCloseIdleConnectionsArgs
36, // 40: ngolofuzz.NgoloFuzzOne.TransportNgdotNewClientConn:type_name -> ngolofuzz.TransportNgdotNewClientConnArgs
37, // 41: ngolofuzz.NgoloFuzzOne.ClientConnNgdotSetDoNotReuse:type_name -> ngolofuzz.ClientConnNgdotSetDoNotReuseArgs
38, // 42: ngolofuzz.NgoloFuzzOne.ClientConnNgdotCanTakeNewRequest:type_name -> ngolofuzz.ClientConnNgdotCanTakeNewRequestArgs
39, // 43: ngolofuzz.NgoloFuzzOne.ClientConnNgdotReserveNewRequest:type_name -> ngolofuzz.ClientConnNgdotReserveNewRequestArgs
40, // 44: ngolofuzz.NgoloFuzzOne.ClientConnNgdotState:type_name -> ngolofuzz.ClientConnNgdotStateArgs
41, // 45: ngolofuzz.NgoloFuzzOne.ClientConnNgdotClose:type_name -> ngolofuzz.ClientConnNgdotCloseArgs
42, // 46: ngolofuzz.NgoloFuzzOne.FrameWriteRequestNgdotStreamID:type_name -> ngolofuzz.FrameWriteRequestNgdotStreamIDArgs
43, // 47: ngolofuzz.NgoloFuzzOne.FrameWriteRequestNgdotDataSize:type_name -> ngolofuzz.FrameWriteRequestNgdotDataSizeArgs
44, // 48: ngolofuzz.NgoloFuzzOne.FrameWriteRequestNgdotConsume:type_name -> ngolofuzz.FrameWriteRequestNgdotConsumeArgs
45, // 49: ngolofuzz.NgoloFuzzOne.FrameWriteRequestNgdotString:type_name -> ngolofuzz.FrameWriteRequestNgdotStringArgs
46, // 50: ngolofuzz.NgoloFuzzOne.NewRandomWriteScheduler:type_name -> ngolofuzz.NewRandomWriteSchedulerArgs
47, // 51: ngolofuzz.NgoloFuzzList.list:type_name -> ngolofuzz.NgoloFuzzOne
52, // [52:52] is the sub-list for method output_type
52, // [52:52] is the sub-list for method input_type
52, // [52:52] is the sub-list for extension type_name
52, // [52:52] is the sub-list for extension extendee
0, // [0:52] 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[43].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_FramerNgdotWritePriorityUpdate)(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[44].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: 46,
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 DecoderResults []*hpack.Decoder
DecoderResultsIndex := 0
var EncoderResults []*hpack.Encoder
EncoderResultsIndex := 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) {
DecoderNb := 0
DecoderResultsIndex := 0
EncoderNb := 0
EncoderResultsIndex := 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.11
// 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.11
// 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.11
// 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 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 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 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 ConnResults []*ipv6.Conn
ConnResultsIndex := 0
var PacketConnResults []*ipv6.PacketConn
PacketConnResultsIndex := 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) {
ConnNb := 0
ConnResultsIndex := 0
PacketConnNb := 0
PacketConnResultsIndex := 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.11
// 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 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[0].Descriptor()
}
func (ICMPTypeEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
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{0}
}
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[1].Descriptor()
}
func (ControlFlagsEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
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{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*\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$*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\x05B\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{
(ICMPTypeEnum)(0), // 0: ngolofuzz.ICMPTypeEnum
(ControlFlagsEnum)(0), // 1: ngolofuzz.ControlFlagsEnum
(*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{
1, // 0: ngolofuzz.NewControlMessageArgs.cf:type_name -> ngolofuzz.ControlFlagsEnum
1, // 1: ngolofuzz.PacketConnNgdotSetControlMessageArgs.cf:type_name -> ngolofuzz.ControlFlagsEnum
0, // 2: ngolofuzz.ICMPTypeNgdotStringArgs.typ:type_name -> ngolofuzz.ICMPTypeEnum
0, // 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.11
// 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.11
// 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.11
// 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 ConnResults []*quic.Conn
ConnResultsIndex := 0
var EndpointResults []*quic.Endpoint
EndpointResultsIndex := 0
var StreamResults []*quic.Stream
StreamResultsIndex := 0
var ConfigResults []*quic.Config
ConfigResultsIndex := 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) {
ConnNb := 0
ConnResultsIndex := 0
EndpointNb := 0
EndpointResultsIndex := 0
StreamNb := 0
StreamResultsIndex := 0
ConfigNb := 0
ConfigResultsIndex := 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.11
// 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.11
// 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.11
// 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.11
// 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.
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
//go:generate stringer -type NodeType
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
}
// Code generated by "stringer -type NodeType"; DO NOT EDIT.
package html
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[ErrorNode-0]
_ = x[TextNode-1]
_ = x[DocumentNode-2]
_ = x[ElementNode-3]
_ = x[CommentNode-4]
_ = x[DoctypeNode-5]
_ = x[RawNode-6]
_ = x[scopeMarkerNode-7]
}
const _NodeType_name = "ErrorNodeTextNodeDocumentNodeElementNodeCommentNodeDoctypeNodeRawNodescopeMarkerNode"
var _NodeType_index = [...]uint8{0, 9, 17, 29, 40, 51, 62, 69, 84}
func (i NodeType) String() string {
idx := int(i) - 0
if i < 0 || idx >= len(_NodeType_index)-1 {
return "NodeType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _NodeType_name[_NodeType_index[idx]:_NodeType_index[idx+1]]
}
// 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 2026 The Go 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.27
package http2
import "net/http"
func clientPriorityDisabled(s *http.Server) bool {
return s.DisableClientPriority
}
// 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"
"slices"
"strings"
"sync"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/internal/httpsfv"
)
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 and other future
// RFCs.
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
FramePriorityUpdate FrameType = 0x10
)
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",
FramePriorityUpdate: "PRIORITY_UPDATE",
}
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,
FramePriorityUpdate: parsePriorityUpdateFrame,
}
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
}
// defaultRFC9218Priority determines what priority we should use as the default
// value.
//
// According to RFC 9218, by default, streams should be given an urgency of 3
// and should be non-incremental. However, making streams non-incremental by
// default would be a huge change to our historical behavior where we would
// round-robin writes across streams. When streams are non-incremental, we
// would process streams of the same urgency one-by-one to completion instead.
//
// To avoid such a sudden change which might break some HTTP/2 users, this
// function allows the caller to specify whether they can actually use the
// default value as specified in RFC 9218. If not, this function will return a
// priority value where streams are incremental by default instead: effectively
// a round-robin between stream of the same urgency.
//
// As an example, a server might not be able to use the RFC 9218 default value
// when it's not sure that the client it is serving is aware of RFC 9218.
func defaultRFC9218Priority(canUseDefault bool) PriorityParam {
if canUseDefault {
return PriorityParam{
urgency: 3,
incremental: 0,
}
}
return PriorityParam{
urgency: 3,
incremental: 1,
}
}
// 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()
}
// PriorityUpdateFrame is a PRIORITY_UPDATE frame as described in
// https://www.rfc-editor.org/rfc/rfc9218.html#name-the-priority_update-frame.
type PriorityUpdateFrame struct {
FrameHeader
Priority string
PrioritizedStreamID uint32
}
func parseRFC9218Priority(s string, canUseDefault bool) (p PriorityParam, ok bool) {
p = defaultRFC9218Priority(canUseDefault)
ok = httpsfv.ParseDictionary(s, func(key, val, _ string) {
switch key {
case "u":
if u, ok := httpsfv.ParseInteger(val); ok && u >= 0 && u <= 7 {
p.urgency = uint8(u)
}
case "i":
if i, ok := httpsfv.ParseBoolean(val); ok {
if i {
p.incremental = 1
} else {
p.incremental = 0
}
}
}
})
if !ok {
return defaultRFC9218Priority(canUseDefault), ok
}
return p, true
}
func parsePriorityUpdateFrame(_ *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) {
if fh.StreamID != 0 {
countError("frame_priority_update_non_zero_stream")
return nil, connError{ErrCodeProtocol, "PRIORITY_UPDATE frame with non-zero stream ID"}
}
if len(payload) < 4 {
countError("frame_priority_update_bad_length")
return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY_UPDATE frame payload size was %d; want at least 4", len(payload))}
}
v := binary.BigEndian.Uint32(payload[:4])
streamID := v & 0x7fffffff // mask off high bit
if streamID == 0 {
countError("frame_priority_update_prioritizing_zero_stream")
return nil, connError{ErrCodeProtocol, "PRIORITY_UPDATE frame with prioritized stream ID of zero"}
}
return &PriorityUpdateFrame{
FrameHeader: fh,
PrioritizedStreamID: streamID,
Priority: string(payload[4:]),
}, nil
}
// WritePriorityUpdate writes a PRIORITY_UPDATE 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) WritePriorityUpdate(streamID uint32, priority string) error {
if !validStreamID(streamID) && !f.AllowIllegalWrites {
return errStreamID
}
f.startWrite(FramePriorityUpdate, 0, 0)
f.writeUint32(streamID)
f.writeBytes([]byte(priority))
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) rfc9218Priority(priorityAware bool) (p PriorityParam, priorityAwareAfter, hasIntermediary bool) {
var s string
for _, field := range mh.Fields {
if field.Name == "priority" {
s = field.Value
priorityAware = true
}
if slices.Contains([]string{"via", "forwarded", "x-forwarded-for"}, field.Name) {
hasIntermediary = true
}
}
// No need to check for ok. parseRFC9218Priority will return a default
// value if there is no priority field or if the field cannot be parsed.
p, _ = parseRFC9218Priority(s, priorityAware && !hasIntermediary)
return p, priorityAware, hasIntermediary
}
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
SettingNoRFC7540Priorities SettingID = 0x9
)
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",
SettingNoRFC7540Priorities: "NO_RFC7540_PRIORITIES",
}
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{})
}
switch {
case s.NewWriteScheduler != nil:
sc.writeSched = s.NewWriteScheduler()
case clientPriorityDisabled(http1srv):
sc.writeSched = newRoundRobinWriteScheduler()
default:
sc.writeSched = newPriorityWriteSchedulerRFC9218()
}
// 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
// Used for RFC 9218 prioritization.
hasIntermediary bool // connection is done via an intermediary / proxy
priorityAware bool // the client has sent priority signal, meaning that it is aware of it.
}
func (sc *serverConn) writeSchedIgnoresRFC7540() bool {
switch sc.writeSched.(type) {
case *priorityWriteSchedulerRFC9218:
return true
case *randomWriteScheduler:
return true
case *roundRobinWriteScheduler:
return true
default:
return false
}
}
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})
}
if sc.writeSchedIgnoresRFC7540() {
settings = append(settings, Setting{SettingNoRFC7540Priorities, 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))
case *PriorityUpdateFrame:
return sc.processPriorityUpdate(f)
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
case SettingNoRFC7540Priorities:
if s.Val > 1 {
return ConnectionError(ErrCodeProtocol)
}
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
}
// We are handling two special cases here:
// 1. When a request is sent via an intermediary, we force priority to be
// u=3,i. This is essentially a round-robin behavior, and is done to ensure
// fairness between, for example, multiple clients using the same proxy.
// 2. Until a client has shown that it is aware of RFC 9218, we make its
// streams non-incremental by default. This is done to preserve the
// historical behavior of handling streams in a round-robin manner, rather
// than one-by-one to completion.
initialPriority := defaultRFC9218Priority(sc.priorityAware && !sc.hasIntermediary)
if _, ok := sc.writeSched.(*priorityWriteSchedulerRFC9218); ok && !sc.hasIntermediary {
headerPriority, priorityAware, hasIntermediary := f.rfc9218Priority(sc.priorityAware)
initialPriority = headerPriority
sc.hasIntermediary = hasIntermediary
if priorityAware {
sc.priorityAware = true
}
}
st := sc.newStream(id, 0, initialState, initialPriority)
if f.HasPriority() {
if err := sc.checkPriority(f.StreamID, f.Priority); err != nil {
return err
}
if !sc.writeSchedIgnoresRFC7540() {
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, defaultRFC9218Priority(sc.priorityAware && !sc.hasIntermediary))
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
}
// We need to avoid calling AdjustStream when using the RFC 9218 write
// scheduler. Otherwise, incremental's zero value in PriorityParam will
// unexpectedly make all streams non-incremental. This causes us to process
// streams one-by-one to completion rather than doing it in a round-robin
// manner (the historical behavior), which might be unexpected to users.
if sc.writeSchedIgnoresRFC7540() {
return nil
}
sc.writeSched.AdjustStream(f.StreamID, f.PriorityParam)
return nil
}
func (sc *serverConn) processPriorityUpdate(f *PriorityUpdateFrame) error {
sc.priorityAware = true
if _, ok := sc.writeSched.(*priorityWriteSchedulerRFC9218); !ok {
return nil
}
p, ok := parseRFC9218Priority(f.Priority, sc.priorityAware)
if !ok {
return sc.countError("unparsable_priority_update", streamError(f.PrioritizedStreamID, ErrCodeProtocol))
}
sc.writeSched.AdjustStream(f.PrioritizedStreamID, p)
return nil
}
func (sc *serverConn) newStream(id, pusherID uint32, state streamState, priority PriorityParam) *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, priority: priority})
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, defaultRFC9218Priority(sc.priorityAware && !sc.hasIntermediary))
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
// readBeforeStreamID is the smallest stream ID that has not been followed by
// a frame read from the peer. We use this to determine when a request may
// have been sent to a completely unresponsive connection:
// If the request ID is less than readBeforeStreamID, then we have had some
// indication of life on the connection since sending the request.
readBeforeStreamID uint32
// 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{}
// internalStateHook reports state changes back to the net/http.ClientConn.
// Note that this is different from the user state hook registered by
// net/http.ClientConn.SetStateHook: The internal hook calls ClientConn,
// which calls the user hook.
internalStateHook func()
// 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, nil)
}
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, nil)
}
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(), nil)
}
func (t *Transport) newClientConn(c net.Conn, singleUse bool, internalStateHook func()) (*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(),
internalStateHook: internalStateHook,
}
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 = maxConcurrentOkay && cc.isUsableLocked()
// 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
}
func (cc *ClientConn) isUsableLocked() bool {
return cc.goAway == nil &&
!cc.closed &&
!cc.closing &&
!cc.doNotReuse &&
int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 &&
!cc.tooIdleLocked()
}
// canReserveLocked reports whether a net/http.ClientConn can reserve a slot on this conn.
//
// This follows slightly different rules than clientConnIdleState.canTakeNewRequest.
// We only permit reservations up to the conn's concurrency limit.
// This differs from ClientConn.ReserveNewRequest, which permits reservations
// past the limit when StrictMaxConcurrentStreams is set.
func (cc *ClientConn) canReserveLocked() bool {
if cc.currentRequestCountLocked() >= int(cc.maxConcurrentStreams) {
return false
}
if !cc.isUsableLocked() {
return false
}
return true
}
// 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
}
// availableLocked reports the number of concurrency slots available.
func (cc *ClientConn) availableLocked() int {
if !cc.canTakeNewRequestLocked() {
return 0
}
return max(0, int(cc.maxConcurrentStreams)-cc.currentRequestCountLocked())
}
// 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()
cc.maybeCallStateHook()
}
// 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
// Have we read any frames from the connection since sending this request?
readSinceStream := cc.readBeforeStreamID > cs.ID
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,
// if we haven't read any frames from the connection since
// sending this request, we let it 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 && !readSinceStream {
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)
cc.maybeCallStateHook()
}
// 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)
}
func (rl *clientConnReadLoop) endStreamErrorLocked(cs *clientStream, err error) {
cs.readAborted = true
cs.abortStreamLocked(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
}
rl.cc.readBeforeStreamID = rl.cc.nextStreamID
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
defer cc.maybeCallStateHook()
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.endStreamErrorLocked(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
defer cc.maybeCallStateHook()
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 a cached connection to the host.
// (The field is exported so it can be accessed via reflect from net/http; tested
// by TestNoDialH2RoundTripperType)
//
// A noDialH2RoundTripper is registered with http1.Transport.RegisterProtocol,
// and the http1.Transport can use type assertions to call non-RoundTrip methods on it.
// This lets us expose, for example, NewClientConn to net/http.
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 (rt noDialH2RoundTripper) NewClientConn(conn net.Conn, internalStateHook func()) (http.RoundTripper, error) {
tr := rt.Transport
cc, err := tr.newClientConn(conn, tr.disableKeepAlives(), internalStateHook)
if err != nil {
return nil, err
}
// RoundTrip should block when the conn is at its concurrency limit,
// not return an error. Setting strictMaxConcurrentStreams enables this.
cc.strictMaxConcurrentStreams = true
return netHTTPClientConn{cc}, nil
}
// netHTTPClientConn wraps ClientConn and implements the interface net/http expects from
// the RoundTripper returned by NewClientConn.
type netHTTPClientConn struct {
cc *ClientConn
}
func (cc netHTTPClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
return cc.cc.RoundTrip(req)
}
func (cc netHTTPClientConn) Close() error {
return cc.cc.Close()
}
func (cc netHTTPClientConn) Err() error {
cc.cc.mu.Lock()
defer cc.cc.mu.Unlock()
if cc.cc.closed {
return errors.New("connection closed")
}
return nil
}
func (cc netHTTPClientConn) Reserve() error {
defer cc.cc.maybeCallStateHook()
cc.cc.mu.Lock()
defer cc.cc.mu.Unlock()
if !cc.cc.canReserveLocked() {
return errors.New("connection is unavailable")
}
cc.cc.streamsReserved++
return nil
}
func (cc netHTTPClientConn) Release() {
defer cc.cc.maybeCallStateHook()
cc.cc.mu.Lock()
defer cc.cc.mu.Unlock()
// We don't complain if streamsReserved is 0.
//
// This is consistent with RoundTrip: both Release and RoundTrip will
// consume a reservation iff one exists.
if cc.cc.streamsReserved > 0 {
cc.cc.streamsReserved--
}
}
func (cc netHTTPClientConn) Available() int {
cc.cc.mu.Lock()
defer cc.cc.mu.Unlock()
return cc.cc.availableLocked()
}
func (cc netHTTPClientConn) InFlight() int {
cc.cc.mu.Lock()
defer cc.cc.mu.Unlock()
return cc.cc.currentRequestCountLocked()
}
func (cc *ClientConn) maybeCallStateHook() {
if cc.internalStateHook != nil {
cc.internalStateHook()
}
}
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 {
return newPriorityWriteSchedulerRFC7540(cfg)
}
func newPriorityWriteSchedulerRFC7540(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
// priorityUpdateBuf is used to buffer the most recent PRIORITY_UPDATE we
// receive per https://www.rfc-editor.org/rfc/rfc9218.html#name-the-priority_update-frame.
priorityUpdateBuf struct {
// streamID being 0 means that the buffer is empty. This is a safe
// assumption as PRIORITY_UPDATE for stream 0 is a PROTOCOL_ERROR.
streamID uint32
priority PriorityParam
}
}
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))
}
if streamID == ws.priorityUpdateBuf.streamID {
ws.priorityUpdateBuf.streamID = 0
opt.priority = ws.priorityUpdateBuf.priority
}
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 {
ws.priorityUpdateBuf.streamID = streamID
ws.priorityUpdateBuf.priority = priority
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 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 httpsfv provides functionality for dealing with HTTP Structured
// Field Values.
package httpsfv
import (
"slices"
"strconv"
"strings"
"time"
"unicode/utf8"
)
func isLCAlpha(b byte) bool {
return (b >= 'a' && b <= 'z')
}
func isAlpha(b byte) bool {
return isLCAlpha(b) || (b >= 'A' && b <= 'Z')
}
func isDigit(b byte) bool {
return b >= '0' && b <= '9'
}
func isVChar(b byte) bool {
return b >= 0x21 && b <= 0x7e
}
func isSP(b byte) bool {
return b == 0x20
}
func isTChar(b byte) bool {
if isAlpha(b) || isDigit(b) {
return true
}
return slices.Contains([]byte{'!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~'}, b)
}
func countLeftWhitespace(s string) int {
i := 0
for _, ch := range []byte(s) {
if ch != ' ' && ch != '\t' {
break
}
i++
}
return i
}
// https://www.rfc-editor.org/rfc/rfc4648#section-8.
func decOctetHex(ch1, ch2 byte) (ch byte, ok bool) {
decBase16 := func(in byte) (out byte, ok bool) {
if !isDigit(in) && !(in >= 'a' && in <= 'f') {
return 0, false
}
if isDigit(in) {
return in - '0', true
}
return in - 'a' + 10, true
}
if ch1, ok = decBase16(ch1); !ok {
return 0, ok
}
if ch2, ok = decBase16(ch2); !ok {
return 0, ok
}
return ch1<<4 | ch2, true
}
// ParseList parses a list from a given HTTP Structured Field Values.
//
// Given an HTTP SFV string that represents a list, it will call the given
// function using each of the members and parameters contained in the list.
// This allows the caller to extract information out of the list.
//
// This function will return once it encounters the end of the string, or
// something that is not a list. If it cannot consume the entire given
// string, the ok value returned will be false.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-list.
func ParseList(s string, f func(member, param string)) (ok bool) {
for len(s) != 0 {
var member, param string
if len(s) != 0 && s[0] == '(' {
if member, s, ok = consumeBareInnerList(s, nil); !ok {
return ok
}
} else {
if member, s, ok = consumeBareItem(s); !ok {
return ok
}
}
if param, s, ok = consumeParameter(s, nil); !ok {
return ok
}
if f != nil {
f(member, param)
}
s = s[countLeftWhitespace(s):]
if len(s) == 0 {
break
}
if s[0] != ',' {
return false
}
s = s[1:]
s = s[countLeftWhitespace(s):]
if len(s) == 0 {
return false
}
}
return true
}
// consumeBareInnerList consumes an inner list
// (https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-inner-list),
// except for the inner list's top-most parameter.
// For example, given `(a;b c;d);e`, it will consume only `(a;b c;d)`.
func consumeBareInnerList(s string, f func(bareItem, param string)) (consumed, rest string, ok bool) {
if len(s) == 0 || s[0] != '(' {
return "", s, false
}
rest = s[1:]
for len(rest) != 0 {
var bareItem, param string
rest = rest[countLeftWhitespace(rest):]
if len(rest) != 0 && rest[0] == ')' {
rest = rest[1:]
break
}
if bareItem, rest, ok = consumeBareItem(rest); !ok {
return "", s, ok
}
if param, rest, ok = consumeParameter(rest, nil); !ok {
return "", s, ok
}
if len(rest) == 0 || (rest[0] != ')' && !isSP(rest[0])) {
return "", s, false
}
if f != nil {
f(bareItem, param)
}
}
return s[:len(s)-len(rest)], rest, true
}
// ParseBareInnerList parses a bare inner list from a given HTTP Structured
// Field Values.
//
// We define a bare inner list as an inner list
// (https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-inner-list),
// without the top-most parameter of the inner list. For example, given the
// inner list `(a;b c;d);e`, the bare inner list would be `(a;b c;d)`.
//
// Given an HTTP SFV string that represents a bare inner list, it will call the
// given function using each of the bare item and parameter within the bare
// inner list. This allows the caller to extract information out of the bare
// inner list.
//
// This function will return once it encounters the end of the bare inner list,
// or something that is not a bare inner list. If it cannot consume the entire
// given string, the ok value returned will be false.
func ParseBareInnerList(s string, f func(bareItem, param string)) (ok bool) {
_, rest, ok := consumeBareInnerList(s, f)
return rest == "" && ok
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-item.
func consumeItem(s string, f func(bareItem, param string)) (consumed, rest string, ok bool) {
var bareItem, param string
if bareItem, rest, ok = consumeBareItem(s); !ok {
return "", s, ok
}
if param, rest, ok = consumeParameter(rest, nil); !ok {
return "", s, ok
}
if f != nil {
f(bareItem, param)
}
return s[:len(s)-len(rest)], rest, true
}
// ParseItem parses an item from a given HTTP Structured Field Values.
//
// Given an HTTP SFV string that represents an item, it will call the given
// function once, with the bare item and the parameter of the item. This allows
// the caller to extract information out of the item.
//
// This function will return once it encounters the end of the string, or
// something that is not an item. If it cannot consume the entire given
// string, the ok value returned will be false.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-item.
func ParseItem(s string, f func(bareItem, param string)) (ok bool) {
_, rest, ok := consumeItem(s, f)
return rest == "" && ok
}
// ParseDictionary parses a dictionary from a given HTTP Structured Field
// Values.
//
// Given an HTTP SFV string that represents a dictionary, it will call the
// given function using each of the keys, values, and parameters contained in
// the dictionary. This allows the caller to extract information out of the
// dictionary.
//
// This function will return once it encounters the end of the string, or
// something that is not a dictionary. If it cannot consume the entire given
// string, the ok value returned will be false.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-dictionary.
func ParseDictionary(s string, f func(key, val, param string)) (ok bool) {
for len(s) != 0 {
var key, val, param string
val = "?1" // Default value for empty val is boolean true.
if key, s, ok = consumeKey(s); !ok {
return ok
}
if len(s) != 0 && s[0] == '=' {
s = s[1:]
if len(s) != 0 && s[0] == '(' {
if val, s, ok = consumeBareInnerList(s, nil); !ok {
return ok
}
} else {
if val, s, ok = consumeBareItem(s); !ok {
return ok
}
}
}
if param, s, ok = consumeParameter(s, nil); !ok {
return ok
}
if f != nil {
f(key, val, param)
}
s = s[countLeftWhitespace(s):]
if len(s) == 0 {
break
}
if s[0] == ',' {
s = s[1:]
}
s = s[countLeftWhitespace(s):]
if len(s) == 0 {
return false
}
}
return true
}
// https://www.rfc-editor.org/rfc/rfc9651.html#parse-param.
func consumeParameter(s string, f func(key, val string)) (consumed, rest string, ok bool) {
rest = s
for len(rest) != 0 {
var key, val string
val = "?1" // Default value for empty val is boolean true.
if rest[0] != ';' {
break
}
rest = rest[1:]
rest = rest[countLeftWhitespace(rest):]
key, rest, ok = consumeKey(rest)
if !ok {
return "", s, ok
}
if len(rest) != 0 && rest[0] == '=' {
rest = rest[1:]
val, rest, ok = consumeBareItem(rest)
if !ok {
return "", s, ok
}
}
if f != nil {
f(key, val)
}
}
return s[:len(s)-len(rest)], rest, true
}
// ParseParameter parses a parameter from a given HTTP Structured Field Values.
//
// Given an HTTP SFV string that represents a parameter, it will call the given
// function using each of the keys and values contained in the parameter. This
// allows the caller to extract information out of the parameter.
//
// This function will return once it encounters the end of the string, or
// something that is not a parameter. If it cannot consume the entire given
// string, the ok value returned will be false.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#parse-param.
func ParseParameter(s string, f func(key, val string)) (ok bool) {
_, rest, ok := consumeParameter(s, f)
return rest == "" && ok
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-key.
func consumeKey(s string) (consumed, rest string, ok bool) {
if len(s) == 0 || (!isLCAlpha(s[0]) && s[0] != '*') {
return "", s, false
}
i := 0
for _, ch := range []byte(s) {
if !isLCAlpha(ch) && !isDigit(ch) && !slices.Contains([]byte("_-.*"), ch) {
break
}
i++
}
return s[:i], s[i:], true
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
func consumeIntegerOrDecimal(s string) (consumed, rest string, ok bool) {
var i, signOffset, periodIndex int
var isDecimal bool
if i < len(s) && s[i] == '-' {
i++
signOffset++
}
if i >= len(s) {
return "", s, false
}
if !isDigit(s[i]) {
return "", s, false
}
for i < len(s) {
ch := s[i]
if isDigit(ch) {
i++
continue
}
if !isDecimal && ch == '.' {
if i-signOffset > 12 {
return "", s, false
}
periodIndex = i
isDecimal = true
i++
continue
}
break
}
if !isDecimal && i-signOffset > 15 {
return "", s, false
}
if isDecimal {
if i-signOffset > 16 {
return "", s, false
}
if s[i-1] == '.' {
return "", s, false
}
if i-periodIndex-1 > 3 {
return "", s, false
}
}
return s[:i], s[i:], true
}
// ParseInteger parses an integer from a given HTTP Structured Field Values.
//
// The entire HTTP SFV string must consist of a valid integer. It returns the
// parsed integer and an ok boolean value, indicating success or not.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
func ParseInteger(s string) (parsed int64, ok bool) {
if _, rest, ok := consumeIntegerOrDecimal(s); !ok || rest != "" {
return 0, false
}
if n, err := strconv.ParseInt(s, 10, 64); err == nil {
return n, true
}
return 0, false
}
// ParseDecimal parses a decimal from a given HTTP Structured Field Values.
//
// The entire HTTP SFV string must consist of a valid decimal. It returns the
// parsed decimal and an ok boolean value, indicating success or not.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-an-integer-or-decim.
func ParseDecimal(s string) (parsed float64, ok bool) {
if _, rest, ok := consumeIntegerOrDecimal(s); !ok || rest != "" {
return 0, false
}
if !strings.Contains(s, ".") {
return 0, false
}
if n, err := strconv.ParseFloat(s, 64); err == nil {
return n, true
}
return 0, false
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-string.
func consumeString(s string) (consumed, rest string, ok bool) {
if len(s) == 0 || s[0] != '"' {
return "", s, false
}
for i := 1; i < len(s); i++ {
switch ch := s[i]; ch {
case '\\':
if i+1 >= len(s) {
return "", s, false
}
i++
if ch = s[i]; ch != '"' && ch != '\\' {
return "", s, false
}
case '"':
return s[:i+1], s[i+1:], true
default:
if !isVChar(ch) && !isSP(ch) {
return "", s, false
}
}
}
return "", s, false
}
// ParseString parses a Go string from a given HTTP Structured Field Values.
//
// The entire HTTP SFV string must consist of a valid string. It returns the
// parsed string and an ok boolean value, indicating success or not.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-string.
func ParseString(s string) (parsed string, ok bool) {
if _, rest, ok := consumeString(s); !ok || rest != "" {
return "", false
}
return s[1 : len(s)-1], true
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-token
func consumeToken(s string) (consumed, rest string, ok bool) {
if len(s) == 0 || (!isAlpha(s[0]) && s[0] != '*') {
return "", s, false
}
i := 0
for _, ch := range []byte(s) {
if !isTChar(ch) && !slices.Contains([]byte(":/"), ch) {
break
}
i++
}
return s[:i], s[i:], true
}
// ParseToken parses a token from a given HTTP Structured Field Values.
//
// The entire HTTP SFV string must consist of a valid token. It returns the
// parsed token and an ok boolean value, indicating success or not.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-token
func ParseToken(s string) (parsed string, ok bool) {
if _, rest, ok := consumeToken(s); !ok || rest != "" {
return "", false
}
return s, true
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-byte-sequence.
func consumeByteSequence(s string) (consumed, rest string, ok bool) {
if len(s) == 0 || s[0] != ':' {
return "", s, false
}
for i := 1; i < len(s); i++ {
if ch := s[i]; ch == ':' {
return s[:i+1], s[i+1:], true
}
if ch := s[i]; !isAlpha(ch) && !isDigit(ch) && !slices.Contains([]byte("+/="), ch) {
return "", s, false
}
}
return "", s, false
}
// ParseByteSequence parses a byte sequence from a given HTTP Structured Field
// Values.
//
// The entire HTTP SFV string must consist of a valid byte sequence. It returns
// the parsed byte sequence and an ok boolean value, indicating success or not.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-byte-sequence.
func ParseByteSequence(s string) (parsed []byte, ok bool) {
if _, rest, ok := consumeByteSequence(s); !ok || rest != "" {
return nil, false
}
return []byte(s[1 : len(s)-1]), true
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-boolean.
func consumeBoolean(s string) (consumed, rest string, ok bool) {
if len(s) >= 2 && (s[:2] == "?0" || s[:2] == "?1") {
return s[:2], s[2:], true
}
return "", s, false
}
// ParseBoolean parses a boolean from a given HTTP Structured Field Values.
//
// The entire HTTP SFV string must consist of a valid boolean. It returns the
// parsed boolean and an ok boolean value, indicating success or not.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-boolean.
func ParseBoolean(s string) (parsed bool, ok bool) {
if _, rest, ok := consumeBoolean(s); !ok || rest != "" {
return false, false
}
return s == "?1", true
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-date.
func consumeDate(s string) (consumed, rest string, ok bool) {
if len(s) == 0 || s[0] != '@' {
return "", s, false
}
if _, rest, ok = consumeIntegerOrDecimal(s[1:]); !ok {
return "", s, ok
}
consumed = s[:len(s)-len(rest)]
if slices.Contains([]byte(consumed), '.') {
return "", s, false
}
return consumed, rest, ok
}
// ParseDate parses a date from a given HTTP Structured Field Values.
//
// The entire HTTP SFV string must consist of a valid date. It returns the
// parsed date and an ok boolean value, indicating success or not.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-date.
func ParseDate(s string) (parsed time.Time, ok bool) {
if _, rest, ok := consumeDate(s); !ok || rest != "" {
return time.Time{}, false
}
if n, ok := ParseInteger(s[1:]); !ok {
return time.Time{}, false
} else {
return time.Unix(n, 0), true
}
}
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-display-string.
func consumeDisplayString(s string) (consumed, rest string, ok bool) {
// To prevent excessive allocation, especially when input is large, we
// maintain a buffer of 4 bytes to keep track of the last rune we
// encounter. This way, we can validate that the display string conforms to
// UTF-8 without actually building the whole string.
var lastRune [4]byte
var runeLen int
isPartOfValidRune := func(ch byte) bool {
lastRune[runeLen] = ch
runeLen++
if utf8.FullRune(lastRune[:runeLen]) {
r, s := utf8.DecodeRune(lastRune[:runeLen])
if r == utf8.RuneError {
return false
}
copy(lastRune[:], lastRune[s:runeLen])
runeLen -= s
return true
}
return runeLen <= 4
}
if len(s) <= 1 || s[:2] != `%"` {
return "", s, false
}
i := 2
for i < len(s) {
ch := s[i]
if !isVChar(ch) && !isSP(ch) {
return "", s, false
}
switch ch {
case '"':
if runeLen > 0 {
return "", s, false
}
return s[:i+1], s[i+1:], true
case '%':
if i+2 >= len(s) {
return "", s, false
}
if ch, ok = decOctetHex(s[i+1], s[i+2]); !ok {
return "", s, ok
}
if ok = isPartOfValidRune(ch); !ok {
return "", s, ok
}
i += 3
default:
if ok = isPartOfValidRune(ch); !ok {
return "", s, ok
}
i++
}
}
return "", s, false
}
// ParseDisplayString parses a display string from a given HTTP Structured
// Field Values.
//
// The entire HTTP SFV string must consist of a valid display string. It
// returns the parsed display string and an ok boolean value, indicating
// success or not.
//
// https://www.rfc-editor.org/rfc/rfc9651.html#name-parsing-a-display-string.
func ParseDisplayString(s string) (parsed string, ok bool) {
if _, rest, ok := consumeDisplayString(s); !ok || rest != "" {
return "", false
}
// consumeDisplayString() already validates that we have a valid display
// string. Therefore, we can just construct the display string, without
// validating it again.
s = s[2 : len(s)-1]
var b strings.Builder
for i := 0; i < len(s); {
if s[i] == '%' {
decoded, _ := decOctetHex(s[i+1], s[i+2])
b.WriteByte(decoded)
i += 3
continue
}
b.WriteByte(s[i])
i++
}
return b.String(), true
}
// https://www.rfc-editor.org/rfc/rfc9651.html#parse-bare-item.
func consumeBareItem(s string) (consumed, rest string, ok bool) {
if len(s) == 0 {
return "", s, false
}
ch := s[0]
switch {
case ch == '-' || isDigit(ch):
return consumeIntegerOrDecimal(s)
case ch == '"':
return consumeString(s)
case ch == '*' || isAlpha(ch):
return consumeToken(s)
case ch == ':':
return consumeByteSequence(s)
case ch == '?':
return consumeBoolean(s)
case ch == '@':
return consumeDate(s)
case ch == '%':
return consumeDisplayString(s)
default:
return "", s, 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 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 (
"encoding/binary"
"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(binary.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
binary.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.
//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":
binary.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":
binary.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 != "" {
binary.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(binary.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(binary.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 (
"encoding/binary"
"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 {
binary.NativeEndian.PutUint32(m.Data(4), uint32(cm.TrafficClass))
}
return m.Next(4)
}
func parseTrafficClass(cm *ControlMessage, b []byte) {
cm.TrafficClass = int(binary.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 {
binary.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
}
return m.Next(4)
}
func parseHopLimit(cm *ControlMessage, b []byte) {
cm.HopLimit = int(binary.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
}
defer resp.Body.Close()
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.27
package cases
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "17.0.0"
var xorData string = "" + // Size: 237 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\x03 " +
"\x00\x01%\x00\x01'\x00\x01+\x00\x01-\x00\x01/\x00\x01;\x00\x01=\x00\x01" +
"\x1e\x00\x01\x22"
var exceptions string = "" + // Size: 2478 bytes
"\x00\x12\x12μΜΜ\x12\x12ssSSSs\x13\x18i̇i̇\x10\x09II\x13\x1bʼnʼNʼN\x11" +
"\x09sSS\x10\x1b\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ꞲꞲ\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\x10ɤɤ\x12\x10ƛƛ\x12\x12ffFFFf\x12\x12fiFIFi\x12\x12flFLFl\x13\x1bff" +
"iFFIFfi\x13\x1bfflFFLFfl\x12\x12stSTSt\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: 14000 bytes (13.67 KiB). Checksum: 76c852e9b991a172.
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 < 24:
return uint16(caseValues[n<<6+uint32(b)])
default:
n -= 24
return uint16(sparse.lookup(n, b))
}
}
// caseValues: 26 blocks, 1664 entries, 3328 bytes
// The third block is the zero block.
var caseValues = [1664]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: 0x02da, 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: 0x035b, 0x105: 0x03d9,
0x106: 0x045a, 0x107: 0x04bb, 0x108: 0x0539, 0x109: 0x05ba, 0x10a: 0x061b, 0x10b: 0x0699,
0x10c: 0x071a, 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: 0x077a, 0x131: 0x082b, 0x132: 0x08a9, 0x133: 0x092a, 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: 0x0b0a, 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: 0x0b8a, 0x151: 0x0c0a,
0x152: 0x0c8a, 0x153: 0x0b52, 0x154: 0x0b52, 0x155: 0x0012, 0x156: 0x0e52, 0x157: 0x1152,
0x158: 0x0012, 0x159: 0x1752, 0x15a: 0x0012, 0x15b: 0x1a52, 0x15c: 0x0d0a, 0x15d: 0x0012,
0x15e: 0x0012, 0x15f: 0x0012, 0x160: 0x1d52, 0x161: 0x0d8a, 0x162: 0x0012, 0x163: 0x2052,
0x164: 0x0e0a, 0x165: 0x0e8a, 0x166: 0x0f0a, 0x167: 0x0012, 0x168: 0x2652, 0x169: 0x2652,
0x16a: 0x0f8a, 0x16b: 0x100a, 0x16c: 0x108a, 0x16d: 0x0012, 0x16e: 0x0012, 0x16f: 0x1d52,
0x170: 0x0012, 0x171: 0x110a, 0x172: 0x2c52, 0x173: 0x0012, 0x174: 0x0012, 0x175: 0x3252,
0x176: 0x0012, 0x177: 0x0012, 0x178: 0x0012, 0x179: 0x0012, 0x17a: 0x0012, 0x17b: 0x0012,
0x17c: 0x0012, 0x17d: 0x118a, 0x17e: 0x0012, 0x17f: 0x0012,
// Block 0x6, offset 0x180
0x180: 0x3552, 0x181: 0x0012, 0x182: 0x120a, 0x183: 0x3852, 0x184: 0x0012, 0x185: 0x0012,
0x186: 0x0012, 0x187: 0x128a, 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: 0x0010, 0x196: 0x0012, 0x197: 0x0012,
0x198: 0x0012, 0x199: 0x0012, 0x19a: 0x0012, 0x19b: 0x0012, 0x19c: 0x0012, 0x19d: 0x130a,
0x19e: 0x138a, 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: 0x140d,
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: 0x148a, 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: 0x15ca, 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: 0x170a, 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: 0x178a, 0x251: 0x180a,
0x252: 0x0013, 0x253: 0x0013, 0x254: 0x0013, 0x255: 0x188a, 0x256: 0x190a, 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: 0x198a, 0x271: 0x1a0a, 0x272: 0x0b12, 0x273: 0x5352, 0x274: 0x6253, 0x275: 0x1a8a,
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: 0x1b0a, 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: 0x1bea, 0x311: 0x1c6a,
0x312: 0x1cea, 0x313: 0x1d6a, 0x314: 0x1dea, 0x315: 0x1e6a, 0x316: 0x1eea, 0x317: 0x1f6a,
0x318: 0x1fea, 0x319: 0x206a, 0x31a: 0x20ea, 0x31b: 0x216a, 0x31c: 0x21ea, 0x31d: 0x226a,
0x31e: 0x22ea, 0x31f: 0x236a, 0x320: 0x23ea, 0x321: 0x246a, 0x322: 0x24ea, 0x323: 0x256a,
0x324: 0x25ea, 0x325: 0x266a, 0x326: 0x26ea, 0x327: 0x276a, 0x328: 0x27ea, 0x329: 0x286a,
0x32a: 0x28ea, 0x32b: 0x296a, 0x32c: 0x29ea, 0x32d: 0x2a6a, 0x32e: 0x2aea, 0x32f: 0x2b6a,
0x330: 0x2bea, 0x331: 0x2c6a, 0x332: 0x2cea, 0x333: 0x2d6a, 0x334: 0x2dea, 0x335: 0x2e6a,
0x336: 0x2eea, 0x337: 0x2f6a, 0x338: 0x2fea, 0x339: 0x306a, 0x33a: 0x30ea,
0x33c: 0x0015, 0x33d: 0x316a, 0x33e: 0x31ea, 0x33f: 0x326a,
// 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: 0x3c1a, 0x351: 0x0812,
0x352: 0x3cfa, 0x353: 0x0812, 0x354: 0x3e3a, 0x355: 0x0812, 0x356: 0x3f7a, 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: 0x40ba, 0x381: 0x41aa, 0x382: 0x429a, 0x383: 0x438a, 0x384: 0x447a, 0x385: 0x456a,
0x386: 0x465a, 0x387: 0x474a, 0x388: 0x4839, 0x389: 0x4929, 0x38a: 0x4a19, 0x38b: 0x4b09,
0x38c: 0x4bf9, 0x38d: 0x4ce9, 0x38e: 0x4dd9, 0x38f: 0x4ec9, 0x390: 0x4fba, 0x391: 0x50aa,
0x392: 0x519a, 0x393: 0x528a, 0x394: 0x537a, 0x395: 0x546a, 0x396: 0x555a, 0x397: 0x564a,
0x398: 0x5739, 0x399: 0x5829, 0x39a: 0x5919, 0x39b: 0x5a09, 0x39c: 0x5af9, 0x39d: 0x5be9,
0x39e: 0x5cd9, 0x39f: 0x5dc9, 0x3a0: 0x5eba, 0x3a1: 0x5faa, 0x3a2: 0x609a, 0x3a3: 0x618a,
0x3a4: 0x627a, 0x3a5: 0x636a, 0x3a6: 0x645a, 0x3a7: 0x654a, 0x3a8: 0x6639, 0x3a9: 0x6729,
0x3aa: 0x6819, 0x3ab: 0x6909, 0x3ac: 0x69f9, 0x3ad: 0x6ae9, 0x3ae: 0x6bd9, 0x3af: 0x6cc9,
0x3b0: 0x0812, 0x3b1: 0x0812, 0x3b2: 0x6dba, 0x3b3: 0x6eca, 0x3b4: 0x6f9a,
0x3b6: 0x707a, 0x3b7: 0x715a, 0x3b8: 0x0813, 0x3b9: 0x0813, 0x3ba: 0x9253, 0x3bb: 0x9253,
0x3bc: 0x7299, 0x3bd: 0x0004, 0x3be: 0x736a, 0x3bf: 0x0004,
// Block 0xf, offset 0x3c0
0x3c0: 0x0004, 0x3c1: 0x0004, 0x3c2: 0x73ea, 0x3c3: 0x74fa, 0x3c4: 0x75ca,
0x3c6: 0x76aa, 0x3c7: 0x778a, 0x3c8: 0x9553, 0x3c9: 0x9553, 0x3ca: 0x9853, 0x3cb: 0x9853,
0x3cc: 0x78c9, 0x3cd: 0x0004, 0x3ce: 0x0004, 0x3cf: 0x0004, 0x3d0: 0x0812, 0x3d1: 0x0812,
0x3d2: 0x799a, 0x3d3: 0x7ada, 0x3d6: 0x7c1a, 0x3d7: 0x7cfa,
0x3d8: 0x0813, 0x3d9: 0x0813, 0x3da: 0x9b53, 0x3db: 0x9b53, 0x3dd: 0x0004,
0x3de: 0x0004, 0x3df: 0x0004, 0x3e0: 0x0812, 0x3e1: 0x0812, 0x3e2: 0x7e3a, 0x3e3: 0x7f7a,
0x3e4: 0x80ba, 0x3e5: 0x0912, 0x3e6: 0x819a, 0x3e7: 0x827a, 0x3e8: 0x0813, 0x3e9: 0x0813,
0x3ea: 0xa153, 0x3eb: 0xa153, 0x3ec: 0x0913, 0x3ed: 0x0004, 0x3ee: 0x0004, 0x3ef: 0x0004,
0x3f2: 0x83ba, 0x3f3: 0x84ca, 0x3f4: 0x859a,
0x3f6: 0x867a, 0x3f7: 0x875a, 0x3f8: 0x9e53, 0x3f9: 0x9e53, 0x3fa: 0x4d53, 0x3fb: 0x4d53,
0x3fc: 0x8899, 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: 0x896b, 0x428: 0x0013,
0x42a: 0x89cb, 0x42b: 0x8a0b, 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: 0x8a6b, 0x4a3: 0x8b53,
0x4a4: 0x8acb, 0x4a5: 0x8b2a, 0x4a6: 0x8b8a, 0x4a7: 0x0f13, 0x4a8: 0x0f12, 0x4a9: 0x0313,
0x4aa: 0x0312, 0x4ab: 0x0713, 0x4ac: 0x0712, 0x4ad: 0x8beb, 0x4ae: 0x8c4b, 0x4af: 0x8cab,
0x4b0: 0x8d0b, 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: 0x8d6b, 0x4bf: 0x8dcb,
// 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: 0x8e2b, 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: 0x8e8b, 0x4eb: 0x8eeb, 0x4ec: 0x8f4b, 0x4ed: 0x8fab, 0x4ee: 0x900b, 0x4ef: 0x0012,
0x4f0: 0x906b, 0x4f1: 0x90cb, 0x4f2: 0x912b, 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: 0x92aa, 0x501: 0x932a, 0x502: 0x93aa, 0x503: 0x942a, 0x504: 0x94da, 0x505: 0x958a,
0x506: 0x960a,
0x513: 0x968a, 0x514: 0x976a, 0x515: 0x984a, 0x516: 0x992a, 0x517: 0x9a0a,
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
0x5a0: 0x1b13, 0x5a1: 0x1d13, 0x5a2: 0x1f13, 0x5a3: 0x1d13,
0x5a4: 0x1b13, 0x5a5: 0xd453, 0x5a6: 0xd753, 0x5a7: 0xd453, 0x5a8: 0xda53, 0x5a9: 0xdd53,
0x5aa: 0xe053, 0x5ab: 0xdd53, 0x5ac: 0xda53, 0x5ad: 0xd453, 0x5ae: 0xd753, 0x5af: 0xd453,
0x5b0: 0xe353, 0x5b1: 0xe653, 0x5b2: 0x0553, 0x5b3: 0xe653, 0x5b4: 0xe353, 0x5b5: 0xd453,
0x5b6: 0xd753, 0x5b7: 0xd453, 0x5b8: 0xda53, 0x5bb: 0x1b12,
0x5bc: 0x1d12, 0x5bd: 0x1f12, 0x5be: 0x1d12, 0x5bf: 0x1b12,
// Block 0x17, offset 0x5c0
0x5c0: 0xd452, 0x5c1: 0xd752, 0x5c2: 0xd452, 0x5c3: 0xda52, 0x5c4: 0xdd52, 0x5c5: 0xe052,
0x5c6: 0xdd52, 0x5c7: 0xda52, 0x5c8: 0xd452, 0x5c9: 0xd752, 0x5ca: 0xd452, 0x5cb: 0xe352,
0x5cc: 0xe652, 0x5cd: 0x0552, 0x5ce: 0xe652, 0x5cf: 0xe352, 0x5d0: 0xd452, 0x5d1: 0xd752,
0x5d2: 0xd452, 0x5d3: 0xda52,
// Block 0x18, offset 0x600
0x600: 0x2213, 0x601: 0x2213, 0x602: 0x2613, 0x603: 0x2613, 0x604: 0x2213, 0x605: 0x2213,
0x606: 0x2e13, 0x607: 0x2e13, 0x608: 0x2213, 0x609: 0x2213, 0x60a: 0x2613, 0x60b: 0x2613,
0x60c: 0x2213, 0x60d: 0x2213, 0x60e: 0x3e13, 0x60f: 0x3e13, 0x610: 0x2213, 0x611: 0x2213,
0x612: 0x2613, 0x613: 0x2613, 0x614: 0x2213, 0x615: 0x2213, 0x616: 0x2e13, 0x617: 0x2e13,
0x618: 0x2213, 0x619: 0x2213, 0x61a: 0x2613, 0x61b: 0x2613, 0x61c: 0x2213, 0x61d: 0x2213,
0x61e: 0xe953, 0x61f: 0xe953, 0x620: 0xec53, 0x621: 0xec53, 0x622: 0x2212, 0x623: 0x2212,
0x624: 0x2612, 0x625: 0x2612, 0x626: 0x2212, 0x627: 0x2212, 0x628: 0x2e12, 0x629: 0x2e12,
0x62a: 0x2212, 0x62b: 0x2212, 0x62c: 0x2612, 0x62d: 0x2612, 0x62e: 0x2212, 0x62f: 0x2212,
0x630: 0x3e12, 0x631: 0x3e12, 0x632: 0x2212, 0x633: 0x2212, 0x634: 0x2612, 0x635: 0x2612,
0x636: 0x2212, 0x637: 0x2212, 0x638: 0x2e12, 0x639: 0x2e12, 0x63a: 0x2212, 0x63b: 0x2212,
0x63c: 0x2612, 0x63d: 0x2612, 0x63e: 0x2212, 0x63f: 0x2212,
// Block 0x19, offset 0x640
0x642: 0x0010,
0x647: 0x0010, 0x649: 0x0010, 0x64b: 0x0010,
0x64d: 0x0010, 0x64e: 0x0010, 0x64f: 0x0010, 0x651: 0x0010,
0x652: 0x0010, 0x654: 0x0010, 0x657: 0x0010,
0x659: 0x0010, 0x65b: 0x0010, 0x65d: 0x0010,
0x65f: 0x0010, 0x661: 0x0010, 0x662: 0x0010,
0x664: 0x0010, 0x667: 0x0010, 0x668: 0x0010, 0x669: 0x0010,
0x66a: 0x0010, 0x66c: 0x0010, 0x66d: 0x0010, 0x66e: 0x0010, 0x66f: 0x0010,
0x670: 0x0010, 0x671: 0x0010, 0x672: 0x0010, 0x674: 0x0010, 0x675: 0x0010,
0x676: 0x0010, 0x677: 0x0010, 0x679: 0x0010, 0x67a: 0x0010, 0x67b: 0x0010,
0x67c: 0x0010, 0x67e: 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: 0x18, 0xc3: 0x19, 0xc4: 0x1a, 0xc5: 0x1b, 0xc6: 0x01, 0xc7: 0x02,
0xc8: 0x1c, 0xc9: 0x03, 0xca: 0x04, 0xcb: 0x1d, 0xcc: 0x1e, 0xcd: 0x05, 0xce: 0x06, 0xcf: 0x07,
0xd0: 0x1f, 0xd1: 0x20, 0xd2: 0x21, 0xd3: 0x22, 0xd4: 0x23, 0xd5: 0x24, 0xd6: 0x08, 0xd7: 0x25,
0xd8: 0x26, 0xd9: 0x27, 0xda: 0x28, 0xdb: 0x29, 0xdc: 0x2a, 0xdd: 0x2b, 0xde: 0x2c, 0xdf: 0x2d,
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: 0x2e, 0x121: 0x2f, 0x122: 0x30, 0x123: 0x09, 0x124: 0x31, 0x125: 0x32, 0x126: 0x33, 0x127: 0x34,
0x128: 0x35, 0x129: 0x36, 0x12a: 0x37, 0x12b: 0x38, 0x12c: 0x39, 0x12d: 0x3a, 0x12e: 0x3b, 0x12f: 0x3c,
0x130: 0x3d, 0x131: 0x3e, 0x132: 0x3f, 0x133: 0x40, 0x134: 0x41, 0x135: 0x42, 0x136: 0x43, 0x137: 0x44,
0x138: 0x45, 0x139: 0x46, 0x13a: 0x47, 0x13b: 0x48, 0x13c: 0x49, 0x13d: 0x4a, 0x13e: 0x4b, 0x13f: 0x4c,
// Block 0x5, offset 0x140
0x140: 0x4d, 0x141: 0x4e, 0x142: 0x4f, 0x143: 0x0a, 0x144: 0x28, 0x145: 0x28, 0x146: 0x28, 0x147: 0x28,
0x148: 0x28, 0x149: 0x50, 0x14a: 0x51, 0x14b: 0x52, 0x14c: 0x53, 0x14d: 0x54, 0x14e: 0x55, 0x14f: 0x56,
0x150: 0x57, 0x151: 0x28, 0x152: 0x28, 0x153: 0x28, 0x154: 0x28, 0x155: 0x28, 0x156: 0x28, 0x157: 0x28,
0x158: 0x28, 0x159: 0x58, 0x15a: 0x59, 0x15b: 0x5a, 0x15c: 0x5b, 0x15d: 0x5c, 0x15e: 0x5d, 0x15f: 0x5e,
0x160: 0x5f, 0x161: 0x60, 0x162: 0x61, 0x163: 0x62, 0x164: 0x63, 0x165: 0x64, 0x167: 0x65,
0x168: 0x66, 0x169: 0x67, 0x16a: 0x68, 0x16b: 0x69, 0x16c: 0x6a, 0x16d: 0x6b, 0x16e: 0x6c, 0x16f: 0x6d,
0x170: 0x6e, 0x171: 0x6f, 0x172: 0x70, 0x173: 0x71, 0x174: 0x72, 0x175: 0x73, 0x176: 0x74, 0x177: 0x75,
0x178: 0x76, 0x179: 0x76, 0x17a: 0x77, 0x17b: 0x76, 0x17c: 0x78, 0x17d: 0x0b, 0x17e: 0x0c, 0x17f: 0x0d,
// Block 0x6, offset 0x180
0x180: 0x79, 0x181: 0x7a, 0x182: 0x7b, 0x183: 0x7c, 0x184: 0x0e, 0x185: 0x7d, 0x186: 0x7e,
0x192: 0x7f, 0x193: 0x0f,
0x1b0: 0x80, 0x1b1: 0x10, 0x1b2: 0x76, 0x1b3: 0x81, 0x1b4: 0x82, 0x1b5: 0x83, 0x1b6: 0x84, 0x1b7: 0x85,
0x1b8: 0x86,
// Block 0x7, offset 0x1c0
0x1c0: 0x87, 0x1c2: 0x88, 0x1c3: 0x89, 0x1c4: 0x8a, 0x1c5: 0x28, 0x1c6: 0x8b,
// Block 0x8, offset 0x200
0x200: 0x8c, 0x201: 0x28, 0x202: 0x28, 0x203: 0x28, 0x204: 0x28, 0x205: 0x28, 0x206: 0x28, 0x207: 0x28,
0x208: 0x28, 0x209: 0x28, 0x20a: 0x28, 0x20b: 0x28, 0x20c: 0x28, 0x20d: 0x28, 0x20e: 0x28, 0x20f: 0x28,
0x210: 0x28, 0x211: 0x28, 0x212: 0x8d, 0x213: 0x8e, 0x214: 0x28, 0x215: 0x28, 0x216: 0x28, 0x217: 0x28,
0x218: 0x8f, 0x219: 0x90, 0x21a: 0x91, 0x21b: 0x92, 0x21c: 0x93, 0x21d: 0x94, 0x21e: 0x11, 0x21f: 0x95,
0x220: 0x96, 0x221: 0x97, 0x222: 0x28, 0x223: 0x98, 0x224: 0x99, 0x225: 0x9a, 0x226: 0x9b, 0x227: 0x9c,
0x228: 0x9d, 0x229: 0x9e, 0x22a: 0x9f, 0x22b: 0xa0, 0x22c: 0xa1, 0x22d: 0xa2, 0x22e: 0xa3, 0x22f: 0xa4,
0x230: 0x28, 0x231: 0x28, 0x232: 0x28, 0x233: 0x28, 0x234: 0x28, 0x235: 0x28, 0x236: 0x28, 0x237: 0x28,
0x238: 0x28, 0x239: 0x28, 0x23a: 0x28, 0x23b: 0x28, 0x23c: 0x28, 0x23d: 0x28, 0x23e: 0x28, 0x23f: 0x28,
// Block 0x9, offset 0x240
0x240: 0x28, 0x241: 0x28, 0x242: 0x28, 0x243: 0x28, 0x244: 0x28, 0x245: 0x28, 0x246: 0x28, 0x247: 0x28,
0x248: 0x28, 0x249: 0x28, 0x24a: 0x28, 0x24b: 0x28, 0x24c: 0x28, 0x24d: 0x28, 0x24e: 0x28, 0x24f: 0x28,
0x250: 0x28, 0x251: 0x28, 0x252: 0x28, 0x253: 0x28, 0x254: 0x28, 0x255: 0x28, 0x256: 0x28, 0x257: 0x28,
0x258: 0x28, 0x259: 0x28, 0x25a: 0x28, 0x25b: 0x28, 0x25c: 0x28, 0x25d: 0x28, 0x25e: 0x28, 0x25f: 0x28,
0x260: 0x28, 0x261: 0x28, 0x262: 0x28, 0x263: 0x28, 0x264: 0x28, 0x265: 0x28, 0x266: 0x28, 0x267: 0x28,
0x268: 0x28, 0x269: 0x28, 0x26a: 0x28, 0x26b: 0x28, 0x26c: 0x28, 0x26d: 0x28, 0x26e: 0x28, 0x26f: 0x28,
0x270: 0x28, 0x271: 0x28, 0x272: 0x28, 0x273: 0x28, 0x274: 0x28, 0x275: 0x28, 0x276: 0x28, 0x277: 0x28,
0x278: 0x28, 0x279: 0x28, 0x27a: 0x28, 0x27b: 0x28, 0x27c: 0x28, 0x27d: 0x28, 0x27e: 0x28, 0x27f: 0x28,
// Block 0xa, offset 0x280
0x280: 0x28, 0x281: 0x28, 0x282: 0x28, 0x283: 0x28, 0x284: 0x28, 0x285: 0x28, 0x286: 0x28, 0x287: 0x28,
0x288: 0x28, 0x289: 0x28, 0x28a: 0x28, 0x28b: 0x28, 0x28c: 0x28, 0x28d: 0x28, 0x28e: 0x28, 0x28f: 0x28,
0x290: 0x28, 0x291: 0x28, 0x292: 0x28, 0x293: 0x28, 0x294: 0x28, 0x295: 0x28, 0x296: 0x28, 0x297: 0x28,
0x298: 0x28, 0x299: 0x28, 0x29a: 0x28, 0x29b: 0x28, 0x29c: 0x28, 0x29d: 0x28, 0x29e: 0xa5, 0x29f: 0xa6,
// Block 0xb, offset 0x2c0
0x2ec: 0x12, 0x2ed: 0xa7, 0x2ee: 0xa8, 0x2ef: 0xa9,
0x2f0: 0x28, 0x2f1: 0x28, 0x2f2: 0x28, 0x2f3: 0x28, 0x2f4: 0xaa, 0x2f5: 0xab, 0x2f6: 0xac, 0x2f7: 0xad,
0x2f8: 0xae, 0x2f9: 0xaf, 0x2fa: 0x28, 0x2fb: 0xb0, 0x2fc: 0xb1, 0x2fd: 0xb2, 0x2fe: 0xb3, 0x2ff: 0xb4,
// Block 0xc, offset 0x300
0x300: 0xb5, 0x301: 0xb6, 0x302: 0x28, 0x303: 0xb7, 0x305: 0xb8, 0x307: 0xb9,
0x30a: 0xba, 0x30b: 0xbb, 0x30c: 0xbc, 0x30d: 0xbd, 0x30e: 0xbe, 0x30f: 0xbf,
0x310: 0xc0, 0x311: 0xc1, 0x312: 0xc2, 0x313: 0xc3, 0x314: 0xc4, 0x315: 0xc5, 0x316: 0x13, 0x317: 0x97,
0x318: 0x28, 0x319: 0x28, 0x31a: 0x28, 0x31b: 0x28, 0x31c: 0xc6, 0x31d: 0xc7, 0x31e: 0xc8,
0x320: 0xc9, 0x321: 0xca, 0x322: 0xcb, 0x323: 0xcc, 0x324: 0xcd, 0x325: 0xce, 0x326: 0xcf,
0x328: 0xd0, 0x329: 0xd1, 0x32a: 0xd2, 0x32b: 0xd3, 0x32c: 0x62, 0x32d: 0xd4, 0x32e: 0xd5,
0x330: 0x28, 0x331: 0xd6, 0x332: 0xd7, 0x333: 0xd8, 0x334: 0xd9, 0x335: 0xda, 0x336: 0xdb,
0x33a: 0xdc, 0x33b: 0xdd, 0x33c: 0xde, 0x33d: 0xdf, 0x33e: 0xe0, 0x33f: 0xe1,
// Block 0xd, offset 0x340
0x340: 0xe2, 0x341: 0xe3, 0x342: 0xe4, 0x343: 0xe5, 0x344: 0xe6, 0x345: 0xe7, 0x346: 0xe8, 0x347: 0xe9,
0x348: 0xea, 0x349: 0xeb, 0x34a: 0xec, 0x34b: 0xed, 0x34c: 0xee, 0x34d: 0xef, 0x34e: 0xf0, 0x34f: 0xf1,
0x350: 0xf2, 0x351: 0xf3, 0x352: 0xf4, 0x353: 0xf5, 0x356: 0xf6, 0x357: 0xf7,
0x358: 0xf8, 0x359: 0xf9, 0x35a: 0xfa, 0x35b: 0xfb, 0x35c: 0xfc,
0x360: 0xfd, 0x362: 0xfe, 0x363: 0xff, 0x364: 0x100, 0x365: 0x101, 0x366: 0x102, 0x367: 0x103,
0x368: 0x104, 0x369: 0x105, 0x36a: 0x106, 0x36b: 0x107, 0x36d: 0x108, 0x36f: 0x109,
0x370: 0x10a, 0x371: 0x10b, 0x372: 0x10c, 0x374: 0x10d, 0x375: 0x10e, 0x376: 0x10f, 0x377: 0x110,
0x37b: 0x111, 0x37c: 0x112, 0x37d: 0x113, 0x37e: 0x114,
// Block 0xe, offset 0x380
0x380: 0x28, 0x381: 0x28, 0x382: 0x28, 0x383: 0x28, 0x384: 0x28, 0x385: 0x28, 0x386: 0x28, 0x387: 0x28,
0x388: 0x28, 0x389: 0x28, 0x38a: 0x28, 0x38b: 0x28, 0x38c: 0x28, 0x38d: 0x28, 0x38e: 0xce,
0x390: 0x28, 0x391: 0x115, 0x392: 0x28, 0x393: 0x28, 0x394: 0x28, 0x395: 0x116,
0x3be: 0xab, 0x3bf: 0x117,
// Block 0xf, offset 0x3c0
0x3c0: 0x28, 0x3c1: 0x28, 0x3c2: 0x28, 0x3c3: 0x28, 0x3c4: 0x28, 0x3c5: 0x28, 0x3c6: 0x28, 0x3c7: 0x28,
0x3c8: 0x28, 0x3c9: 0x28, 0x3ca: 0x28, 0x3cb: 0x28, 0x3cc: 0x28, 0x3cd: 0x28, 0x3ce: 0x28, 0x3cf: 0x28,
0x3d0: 0x118, 0x3d1: 0x119, 0x3d2: 0x28, 0x3d3: 0x28, 0x3d4: 0x28, 0x3d5: 0x28, 0x3d6: 0x28, 0x3d7: 0x28,
0x3d8: 0x28, 0x3d9: 0x28, 0x3da: 0x28, 0x3db: 0x28, 0x3dc: 0x28, 0x3dd: 0x28, 0x3de: 0x28, 0x3df: 0x28,
0x3e0: 0x28, 0x3e1: 0x28, 0x3e2: 0x28, 0x3e3: 0x28, 0x3e4: 0x28, 0x3e5: 0x28, 0x3e6: 0x28, 0x3e7: 0x28,
0x3e8: 0x28, 0x3e9: 0x28, 0x3ea: 0x28, 0x3eb: 0x28, 0x3ec: 0x28, 0x3ed: 0x28, 0x3ee: 0x28, 0x3ef: 0x28,
0x3f0: 0x28, 0x3f1: 0x28, 0x3f2: 0x28, 0x3f3: 0x28, 0x3f4: 0x28, 0x3f5: 0x28, 0x3f6: 0x28, 0x3f7: 0x28,
0x3f8: 0x28, 0x3f9: 0x28, 0x3fa: 0x28, 0x3fb: 0x28, 0x3fc: 0x28, 0x3fd: 0x28, 0x3fe: 0x28, 0x3ff: 0x28,
// Block 0x10, offset 0x400
0x400: 0x28, 0x401: 0x28, 0x402: 0x28, 0x403: 0x28, 0x404: 0x28, 0x405: 0x28, 0x406: 0x28, 0x407: 0x28,
0x408: 0x28, 0x409: 0x28, 0x40a: 0x28, 0x40b: 0x28, 0x40c: 0x28, 0x40d: 0x28, 0x40e: 0x28, 0x40f: 0xb7,
0x410: 0x28, 0x411: 0x28, 0x412: 0x28, 0x413: 0x28, 0x414: 0x28, 0x415: 0x28, 0x416: 0x28, 0x417: 0x28,
0x418: 0x28, 0x419: 0x11a,
// Block 0x11, offset 0x440
0x444: 0x11b,
0x460: 0x28, 0x461: 0x28, 0x462: 0x28, 0x463: 0x28, 0x464: 0x28, 0x465: 0x28, 0x466: 0x28, 0x467: 0x28,
0x468: 0x107, 0x469: 0x11c, 0x46a: 0x11d, 0x46b: 0x11e, 0x46c: 0x11f, 0x46d: 0x120, 0x46e: 0x121,
0x475: 0x122,
0x479: 0x123, 0x47a: 0x14, 0x47b: 0x15, 0x47c: 0x28, 0x47d: 0x124, 0x47e: 0x125, 0x47f: 0x126,
// Block 0x12, offset 0x480
0x4bf: 0x127,
// Block 0x13, offset 0x4c0
0x4f0: 0x28, 0x4f1: 0x128, 0x4f2: 0x129,
// Block 0x14, offset 0x500
0x533: 0x12a,
0x53c: 0x12b, 0x53d: 0x12c,
// Block 0x15, offset 0x540
0x545: 0x12d, 0x546: 0x12e,
0x549: 0x12f,
0x550: 0x130, 0x551: 0x131, 0x552: 0x132, 0x553: 0x133, 0x554: 0x134, 0x555: 0x135, 0x556: 0x136, 0x557: 0x137,
0x558: 0x138, 0x559: 0x139, 0x55a: 0x13a, 0x55b: 0x13b, 0x55c: 0x13c, 0x55d: 0x13d, 0x55e: 0x13e, 0x55f: 0x13f,
0x568: 0x140, 0x569: 0x141, 0x56a: 0x142,
0x57c: 0x143,
// Block 0x16, offset 0x580
0x580: 0x144, 0x581: 0x145, 0x582: 0x146, 0x584: 0x147, 0x585: 0x148,
0x58a: 0x149, 0x58b: 0x14a,
0x593: 0x14b, 0x597: 0x14c,
0x59b: 0x14d, 0x59f: 0x14e,
0x5a0: 0x28, 0x5a1: 0x28, 0x5a2: 0x28, 0x5a3: 0x14f, 0x5a4: 0x16, 0x5a5: 0x150,
0x5b8: 0x151, 0x5b9: 0x17, 0x5ba: 0x152,
// Block 0x17, offset 0x5c0
0x5c4: 0x153, 0x5c5: 0x154, 0x5c6: 0x155,
0x5cf: 0x156,
0x5ef: 0x12a,
// 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: 0x157, 0x641: 0x158, 0x644: 0x158, 0x645: 0x158, 0x646: 0x158, 0x647: 0x159,
// Block 0x1a, offset 0x680
0x6a0: 0x17,
}
// sparseOffsets: 323 entries, 646 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, 0x243, 0x24b, 0x254, 0x25d, 0x266, 0x26b, 0x26e, 0x27a, 0x288, 0x28a, 0x291, 0x295, 0x2a1, 0x2a2, 0x2ad, 0x2b5, 0x2bd, 0x2c3, 0x2c4, 0x2d2, 0x2d7, 0x2da, 0x2df, 0x2e3, 0x2e9, 0x2ee, 0x2f1, 0x2f6, 0x2fb, 0x2fc, 0x302, 0x304, 0x305, 0x307, 0x309, 0x30c, 0x30d, 0x30f, 0x312, 0x318, 0x31c, 0x31e, 0x323, 0x32a, 0x339, 0x343, 0x344, 0x34d, 0x351, 0x356, 0x35e, 0x364, 0x36a, 0x374, 0x379, 0x382, 0x388, 0x391, 0x395, 0x39d, 0x39f, 0x3a1, 0x3a4, 0x3a6, 0x3a8, 0x3a9, 0x3aa, 0x3ac, 0x3ae, 0x3b4, 0x3b9, 0x3bb, 0x3c2, 0x3c5, 0x3c7, 0x3cd, 0x3d2, 0x3d4, 0x3d5, 0x3d6, 0x3d7, 0x3d9, 0x3db, 0x3dd, 0x3e0, 0x3e2, 0x3e5, 0x3ed, 0x3f0, 0x3f4, 0x3fc, 0x3fe, 0x40e, 0x40f, 0x411, 0x416, 0x41c, 0x41e, 0x41f, 0x421, 0x423, 0x424, 0x426, 0x433, 0x434, 0x435, 0x439, 0x43b, 0x43c, 0x43d, 0x43e, 0x43f, 0x442, 0x44a, 0x44b, 0x44e, 0x454, 0x457, 0x45e, 0x464, 0x466, 0x46a, 0x472, 0x478, 0x47c, 0x483, 0x487, 0x48b, 0x494, 0x49e, 0x4a0, 0x4a6, 0x4ac, 0x4b6, 0x4c0, 0x4c6, 0x4d2, 0x4d4, 0x4dd, 0x4e3, 0x4e9, 0x4ef, 0x4f2, 0x4f8, 0x4fb, 0x504, 0x506, 0x50f, 0x513, 0x514, 0x517, 0x521, 0x524, 0x526, 0x52d, 0x535, 0x53b, 0x542, 0x543, 0x549, 0x54b, 0x551, 0x554, 0x55c, 0x563, 0x56d, 0x576, 0x57a, 0x57d, 0x582, 0x587, 0x588, 0x589, 0x58a, 0x58b, 0x58d, 0x591, 0x592, 0x598, 0x59b, 0x59c, 0x59f, 0x5a1, 0x5a5, 0x5a6, 0x5aa, 0x5ac, 0x5af, 0x5b1, 0x5b5, 0x5b8, 0x5ba, 0x5bf, 0x5c0, 0x5c2, 0x5c3, 0x5c8, 0x5cc, 0x5cd, 0x5d0, 0x5d4, 0x5df, 0x5e3, 0x5eb, 0x5f0, 0x5f4, 0x5f7, 0x5fb, 0x5fe, 0x601, 0x606, 0x60a, 0x60e, 0x612, 0x616, 0x618, 0x61a, 0x61d, 0x621, 0x627, 0x628, 0x629, 0x62c, 0x62e, 0x630, 0x633, 0x638, 0x63c, 0x647, 0x64b, 0x64d, 0x653, 0x65c, 0x661, 0x662, 0x665, 0x666, 0x667, 0x669, 0x66a, 0x66b}
// sparseValues: 1643 entries, 6572 bytes
var sparseValues = [1643]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: 0x0014, 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: 0x098b, lo: 0xba, hi: 0xba},
{value: 0x0716, lo: 0xbb, hi: 0xbc},
{value: 0x2953, lo: 0xbd, hi: 0xbd},
{value: 0x0a0b, lo: 0xbe, hi: 0xbe},
{value: 0x0a8a, 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: 0x8f},
{value: 0x0014, lo: 0x90, hi: 0x91},
{value: 0x0024, lo: 0x97, 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: 0x9c, 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: 0x9c, 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: 0x9a},
// 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: 0x9c},
{value: 0x0034, lo: 0x9d, hi: 0x9d},
{value: 0x0024, lo: 0xa0, hi: 0xa5},
{value: 0x0034, lo: 0xa6, hi: 0xa6},
{value: 0x0024, lo: 0xa7, hi: 0xaa},
{value: 0x0034, lo: 0xab, hi: 0xab},
// Block 0x52, offset 0x243
{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 0x24b
{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 0x254
{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 0x25d
{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 0x266
{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 0x26b
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8d, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbd},
// Block 0x58, offset 0x26e
{value: 0x32ea, lo: 0x80, hi: 0x80},
{value: 0x336a, lo: 0x81, hi: 0x81},
{value: 0x33ea, lo: 0x82, hi: 0x82},
{value: 0x346a, lo: 0x83, hi: 0x83},
{value: 0x34ea, lo: 0x84, hi: 0x84},
{value: 0x356a, lo: 0x85, hi: 0x85},
{value: 0x35ea, lo: 0x86, hi: 0x86},
{value: 0x366a, lo: 0x87, hi: 0x87},
{value: 0x36ea, lo: 0x88, hi: 0x88},
{value: 0x0316, lo: 0x89, hi: 0x8a},
{value: 0x8353, lo: 0x90, hi: 0xba},
{value: 0x8353, lo: 0xbd, hi: 0xbf},
// Block 0x59, offset 0x27a
{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 0x288
{value: 0x0012, lo: 0x80, hi: 0xab},
{value: 0x0015, lo: 0xac, hi: 0xbf},
// Block 0x5b, offset 0x28a
{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 0x291
{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 0x295
{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 0x2a1
{value: 0x0117, lo: 0x80, hi: 0xbf},
// Block 0x5f, offset 0x2a2
{value: 0x0117, lo: 0x80, hi: 0x95},
{value: 0x379a, lo: 0x96, hi: 0x96},
{value: 0x384a, lo: 0x97, hi: 0x97},
{value: 0x38fa, lo: 0x98, hi: 0x98},
{value: 0x39aa, lo: 0x99, hi: 0x99},
{value: 0x3a5a, lo: 0x9a, hi: 0x9a},
{value: 0x3b0a, lo: 0x9b, hi: 0x9b},
{value: 0x0012, lo: 0x9c, hi: 0x9d},
{value: 0x3bbb, lo: 0x9e, hi: 0x9e},
{value: 0x0012, lo: 0x9f, hi: 0x9f},
{value: 0x0117, lo: 0xa0, hi: 0xbf},
// Block 0x60, offset 0x2ad
{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 0x2b5
{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 0x2bd
{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 0x2c3
{value: 0x0015, lo: 0x90, hi: 0x9c},
// Block 0x64, offset 0x2c4
{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 0x2d2
{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 0x2d7
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0716, lo: 0x83, hi: 0x84},
{value: 0x0010, lo: 0x85, hi: 0x88},
// Block 0x67, offset 0x2da
{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 0x2df
{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 0x2e3
{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 0x2e9
{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 0x2ee
{value: 0x0010, lo: 0x80, hi: 0xa7},
{value: 0x0014, lo: 0xaf, hi: 0xaf},
{value: 0x0034, lo: 0xbf, hi: 0xbf},
// Block 0x6c, offset 0x2f1
{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 0x2f6
{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 0x2fb
{value: 0x0014, lo: 0xaf, hi: 0xaf},
// Block 0x6f, offset 0x2fc
{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 0x302
{value: 0x0034, lo: 0x99, hi: 0x9a},
{value: 0x0004, lo: 0x9b, hi: 0x9e},
// Block 0x71, offset 0x304
{value: 0x0004, lo: 0xbc, hi: 0xbe},
// Block 0x72, offset 0x305
{value: 0x0010, lo: 0x85, hi: 0xaf},
{value: 0x0010, lo: 0xb1, hi: 0xbf},
// Block 0x73, offset 0x307
{value: 0x0010, lo: 0x80, hi: 0x8e},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x74, offset 0x309
{value: 0x0010, lo: 0x80, hi: 0x94},
{value: 0x0014, lo: 0x95, hi: 0x95},
{value: 0x0010, lo: 0x96, hi: 0xbf},
// Block 0x75, offset 0x30c
{value: 0x0010, lo: 0x80, hi: 0x8c},
// Block 0x76, offset 0x30d
{value: 0x0010, lo: 0x90, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbd},
// Block 0x77, offset 0x30f
{value: 0x0010, lo: 0x80, hi: 0x8b},
{value: 0x0014, lo: 0x8c, hi: 0x8c},
{value: 0x0010, lo: 0x90, hi: 0xab},
// Block 0x78, offset 0x312
{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 0x318
{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 0x31c
{value: 0x0010, lo: 0x80, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb1},
// Block 0x7b, offset 0x31e
{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 0x323
{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 0x32a
{value: 0x0117, lo: 0x80, hi: 0x83},
{value: 0x6553, lo: 0x84, hi: 0x84},
{value: 0x918b, lo: 0x85, hi: 0x85},
{value: 0x8f53, lo: 0x86, hi: 0x86},
{value: 0x0f16, lo: 0x87, hi: 0x88},
{value: 0x0316, lo: 0x89, hi: 0x8a},
{value: 0x91eb, lo: 0x8b, hi: 0x8b},
{value: 0x0117, lo: 0x8c, hi: 0x9b},
{value: 0x924b, lo: 0x9c, hi: 0x9c},
{value: 0x0015, lo: 0xb1, 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 0x339
{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 0x343
{value: 0x0010, lo: 0x80, hi: 0xb3},
// Block 0x80, offset 0x344
{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 0x34d
{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 0x351
{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 0x356
{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 0x35e
{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 0x364
{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 0x36a
{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 0x374
{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 0x379
{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 0x382
{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 0x388
{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 0x391
{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 0x395
{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 0x39d
{value: 0x0010, lo: 0x80, hi: 0xa3},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x8e, offset 0x39f
{value: 0x0010, lo: 0x80, hi: 0x86},
{value: 0x0010, lo: 0x8b, hi: 0xbb},
// Block 0x8f, offset 0x3a1
{value: 0x0010, lo: 0x80, hi: 0x81},
{value: 0x0010, lo: 0x83, hi: 0x84},
{value: 0x0010, lo: 0x86, hi: 0xbf},
// Block 0x90, offset 0x3a4
{value: 0x0010, lo: 0x80, hi: 0xb1},
{value: 0x0004, lo: 0xb2, hi: 0xbf},
// Block 0x91, offset 0x3a6
{value: 0x0004, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x93, hi: 0xbf},
// Block 0x92, offset 0x3a8
{value: 0x0010, lo: 0x80, hi: 0xbd},
// Block 0x93, offset 0x3a9
{value: 0x0010, lo: 0x90, hi: 0xbf},
// Block 0x94, offset 0x3aa
{value: 0x0010, lo: 0x80, hi: 0x8f},
{value: 0x0010, lo: 0x92, hi: 0xbf},
// Block 0x95, offset 0x3ac
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0010, lo: 0xb0, hi: 0xbb},
// Block 0x96, offset 0x3ae
{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 0x3b4
{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 0x3b9
{value: 0x0010, lo: 0x80, hi: 0xbc},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x99, offset 0x3bb
{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 0x3c2
{value: 0x0004, lo: 0x80, hi: 0x80},
{value: 0x5f52, lo: 0x81, hi: 0x9a},
{value: 0x0004, lo: 0xb0, hi: 0xb0},
// Block 0x9b, offset 0x3c5
{value: 0x0014, lo: 0x9e, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xbe},
// Block 0x9c, offset 0x3c7
{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 0x3cd
{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 0x3d2
{value: 0x0010, lo: 0x80, hi: 0x8d},
{value: 0x0010, lo: 0x90, hi: 0x9d},
// Block 0x9f, offset 0x3d4
{value: 0x0010, lo: 0x80, hi: 0xba},
// Block 0xa0, offset 0x3d5
{value: 0x0010, lo: 0x80, hi: 0xb4},
// Block 0xa1, offset 0x3d6
{value: 0x0034, lo: 0xbd, hi: 0xbd},
// Block 0xa2, offset 0x3d7
{value: 0x0010, lo: 0x80, hi: 0x9c},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0xa3, offset 0x3d9
{value: 0x0010, lo: 0x80, hi: 0x90},
{value: 0x0034, lo: 0xa0, hi: 0xa0},
// Block 0xa4, offset 0x3db
{value: 0x0010, lo: 0x80, hi: 0x9f},
{value: 0x0010, lo: 0xad, hi: 0xbf},
// Block 0xa5, offset 0x3dd
{value: 0x0010, lo: 0x80, hi: 0x8a},
{value: 0x0010, lo: 0x90, hi: 0xb5},
{value: 0x0024, lo: 0xb6, hi: 0xba},
// Block 0xa6, offset 0x3e0
{value: 0x0010, lo: 0x80, hi: 0x9d},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0xa7, offset 0x3e2
{value: 0x0010, lo: 0x80, hi: 0x83},
{value: 0x0010, lo: 0x88, hi: 0x8f},
{value: 0x0010, lo: 0x91, hi: 0x95},
// Block 0xa8, offset 0x3e5
{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 0x3ed
{value: 0xb652, lo: 0x80, hi: 0x87},
{value: 0xb952, lo: 0x88, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0xbf},
// Block 0xaa, offset 0x3f0
{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 0x3f4
{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 0x3fc
{value: 0x0010, lo: 0x80, hi: 0xa7},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xad, offset 0x3fe
{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 0x40e
{value: 0x0010, lo: 0x80, hi: 0xb6},
// Block 0xaf, offset 0x40f
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xa7},
// Block 0xb0, offset 0x411
{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 0x416
{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 0x41c
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb6},
// Block 0xb3, offset 0x41e
{value: 0x0010, lo: 0x80, hi: 0x9e},
// Block 0xb4, offset 0x41f
{value: 0x0010, lo: 0xa0, hi: 0xb2},
{value: 0x0010, lo: 0xb4, hi: 0xb5},
// Block 0xb5, offset 0x421
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb9},
// Block 0xb6, offset 0x423
{value: 0x0010, lo: 0x80, hi: 0x99},
// Block 0xb7, offset 0x424
{value: 0x0010, lo: 0x80, hi: 0xb7},
{value: 0x0010, lo: 0xbe, hi: 0xbf},
// Block 0xb8, offset 0x426
{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 0xb9, offset 0x433
{value: 0x0010, lo: 0xa0, hi: 0xbc},
// Block 0xba, offset 0x434
{value: 0x0010, lo: 0x80, hi: 0x9c},
// Block 0xbb, offset 0x435
{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 0xbc, offset 0x439
{value: 0x0010, lo: 0x80, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xb2},
// Block 0xbd, offset 0x43b
{value: 0x0010, lo: 0x80, hi: 0x91},
// Block 0xbe, offset 0x43c
{value: 0x0010, lo: 0x80, hi: 0x88},
// Block 0xbf, offset 0x43d
{value: 0x5653, lo: 0x80, hi: 0xb2},
// Block 0xc0, offset 0x43e
{value: 0x5652, lo: 0x80, hi: 0xb2},
// Block 0xc1, offset 0x43f
{value: 0x0010, lo: 0x80, hi: 0xa3},
{value: 0x0024, lo: 0xa4, hi: 0xa7},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xc2, offset 0x442
{value: 0x0010, lo: 0x80, hi: 0x8d},
{value: 0x0014, lo: 0x8e, hi: 0x8e},
{value: 0x0010, lo: 0x8f, hi: 0x8f},
{value: 0x2013, lo: 0x90, hi: 0x9f},
{value: 0xd153, lo: 0xa0, hi: 0xa5},
{value: 0x0024, lo: 0xa9, hi: 0xad},
{value: 0x0014, lo: 0xaf, hi: 0xaf},
{value: 0x2012, lo: 0xb0, hi: 0xbf},
// Block 0xc3, offset 0x44a
{value: 0xd152, lo: 0x80, hi: 0x85},
// Block 0xc4, offset 0x44b
{value: 0x0010, lo: 0x80, hi: 0xa9},
{value: 0x0024, lo: 0xab, hi: 0xac},
{value: 0x0010, lo: 0xb0, hi: 0xb1},
// Block 0xc5, offset 0x44e
{value: 0x0010, lo: 0x82, hi: 0x84},
{value: 0x0014, lo: 0x85, hi: 0x85},
{value: 0x0010, lo: 0x86, hi: 0x87},
{value: 0x0034, lo: 0xba, hi: 0xbb},
{value: 0x0014, lo: 0xbc, hi: 0xbc},
{value: 0x0034, lo: 0xbd, hi: 0xbf},
// Block 0xc6, offset 0x454
{value: 0x0010, lo: 0x80, hi: 0x9c},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xc7, offset 0x457
{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 0xc8, offset 0x45e
{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 0xc9, offset 0x464
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0010, lo: 0xa0, hi: 0xb6},
// Block 0xca, offset 0x466
{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 0xcb, offset 0x46a
{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 0xcc, offset 0x472
{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 0xcd, offset 0x478
{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 0xce, offset 0x47c
{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 0xcf, offset 0x483
{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 0xd0, offset 0x487
{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 0xd1, offset 0x48b
{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 0xd2, offset 0x494
{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 0xd3, offset 0x49e
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0014, lo: 0x81, hi: 0x81},
// Block 0xd4, offset 0x4a0
{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 0xd5, offset 0x4a6
{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 0xd6, offset 0x4ac
{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 0xd7, offset 0x4b6
{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 0xd8, offset 0x4c0
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8b, hi: 0x8b},
{value: 0x0010, lo: 0x8e, hi: 0x8e},
{value: 0x0010, lo: 0x90, hi: 0xb5},
{value: 0x0010, lo: 0xb7, hi: 0xba},
{value: 0x0014, lo: 0xbb, hi: 0xbf},
// Block 0xd9, offset 0x4c6
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x85, hi: 0x85},
{value: 0x0010, lo: 0x87, hi: 0x8a},
{value: 0x0010, lo: 0x8c, hi: 0x8d},
{value: 0x0034, lo: 0x8e, hi: 0x8e},
{value: 0x0030, lo: 0x8f, hi: 0x8f},
{value: 0x0034, lo: 0x90, hi: 0x90},
{value: 0x0010, lo: 0x91, hi: 0x91},
{value: 0x0014, lo: 0x92, hi: 0x92},
{value: 0x0010, lo: 0x93, hi: 0x93},
{value: 0x0014, lo: 0xa1, hi: 0xa2},
// Block 0xda, offset 0x4d2
{value: 0x0010, lo: 0x80, hi: 0xb7},
{value: 0x0014, lo: 0xb8, hi: 0xbf},
// Block 0xdb, offset 0x4d4
{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 0xdc, offset 0x4dd
{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 0xdd, offset 0x4e3
{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 0xde, offset 0x4e9
{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 0xdf, offset 0x4ef
{value: 0x0034, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x98, hi: 0x9b},
{value: 0x0014, lo: 0x9c, hi: 0x9d},
// Block 0xe0, offset 0x4f2
{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 0xe1, offset 0x4f8
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x84, hi: 0x84},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0xe2, offset 0x4fb
{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 0xe3, offset 0x504
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x90, hi: 0xa3},
// Block 0xe4, offset 0x506
{value: 0x0014, lo: 0x9d, hi: 0x9d},
{value: 0x0010, lo: 0x9e, hi: 0x9e},
{value: 0x0014, lo: 0x9f, 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 0xe5, offset 0x50f
{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 0xe6, offset 0x513
{value: 0x5f53, lo: 0xa0, hi: 0xbf},
// Block 0xe7, offset 0x514
{value: 0x5f52, lo: 0x80, hi: 0x9f},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0010, lo: 0xbf, hi: 0xbf},
// Block 0xe8, offset 0x517
{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 0xe9, offset 0x521
{value: 0x0010, lo: 0x80, hi: 0x82},
{value: 0x0034, lo: 0x83, hi: 0x83},
{value: 0x0010, lo: 0x90, hi: 0x99},
// Block 0xea, offset 0x524
{value: 0x0010, lo: 0xa0, hi: 0xa7},
{value: 0x0010, lo: 0xaa, hi: 0xbf},
// Block 0xeb, offset 0x526
{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 0xec, offset 0x52d
{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 0xed, offset 0x535
{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 0xee, offset 0x53b
{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 0xef, offset 0x542
{value: 0x0010, lo: 0x80, hi: 0xb8},
// Block 0xf0, offset 0x543
{value: 0x0014, lo: 0xa0, hi: 0xa0},
{value: 0x0010, lo: 0xa1, hi: 0xa1},
{value: 0x0014, lo: 0xa2, hi: 0xa4},
{value: 0x0010, lo: 0xa5, hi: 0xa5},
{value: 0x0014, lo: 0xa6, hi: 0xa6},
{value: 0x0010, lo: 0xa7, hi: 0xa7},
// Block 0xf1, offset 0x549
{value: 0x0010, lo: 0x80, hi: 0xa0},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0xf2, offset 0x54b
{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 0xf3, offset 0x551
{value: 0x0010, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0010, lo: 0xb2, hi: 0xbf},
// Block 0xf4, offset 0x554
{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 0xf5, offset 0x55c
{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 0xf6, offset 0x563
{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 0xf7, offset 0x56d
{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},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0xf8, offset 0x576
{value: 0x0010, lo: 0x80, hi: 0x98},
{value: 0x0014, lo: 0x99, hi: 0x99},
{value: 0x0010, lo: 0x9a, hi: 0x9b},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
// Block 0xf9, offset 0x57a
{value: 0x0010, lo: 0xa0, hi: 0xb2},
{value: 0x0014, lo: 0xb3, hi: 0xb4},
{value: 0x0010, lo: 0xb5, hi: 0xb6},
// Block 0xfa, offset 0x57d
{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 0xfb, offset 0x582
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0030, lo: 0x81, hi: 0x81},
{value: 0x0034, lo: 0x82, hi: 0x82},
{value: 0x0010, lo: 0x90, hi: 0x99},
{value: 0x0014, lo: 0x9a, hi: 0x9a},
// Block 0xfc, offset 0x587
{value: 0x0010, lo: 0xb0, hi: 0xb0},
// Block 0xfd, offset 0x588
{value: 0x0010, lo: 0x80, hi: 0xae},
// Block 0xfe, offset 0x589
{value: 0x0010, lo: 0x80, hi: 0x83},
// Block 0xff, offset 0x58a
{value: 0x0010, lo: 0x80, hi: 0xb0},
// Block 0x100, offset 0x58b
{value: 0x0010, lo: 0x80, hi: 0xaf},
{value: 0x0014, lo: 0xb0, hi: 0xbf},
// Block 0x101, offset 0x58d
{value: 0x0014, lo: 0x80, hi: 0x80},
{value: 0x0010, lo: 0x81, hi: 0x86},
{value: 0x0014, lo: 0x87, hi: 0x95},
{value: 0x0010, lo: 0xa0, hi: 0xbf},
// Block 0x102, offset 0x591
{value: 0x0010, lo: 0x80, hi: 0x86},
// Block 0x103, offset 0x592
{value: 0x0010, lo: 0x80, hi: 0x9d},
{value: 0x0014, lo: 0x9e, hi: 0xa9},
{value: 0x0010, lo: 0xaa, hi: 0xac},
{value: 0x0014, lo: 0xad, hi: 0xae},
{value: 0x0034, lo: 0xaf, hi: 0xaf},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x104, offset 0x598
{value: 0x0010, lo: 0x80, hi: 0x9e},
{value: 0x0010, lo: 0xa0, hi: 0xa9},
{value: 0x0010, lo: 0xb0, hi: 0xbf},
// Block 0x105, offset 0x59b
{value: 0x0010, lo: 0x80, hi: 0xbe},
// Block 0x106, offset 0x59c
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x90, hi: 0xad},
{value: 0x0034, lo: 0xb0, hi: 0xb4},
// Block 0x107, offset 0x59f
{value: 0x0010, lo: 0x80, hi: 0xaf},
{value: 0x0024, lo: 0xb0, hi: 0xb6},
// Block 0x108, offset 0x5a1
{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 0x109, offset 0x5a5
{value: 0x0010, lo: 0x80, hi: 0x8f},
// Block 0x10a, offset 0x5a6
{value: 0x0014, lo: 0x80, hi: 0x82},
{value: 0x0010, lo: 0x83, hi: 0xaa},
{value: 0x0014, lo: 0xab, hi: 0xac},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x10b, offset 0x5aa
{value: 0x2013, lo: 0x80, hi: 0x9f},
{value: 0x2012, lo: 0xa0, hi: 0xbf},
// Block 0x10c, offset 0x5ac
{value: 0x0010, lo: 0x80, hi: 0x8a},
{value: 0x0014, lo: 0x8f, hi: 0x8f},
{value: 0x0010, lo: 0x90, hi: 0xbf},
// Block 0x10d, offset 0x5af
{value: 0x0010, lo: 0x80, hi: 0x87},
{value: 0x0014, lo: 0x8f, hi: 0x9f},
// Block 0x10e, offset 0x5b1
{value: 0x0014, lo: 0xa0, hi: 0xa1},
{value: 0x0014, lo: 0xa3, hi: 0xa4},
{value: 0x0030, lo: 0xb0, hi: 0xb1},
{value: 0x0004, lo: 0xb2, hi: 0xb3},
// Block 0x10f, offset 0x5b5
{value: 0x0004, lo: 0xb0, hi: 0xb3},
{value: 0x0004, lo: 0xb5, hi: 0xbb},
{value: 0x0004, lo: 0xbd, hi: 0xbe},
// Block 0x110, offset 0x5b8
{value: 0x0010, lo: 0x80, hi: 0xaa},
{value: 0x0010, lo: 0xb0, hi: 0xbc},
// Block 0x111, offset 0x5ba
{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 0x112, offset 0x5bf
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x113, offset 0x5c0
{value: 0x0014, lo: 0x80, hi: 0xad},
{value: 0x0014, lo: 0xb0, hi: 0xbf},
// Block 0x114, offset 0x5c2
{value: 0x0014, lo: 0x80, hi: 0x86},
// Block 0x115, offset 0x5c3
{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 0x116, offset 0x5c8
{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 0x117, offset 0x5cc
{value: 0x0024, lo: 0x82, hi: 0x84},
// Block 0x118, offset 0x5cd
{value: 0x0013, lo: 0x80, hi: 0x99},
{value: 0x0012, lo: 0x9a, hi: 0xb3},
{value: 0x0013, lo: 0xb4, hi: 0xbf},
// Block 0x119, offset 0x5d0
{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 0x11a, offset 0x5d4
{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 0x11b, offset 0x5df
{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 0x11c, offset 0x5e3
{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 0x11d, offset 0x5eb
{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 0x11e, offset 0x5f0
{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 0x11f, offset 0x5f4
{value: 0x0012, lo: 0x80, hi: 0x93},
{value: 0x0013, lo: 0x94, hi: 0xad},
{value: 0x0012, lo: 0xae, hi: 0xbf},
// Block 0x120, offset 0x5f7
{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 0x121, offset 0x5fb
{value: 0x0013, lo: 0x80, hi: 0x95},
{value: 0x0012, lo: 0x96, hi: 0xaf},
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0x122, offset 0x5fe
{value: 0x0013, lo: 0x80, hi: 0x89},
{value: 0x0012, lo: 0x8a, hi: 0xa5},
{value: 0x0013, lo: 0xa8, hi: 0xbf},
// Block 0x123, offset 0x601
{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 0x124, offset 0x606
{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 0x125, offset 0x60a
{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 0x126, offset 0x60e
{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 0x127, offset 0x612
{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 0x128, offset 0x616
{value: 0x0014, lo: 0x80, hi: 0xb6},
{value: 0x0014, lo: 0xbb, hi: 0xbf},
// Block 0x129, offset 0x618
{value: 0x0014, lo: 0x80, hi: 0xac},
{value: 0x0014, lo: 0xb5, hi: 0xb5},
// Block 0x12a, offset 0x61a
{value: 0x0014, lo: 0x84, hi: 0x84},
{value: 0x0014, lo: 0x9b, hi: 0x9f},
{value: 0x0014, lo: 0xa1, hi: 0xaf},
// Block 0x12b, offset 0x61d
{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 0x12c, offset 0x621
{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 0x12d, offset 0x627
{value: 0x0015, lo: 0x80, hi: 0xad},
// Block 0x12e, offset 0x628
{value: 0x0024, lo: 0x8f, hi: 0x8f},
// Block 0x12f, offset 0x629
{value: 0x0010, lo: 0x80, hi: 0xac},
{value: 0x0024, lo: 0xb0, hi: 0xb6},
{value: 0x0014, lo: 0xb7, hi: 0xbd},
// Block 0x130, offset 0x62c
{value: 0x0010, lo: 0x80, hi: 0x89},
{value: 0x0010, lo: 0x8e, hi: 0x8e},
// Block 0x131, offset 0x62e
{value: 0x0010, lo: 0x90, hi: 0xad},
{value: 0x0024, lo: 0xae, hi: 0xae},
// Block 0x132, offset 0x630
{value: 0x0010, lo: 0x80, hi: 0xab},
{value: 0x0024, lo: 0xac, hi: 0xaf},
{value: 0x0010, lo: 0xb0, hi: 0xb9},
// Block 0x133, offset 0x633
{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 0x134, offset 0x638
{value: 0x0010, lo: 0x90, hi: 0xad},
{value: 0x0024, lo: 0xae, hi: 0xae},
{value: 0x0034, lo: 0xaf, hi: 0xaf},
{value: 0x0010, lo: 0xb0, hi: 0xba},
// Block 0x135, offset 0x63c
{value: 0x0010, lo: 0x80, hi: 0x9e},
{value: 0x0010, lo: 0xa0, hi: 0xa2},
{value: 0x0024, lo: 0xa3, hi: 0xa3},
{value: 0x0010, lo: 0xa4, hi: 0xa5},
{value: 0x0024, lo: 0xa6, hi: 0xa6},
{value: 0x0010, lo: 0xa7, hi: 0xad},
{value: 0x0024, lo: 0xae, hi: 0xaf},
{value: 0x0010, lo: 0xb0, hi: 0xb4},
{value: 0x0024, lo: 0xb5, hi: 0xb5},
{value: 0x0010, lo: 0xbe, hi: 0xbe},
{value: 0x0014, lo: 0xbf, hi: 0xbf},
// Block 0x136, offset 0x647
{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 0x137, offset 0x64b
{value: 0x0010, lo: 0x80, hi: 0x84},
{value: 0x0034, lo: 0x90, hi: 0x96},
// Block 0x138, offset 0x64d
{value: 0xe952, lo: 0x80, hi: 0x81},
{value: 0xec52, 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 0x139, offset 0x653
{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 0x13a, offset 0x65c
{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 0x13b, offset 0x661
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0x13c, offset 0x662
{value: 0x0013, lo: 0x80, hi: 0x89},
{value: 0x0013, lo: 0x90, hi: 0xa9},
{value: 0x0013, lo: 0xb0, hi: 0xbf},
// Block 0x13d, offset 0x665
{value: 0x0013, lo: 0x80, hi: 0x89},
// Block 0x13e, offset 0x666
{value: 0x0014, lo: 0xbb, hi: 0xbf},
// Block 0x13f, offset 0x667
{value: 0x0014, lo: 0x81, hi: 0x81},
{value: 0x0014, lo: 0xa0, hi: 0xbf},
// Block 0x140, offset 0x669
{value: 0x0014, lo: 0x80, hi: 0xbf},
// Block 0x141, offset 0x66a
{value: 0x0014, lo: 0x80, hi: 0xaf},
}
// Total table size 16747 bytes (16KiB); checksum: D520269F
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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 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 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 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.11
// 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 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[0].Descriptor()
}
func (EndiannessEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[0]
}
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{0}
}
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[1].Descriptor()
}
func (BOMPolicyEnum) Type() protoreflect.EnumType {
return &file_ngolofuzz_proto_enumTypes[1]
}
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{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*1\n" +
"\x0eEndiannessEnum\x12\r\n" +
"\tBigEndian\x10\x00\x12\x10\n" +
"\fLittleEndian\x10\x01*9\n" +
"\rBOMPolicyEnum\x12\r\n" +
"\tIgnoreBOM\x10\x00\x12\n" +
"\n" +
"\x06UseBOM\x10\x01\x12\r\n" +
"\tExpectBOM\x10\x02B$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{
(EndiannessEnum)(0), // 0: ngolofuzz.EndiannessEnum
(BOMPolicyEnum)(0), // 1: ngolofuzz.BOMPolicyEnum
(*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{
0, // 0: ngolofuzz.UTF16Args.e:type_name -> ngolofuzz.EndiannessEnum
1, // 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.11
// 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.11
// 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.11
// 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.11
// 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.11
// 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 DirectionResults []*bidi.Direction
DirectionResultsIndex := 0
var OrderingResults []*bidi.Ordering
OrderingResultsIndex := 0
var RunResults []*bidi.Run
RunResultsIndex := 0
var PropertiesResults []*bidi.Properties
PropertiesResultsIndex := 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) {
DirectionNb := 0
DirectionResultsIndex := 0
OrderingNb := 0
OrderingResultsIndex := 0
RunNb := 0
RunResultsIndex := 0
PropertiesNb := 0
PropertiesResultsIndex := 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.11
// 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 DraftResults []*cldr.Draft
DraftResultsIndex := 0
var CommonResults []*cldr.Common
CommonResultsIndex := 0
var SliceResults []*cldr.Slice
SliceResultsIndex := 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
DraftNb := 0
DraftResultsIndex := 0
CommonNb := 0
CommonResultsIndex := 0
SliceNb := 0
SliceResultsIndex := 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.11
// 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.11
// 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.11
// 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 PropertiesResults []*width.Properties
PropertiesResultsIndex := 0
var KindResults []*width.Kind
KindResultsIndex := 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) {
PropertiesNb := 0
PropertiesResultsIndex := 0
KindNb := 0
KindResultsIndex := 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.11
// 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 }{
{"15.0.0", "!go1.27"},
{"17.0.0", "go1.27"},
}
// 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: catmsg.FirstOf(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"
)
// A Message holds a collection of translations for the same phrase that may
// vary based on the values of substitution arguments.
type Message = catmsg.Message
// 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}, catmsg.FirstOf(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
}
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.27
package precis
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "17.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: 29888 bytes (29.19 KiB). Checksum: 95c6e1fb42cd4aca.
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: 387 blocks, 24768 entries, 24768 bytes
// The third block is the zero block.
var derivedPropertiesValues = [24768]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, 0x78f: 0x00c2, 0x790: 0x0040, 0x791: 0x0040,
0x797: 0x00c3,
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, 0xb5c: 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,
0xbdc: 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, 0x16cf: 0x00c3, 0x16d0: 0x00c3, 0x16d1: 0x00c3,
0x16d2: 0x00c3, 0x16d3: 0x00c3, 0x16d4: 0x00c3, 0x16d5: 0x00c3, 0x16d6: 0x00c3, 0x16d7: 0x00c3,
0x16d8: 0x00c3, 0x16d9: 0x00c3, 0x16da: 0x00c3, 0x16db: 0x00c3, 0x16dc: 0x00c3, 0x16dd: 0x00c3,
0x16e0: 0x00c3, 0x16e1: 0x00c3, 0x16e2: 0x00c3, 0x16e3: 0x00c3,
0x16e4: 0x00c3, 0x16e5: 0x00c3, 0x16e6: 0x00c3, 0x16e7: 0x00c3, 0x16e8: 0x00c3, 0x16e9: 0x00c3,
0x16ea: 0x00c3, 0x16eb: 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, 0x174e: 0x0080, 0x174f: 0x0080, 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, 0x177f: 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, 0x1889: 0x00c0, 0x188a: 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, 0x1bc1: 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, 0x1d27: 0x0080, 0x1d28: 0x0080, 0x1d29: 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: 0x00c0, 0x1dc1: 0x00c0, 0x1dc2: 0x00c0, 0x1dc3: 0x00c0, 0x1dc4: 0x00c0, 0x1dc5: 0x00c0,
0x1dc6: 0x00c0, 0x1dc7: 0x00c0, 0x1dc8: 0x00c0, 0x1dc9: 0x00c0, 0x1dca: 0x00c0, 0x1dcb: 0x00c0,
0x1dcc: 0x00c0, 0x1dcd: 0x00c0, 0x1dce: 0x00c0, 0x1dcf: 0x00c0, 0x1dd0: 0x00c0, 0x1dd1: 0x00c0,
0x1dd2: 0x00c0, 0x1dd3: 0x00c0, 0x1dd4: 0x00c0, 0x1dd5: 0x00c0, 0x1dd6: 0x00c0, 0x1dd7: 0x00c0,
0x1dd8: 0x00c0, 0x1dd9: 0x00c0, 0x1dda: 0x00c0, 0x1ddb: 0x00c0, 0x1ddc: 0x00c0, 0x1ddd: 0x00c0,
0x1dde: 0x00c0, 0x1ddf: 0x00c0, 0x1de0: 0x00c0, 0x1de1: 0x00c0, 0x1de2: 0x00c0, 0x1de3: 0x00c0,
0x1de4: 0x00c0, 0x1de5: 0x00c0, 0x1de6: 0x00c0, 0x1de7: 0x00c0, 0x1de8: 0x00c0, 0x1de9: 0x00c0,
0x1dea: 0x00c0, 0x1deb: 0x00c0, 0x1dec: 0x00c0, 0x1ded: 0x00c0, 0x1dee: 0x00c0, 0x1def: 0x00c0,
0x1df0: 0x00c0, 0x1df1: 0x00c0, 0x1df2: 0x00c0, 0x1df3: 0x00c0, 0x1df4: 0x00c0, 0x1df5: 0x00c0,
0x1df6: 0x00c0, 0x1df7: 0x00c0, 0x1df8: 0x00c0, 0x1df9: 0x00c0, 0x1dfa: 0x00c0, 0x1dfb: 0x00c0,
0x1dfc: 0x0080, 0x1dfd: 0x0080, 0x1dfe: 0x00c0, 0x1dff: 0x00c0,
// 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: 0x0080, 0x1e26: 0x0080, 0x1e27: 0x0080, 0x1e28: 0x0080, 0x1e29: 0x0080,
0x1e2a: 0x0080, 0x1e2b: 0x00c0, 0x1e2c: 0x00c0, 0x1e2d: 0x00c0, 0x1e2e: 0x00c0, 0x1e2f: 0x00c3,
0x1e30: 0x00c3, 0x1e31: 0x00c3, 0x1e32: 0x00c0, 0x1e33: 0x00c0,
0x1e39: 0x0080, 0x1e3a: 0x0080, 0x1e3b: 0x0080,
0x1e3c: 0x0080, 0x1e3d: 0x0080, 0x1e3e: 0x0080, 0x1e3f: 0x0080,
// 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: 0x00c0, 0x1e67: 0x00c0,
0x1e6d: 0x00c0,
0x1e70: 0x00c0, 0x1e71: 0x00c0, 0x1e72: 0x00c0, 0x1e73: 0x00c0, 0x1e74: 0x00c0, 0x1e75: 0x00c0,
0x1e76: 0x00c0, 0x1e77: 0x00c0, 0x1e78: 0x00c0, 0x1e79: 0x00c0, 0x1e7a: 0x00c0, 0x1e7b: 0x00c0,
0x1e7c: 0x00c0, 0x1e7d: 0x00c0, 0x1e7e: 0x00c0, 0x1e7f: 0x00c0,
// 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, 0x1ea6: 0x00c0, 0x1ea7: 0x00c0,
0x1eaf: 0x0080,
0x1eb0: 0x0080,
0x1ebf: 0x00c6,
// 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,
0x1ee0: 0x00c0, 0x1ee1: 0x00c0, 0x1ee2: 0x00c0, 0x1ee3: 0x00c0,
0x1ee4: 0x00c0, 0x1ee5: 0x00c0, 0x1ee6: 0x00c0, 0x1ee8: 0x00c0, 0x1ee9: 0x00c0,
0x1eea: 0x00c0, 0x1eeb: 0x00c0, 0x1eec: 0x00c0, 0x1eed: 0x00c0, 0x1eee: 0x00c0,
0x1ef0: 0x00c0, 0x1ef1: 0x00c0, 0x1ef2: 0x00c0, 0x1ef3: 0x00c0, 0x1ef4: 0x00c0, 0x1ef5: 0x00c0,
0x1ef6: 0x00c0, 0x1ef8: 0x00c0, 0x1ef9: 0x00c0, 0x1efa: 0x00c0, 0x1efb: 0x00c0,
0x1efc: 0x00c0, 0x1efd: 0x00c0, 0x1efe: 0x00c0,
// Block 0x7c, offset 0x1f00
0x1f00: 0x00c0, 0x1f01: 0x00c0, 0x1f02: 0x00c0, 0x1f03: 0x00c0, 0x1f04: 0x00c0, 0x1f05: 0x00c0,
0x1f06: 0x00c0, 0x1f08: 0x00c0, 0x1f09: 0x00c0, 0x1f0a: 0x00c0, 0x1f0b: 0x00c0,
0x1f0c: 0x00c0, 0x1f0d: 0x00c0, 0x1f0e: 0x00c0, 0x1f10: 0x00c0, 0x1f11: 0x00c0,
0x1f12: 0x00c0, 0x1f13: 0x00c0, 0x1f14: 0x00c0, 0x1f15: 0x00c0, 0x1f16: 0x00c0,
0x1f18: 0x00c0, 0x1f19: 0x00c0, 0x1f1a: 0x00c0, 0x1f1b: 0x00c0, 0x1f1c: 0x00c0, 0x1f1d: 0x00c0,
0x1f1e: 0x00c0, 0x1f20: 0x00c3, 0x1f21: 0x00c3, 0x1f22: 0x00c3, 0x1f23: 0x00c3,
0x1f24: 0x00c3, 0x1f25: 0x00c3, 0x1f26: 0x00c3, 0x1f27: 0x00c3, 0x1f28: 0x00c3, 0x1f29: 0x00c3,
0x1f2a: 0x00c3, 0x1f2b: 0x00c3, 0x1f2c: 0x00c3, 0x1f2d: 0x00c3, 0x1f2e: 0x00c3, 0x1f2f: 0x00c3,
0x1f30: 0x00c3, 0x1f31: 0x00c3, 0x1f32: 0x00c3, 0x1f33: 0x00c3, 0x1f34: 0x00c3, 0x1f35: 0x00c3,
0x1f36: 0x00c3, 0x1f37: 0x00c3, 0x1f38: 0x00c3, 0x1f39: 0x00c3, 0x1f3a: 0x00c3, 0x1f3b: 0x00c3,
0x1f3c: 0x00c3, 0x1f3d: 0x00c3, 0x1f3e: 0x00c3, 0x1f3f: 0x00c3,
// Block 0x7d, offset 0x1f40
0x1f40: 0x0080, 0x1f41: 0x0080, 0x1f42: 0x0080, 0x1f43: 0x0080, 0x1f44: 0x0080, 0x1f45: 0x0080,
0x1f46: 0x0080, 0x1f47: 0x0080, 0x1f48: 0x0080, 0x1f49: 0x0080, 0x1f4a: 0x0080, 0x1f4b: 0x0080,
0x1f4c: 0x0080, 0x1f4d: 0x0080, 0x1f4e: 0x0080, 0x1f4f: 0x0080, 0x1f50: 0x0080, 0x1f51: 0x0080,
0x1f52: 0x0080, 0x1f53: 0x0080, 0x1f54: 0x0080, 0x1f55: 0x0080, 0x1f56: 0x0080, 0x1f57: 0x0080,
0x1f58: 0x0080, 0x1f59: 0x0080, 0x1f5a: 0x0080, 0x1f5b: 0x0080, 0x1f5c: 0x0080, 0x1f5d: 0x0080,
0x1f5e: 0x0080, 0x1f5f: 0x0080, 0x1f60: 0x0080, 0x1f61: 0x0080, 0x1f62: 0x0080, 0x1f63: 0x0080,
0x1f64: 0x0080, 0x1f65: 0x0080, 0x1f66: 0x0080, 0x1f67: 0x0080, 0x1f68: 0x0080, 0x1f69: 0x0080,
0x1f6a: 0x0080, 0x1f6b: 0x0080, 0x1f6c: 0x0080, 0x1f6d: 0x0080, 0x1f6e: 0x0080, 0x1f6f: 0x00c0,
0x1f70: 0x0080, 0x1f71: 0x0080, 0x1f72: 0x0080, 0x1f73: 0x0080, 0x1f74: 0x0080, 0x1f75: 0x0080,
0x1f76: 0x0080, 0x1f77: 0x0080, 0x1f78: 0x0080, 0x1f79: 0x0080, 0x1f7a: 0x0080, 0x1f7b: 0x0080,
0x1f7c: 0x0080, 0x1f7d: 0x0080, 0x1f7e: 0x0080, 0x1f7f: 0x0080,
// 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,
// Block 0x7f, offset 0x1fc0
0x1fc0: 0x008c, 0x1fc1: 0x008c, 0x1fc2: 0x008c, 0x1fc3: 0x008c, 0x1fc4: 0x008c, 0x1fc5: 0x008c,
0x1fc6: 0x008c, 0x1fc7: 0x008c, 0x1fc8: 0x008c, 0x1fc9: 0x008c, 0x1fca: 0x008c, 0x1fcb: 0x008c,
0x1fcc: 0x008c, 0x1fcd: 0x008c, 0x1fce: 0x008c, 0x1fcf: 0x008c, 0x1fd0: 0x008c, 0x1fd1: 0x008c,
0x1fd2: 0x008c, 0x1fd3: 0x008c, 0x1fd4: 0x008c, 0x1fd5: 0x008c, 0x1fd6: 0x008c, 0x1fd7: 0x008c,
0x1fd8: 0x008c, 0x1fd9: 0x008c, 0x1fdb: 0x008c, 0x1fdc: 0x008c, 0x1fdd: 0x008c,
0x1fde: 0x008c, 0x1fdf: 0x008c, 0x1fe0: 0x008c, 0x1fe1: 0x008c, 0x1fe2: 0x008c, 0x1fe3: 0x008c,
0x1fe4: 0x008c, 0x1fe5: 0x008c, 0x1fe6: 0x008c, 0x1fe7: 0x008c, 0x1fe8: 0x008c, 0x1fe9: 0x008c,
0x1fea: 0x008c, 0x1feb: 0x008c, 0x1fec: 0x008c, 0x1fed: 0x008c, 0x1fee: 0x008c, 0x1fef: 0x008c,
0x1ff0: 0x008c, 0x1ff1: 0x008c, 0x1ff2: 0x008c, 0x1ff3: 0x008c, 0x1ff4: 0x008c, 0x1ff5: 0x008c,
0x1ff6: 0x008c, 0x1ff7: 0x008c, 0x1ff8: 0x008c, 0x1ff9: 0x008c, 0x1ffa: 0x008c, 0x1ffb: 0x008c,
0x1ffc: 0x008c, 0x1ffd: 0x008c, 0x1ffe: 0x008c, 0x1fff: 0x008c,
// 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, 0x201a: 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,
// 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, 0x2074: 0x008c, 0x2075: 0x008c,
0x2076: 0x008c, 0x2077: 0x008c, 0x2078: 0x008c, 0x2079: 0x008c, 0x207a: 0x008c, 0x207b: 0x008c,
0x207c: 0x008c, 0x207d: 0x008c, 0x207e: 0x008c, 0x207f: 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,
0x20b0: 0x0080, 0x20b1: 0x0080, 0x20b2: 0x0080, 0x20b3: 0x0080, 0x20b4: 0x0080, 0x20b5: 0x0080,
0x20b6: 0x0080, 0x20b7: 0x0080, 0x20b8: 0x0080, 0x20b9: 0x0080, 0x20ba: 0x0080, 0x20bb: 0x0080,
0x20bc: 0x0080, 0x20bd: 0x0080, 0x20be: 0x0080, 0x20bf: 0x0080,
// Block 0x83, offset 0x20c0
0x20c0: 0x0080, 0x20c1: 0x0080, 0x20c2: 0x0080, 0x20c3: 0x0080, 0x20c4: 0x0080, 0x20c5: 0x00cc,
0x20c6: 0x00c0, 0x20c7: 0x00cc, 0x20c8: 0x0080, 0x20c9: 0x0080, 0x20ca: 0x0080, 0x20cb: 0x0080,
0x20cc: 0x0080, 0x20cd: 0x0080, 0x20ce: 0x0080, 0x20cf: 0x0080, 0x20d0: 0x0080, 0x20d1: 0x0080,
0x20d2: 0x0080, 0x20d3: 0x0080, 0x20d4: 0x0080, 0x20d5: 0x0080, 0x20d6: 0x0080, 0x20d7: 0x0080,
0x20d8: 0x0080, 0x20d9: 0x0080, 0x20da: 0x0080, 0x20db: 0x0080, 0x20dc: 0x0080, 0x20dd: 0x0080,
0x20de: 0x0080, 0x20df: 0x0080, 0x20e0: 0x0080, 0x20e1: 0x008c, 0x20e2: 0x008c, 0x20e3: 0x008c,
0x20e4: 0x008c, 0x20e5: 0x008c, 0x20e6: 0x008c, 0x20e7: 0x008c, 0x20e8: 0x008c, 0x20e9: 0x008c,
0x20ea: 0x00c3, 0x20eb: 0x00c3, 0x20ec: 0x00c3, 0x20ed: 0x00c3, 0x20ee: 0x0040, 0x20ef: 0x0040,
0x20f0: 0x0080, 0x20f1: 0x0040, 0x20f2: 0x0040, 0x20f3: 0x0040, 0x20f4: 0x0040, 0x20f5: 0x0040,
0x20f6: 0x0080, 0x20f7: 0x0080, 0x20f8: 0x008c, 0x20f9: 0x008c, 0x20fa: 0x008c, 0x20fb: 0x0040,
0x20fc: 0x00c0, 0x20fd: 0x0080, 0x20fe: 0x0080, 0x20ff: 0x0080,
// Block 0x84, offset 0x2100
0x2101: 0x00cc, 0x2102: 0x00cc, 0x2103: 0x00cc, 0x2104: 0x00cc, 0x2105: 0x00cc,
0x2106: 0x00cc, 0x2107: 0x00cc, 0x2108: 0x00cc, 0x2109: 0x00cc, 0x210a: 0x00cc, 0x210b: 0x00cc,
0x210c: 0x00cc, 0x210d: 0x00cc, 0x210e: 0x00cc, 0x210f: 0x00cc, 0x2110: 0x00cc, 0x2111: 0x00cc,
0x2112: 0x00cc, 0x2113: 0x00cc, 0x2114: 0x00cc, 0x2115: 0x00cc, 0x2116: 0x00cc, 0x2117: 0x00cc,
0x2118: 0x00cc, 0x2119: 0x00cc, 0x211a: 0x00cc, 0x211b: 0x00cc, 0x211c: 0x00cc, 0x211d: 0x00cc,
0x211e: 0x00cc, 0x211f: 0x00cc, 0x2120: 0x00cc, 0x2121: 0x00cc, 0x2122: 0x00cc, 0x2123: 0x00cc,
0x2124: 0x00cc, 0x2125: 0x00cc, 0x2126: 0x00cc, 0x2127: 0x00cc, 0x2128: 0x00cc, 0x2129: 0x00cc,
0x212a: 0x00cc, 0x212b: 0x00cc, 0x212c: 0x00cc, 0x212d: 0x00cc, 0x212e: 0x00cc, 0x212f: 0x00cc,
0x2130: 0x00cc, 0x2131: 0x00cc, 0x2132: 0x00cc, 0x2133: 0x00cc, 0x2134: 0x00cc, 0x2135: 0x00cc,
0x2136: 0x00cc, 0x2137: 0x00cc, 0x2138: 0x00cc, 0x2139: 0x00cc, 0x213a: 0x00cc, 0x213b: 0x00cc,
0x213c: 0x00cc, 0x213d: 0x00cc, 0x213e: 0x00cc, 0x213f: 0x00cc,
// Block 0x85, offset 0x2140
0x2140: 0x00cc, 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,
0x2159: 0x00c3, 0x215a: 0x00c3, 0x215b: 0x0080, 0x215c: 0x0080, 0x215d: 0x00cc,
0x215e: 0x00cc, 0x215f: 0x008c, 0x2160: 0x0080, 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, 0x2197: 0x00cc,
0x2198: 0x00cc, 0x2199: 0x00cc, 0x219a: 0x00cc, 0x219b: 0x00cc, 0x219c: 0x00cc, 0x219d: 0x00cc,
0x219e: 0x00cc, 0x219f: 0x00cc, 0x21a0: 0x00cc, 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: 0x00d2,
0x21bc: 0x00c0, 0x21bd: 0x00cc, 0x21be: 0x00cc, 0x21bf: 0x008c,
// Block 0x87, offset 0x21c0
0x21c5: 0x00c0,
0x21c6: 0x00c0, 0x21c7: 0x00c0, 0x21c8: 0x00c0, 0x21c9: 0x00c0, 0x21ca: 0x00c0, 0x21cb: 0x00c0,
0x21cc: 0x00c0, 0x21cd: 0x00c0, 0x21ce: 0x00c0, 0x21cf: 0x00c0, 0x21d0: 0x00c0, 0x21d1: 0x00c0,
0x21d2: 0x00c0, 0x21d3: 0x00c0, 0x21d4: 0x00c0, 0x21d5: 0x00c0, 0x21d6: 0x00c0, 0x21d7: 0x00c0,
0x21d8: 0x00c0, 0x21d9: 0x00c0, 0x21da: 0x00c0, 0x21db: 0x00c0, 0x21dc: 0x00c0, 0x21dd: 0x00c0,
0x21de: 0x00c0, 0x21df: 0x00c0, 0x21e0: 0x00c0, 0x21e1: 0x00c0, 0x21e2: 0x00c0, 0x21e3: 0x00c0,
0x21e4: 0x00c0, 0x21e5: 0x00c0, 0x21e6: 0x00c0, 0x21e7: 0x00c0, 0x21e8: 0x00c0, 0x21e9: 0x00c0,
0x21ea: 0x00c0, 0x21eb: 0x00c0, 0x21ec: 0x00c0, 0x21ed: 0x00c0, 0x21ee: 0x00c0, 0x21ef: 0x00c0,
0x21f1: 0x0080, 0x21f2: 0x0080, 0x21f3: 0x0080, 0x21f4: 0x0080, 0x21f5: 0x0080,
0x21f6: 0x0080, 0x21f7: 0x0080, 0x21f8: 0x0080, 0x21f9: 0x0080, 0x21fa: 0x0080, 0x21fb: 0x0080,
0x21fc: 0x0080, 0x21fd: 0x0080, 0x21fe: 0x0080, 0x21ff: 0x0080,
// Block 0x88, offset 0x2200
0x2200: 0x0080, 0x2201: 0x0080, 0x2202: 0x0080, 0x2203: 0x0080, 0x2204: 0x0080, 0x2205: 0x0080,
0x2206: 0x0080, 0x2207: 0x0080, 0x2208: 0x0080, 0x2209: 0x0080, 0x220a: 0x0080, 0x220b: 0x0080,
0x220c: 0x0080, 0x220d: 0x0080, 0x220e: 0x0080, 0x220f: 0x0080, 0x2210: 0x0080, 0x2211: 0x0080,
0x2212: 0x0080, 0x2213: 0x0080, 0x2214: 0x0080, 0x2215: 0x0080, 0x2216: 0x0080, 0x2217: 0x0080,
0x2218: 0x0080, 0x2219: 0x0080, 0x221a: 0x0080, 0x221b: 0x0080, 0x221c: 0x0080, 0x221d: 0x0080,
0x221e: 0x0080, 0x221f: 0x0080, 0x2220: 0x0080, 0x2221: 0x0080, 0x2222: 0x0080, 0x2223: 0x0080,
0x2224: 0x0040, 0x2225: 0x0080, 0x2226: 0x0080, 0x2227: 0x0080, 0x2228: 0x0080, 0x2229: 0x0080,
0x222a: 0x0080, 0x222b: 0x0080, 0x222c: 0x0080, 0x222d: 0x0080, 0x222e: 0x0080, 0x222f: 0x0080,
0x2230: 0x0080, 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, 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: 0x00c0, 0x2261: 0x00c0, 0x2262: 0x00c0, 0x2263: 0x00c0,
0x2264: 0x00c0, 0x2265: 0x00c0, 0x2266: 0x00c0, 0x2267: 0x00c0, 0x2268: 0x00c0, 0x2269: 0x00c0,
0x226a: 0x00c0, 0x226b: 0x00c0, 0x226c: 0x00c0, 0x226d: 0x00c0, 0x226e: 0x00c0, 0x226f: 0x00c0,
0x2270: 0x00c0, 0x2271: 0x00c0, 0x2272: 0x00c0, 0x2273: 0x00c0, 0x2274: 0x00c0, 0x2275: 0x00c0,
0x2276: 0x00c0, 0x2277: 0x00c0, 0x2278: 0x00c0, 0x2279: 0x00c0, 0x227a: 0x00c0, 0x227b: 0x00c0,
0x227c: 0x00c0, 0x227d: 0x00c0, 0x227e: 0x00c0, 0x227f: 0x00c0,
// 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, 0x228f: 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: 0x0080, 0x22a1: 0x0080, 0x22a2: 0x0080, 0x22a3: 0x0080,
0x22a4: 0x0080, 0x22a5: 0x0080,
0x22af: 0x0080,
0x22b0: 0x00cc, 0x22b1: 0x00cc, 0x22b2: 0x00cc, 0x22b3: 0x00cc, 0x22b4: 0x00cc, 0x22b5: 0x00cc,
0x22b6: 0x00cc, 0x22b7: 0x00cc, 0x22b8: 0x00cc, 0x22b9: 0x00cc, 0x22ba: 0x00cc, 0x22bb: 0x00cc,
0x22bc: 0x00cc, 0x22bd: 0x00cc, 0x22be: 0x00cc, 0x22bf: 0x00cc,
// 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, 0x22e0: 0x0080, 0x22e1: 0x0080, 0x22e2: 0x0080, 0x22e3: 0x0080,
0x22e4: 0x0080, 0x22e5: 0x0080, 0x22e6: 0x0080, 0x22e7: 0x0080, 0x22e8: 0x0080, 0x22e9: 0x0080,
0x22ea: 0x0080, 0x22eb: 0x0080, 0x22ec: 0x0080, 0x22ed: 0x0080, 0x22ee: 0x0080, 0x22ef: 0x0080,
0x22f0: 0x0080, 0x22f1: 0x0080, 0x22f2: 0x0080, 0x22f3: 0x0080, 0x22f4: 0x0080, 0x22f5: 0x0080,
0x22f6: 0x0080, 0x22f7: 0x0080, 0x22f8: 0x0080, 0x22f9: 0x0080, 0x22fa: 0x0080, 0x22fb: 0x0080,
0x22fc: 0x0080, 0x22fd: 0x0080, 0x22fe: 0x0080, 0x22ff: 0x0080,
// 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: 0x008c, 0x2311: 0x008c,
0x2312: 0x008c, 0x2313: 0x008c, 0x2314: 0x008c, 0x2315: 0x008c, 0x2316: 0x008c, 0x2317: 0x008c,
0x2318: 0x008c, 0x2319: 0x008c, 0x231a: 0x008c, 0x231b: 0x008c, 0x231c: 0x008c, 0x231d: 0x008c,
0x231e: 0x008c, 0x231f: 0x008c, 0x2320: 0x008c, 0x2321: 0x008c, 0x2322: 0x008c, 0x2323: 0x008c,
0x2324: 0x008c, 0x2325: 0x008c, 0x2326: 0x008c, 0x2327: 0x008c, 0x2328: 0x008c, 0x2329: 0x008c,
0x232a: 0x008c, 0x232b: 0x008c, 0x232c: 0x008c, 0x232d: 0x008c, 0x232e: 0x008c, 0x232f: 0x008c,
0x2330: 0x008c, 0x2331: 0x008c, 0x2332: 0x008c, 0x2333: 0x008c, 0x2334: 0x008c, 0x2335: 0x008c,
0x2336: 0x008c, 0x2337: 0x008c, 0x2338: 0x008c, 0x2339: 0x008c, 0x233a: 0x008c, 0x233b: 0x008c,
0x233c: 0x008c, 0x233d: 0x008c, 0x233e: 0x008c, 0x233f: 0x0080,
// Block 0x8d, offset 0x2340
0x2340: 0x008c, 0x2341: 0x008c, 0x2342: 0x008c, 0x2343: 0x008c, 0x2344: 0x008c, 0x2345: 0x008c,
0x2346: 0x008c, 0x2347: 0x008c, 0x2348: 0x008c, 0x2349: 0x008c, 0x234a: 0x008c, 0x234b: 0x008c,
0x234c: 0x008c, 0x234d: 0x008c, 0x234e: 0x008c, 0x234f: 0x008c, 0x2350: 0x008c, 0x2351: 0x008c,
0x2352: 0x008c, 0x2353: 0x008c, 0x2354: 0x008c, 0x2355: 0x008c, 0x2356: 0x008c, 0x2357: 0x008c,
0x2358: 0x0080, 0x2359: 0x0080, 0x235a: 0x0080, 0x235b: 0x0080, 0x235c: 0x0080, 0x235d: 0x0080,
0x235e: 0x0080, 0x235f: 0x0080, 0x2360: 0x0080, 0x2361: 0x0080, 0x2362: 0x0080, 0x2363: 0x0080,
0x2364: 0x0080, 0x2365: 0x0080, 0x2366: 0x0080, 0x2367: 0x0080, 0x2368: 0x0080, 0x2369: 0x0080,
0x236a: 0x0080, 0x236b: 0x0080, 0x236c: 0x0080, 0x236d: 0x0080, 0x236e: 0x0080, 0x236f: 0x0080,
0x2370: 0x0080, 0x2371: 0x0080, 0x2372: 0x0080, 0x2373: 0x0080, 0x2374: 0x0080, 0x2375: 0x0080,
0x2376: 0x0080, 0x2377: 0x0080, 0x2378: 0x0080, 0x2379: 0x0080, 0x237a: 0x0080, 0x237b: 0x0080,
0x237c: 0x0080, 0x237d: 0x0080, 0x237e: 0x0080, 0x237f: 0x0080,
// Block 0x8e, offset 0x2380
0x2380: 0x00cc, 0x2381: 0x00cc, 0x2382: 0x00cc, 0x2383: 0x00cc, 0x2384: 0x00cc, 0x2385: 0x00cc,
0x2386: 0x00cc, 0x2387: 0x00cc, 0x2388: 0x00cc, 0x2389: 0x00cc, 0x238a: 0x00cc, 0x238b: 0x00cc,
0x238c: 0x00cc, 0x238d: 0x00cc, 0x238e: 0x00cc, 0x238f: 0x00cc, 0x2390: 0x00cc, 0x2391: 0x00cc,
0x2392: 0x00cc, 0x2393: 0x00cc, 0x2394: 0x00cc, 0x2395: 0x00cc, 0x2396: 0x00cc, 0x2397: 0x00cc,
0x2398: 0x00cc, 0x2399: 0x00cc, 0x239a: 0x00cc, 0x239b: 0x00cc, 0x239c: 0x00cc, 0x239d: 0x00cc,
0x239e: 0x00cc, 0x239f: 0x00cc, 0x23a0: 0x00cc, 0x23a1: 0x00cc, 0x23a2: 0x00cc, 0x23a3: 0x00cc,
0x23a4: 0x00cc, 0x23a5: 0x00cc, 0x23a6: 0x00cc, 0x23a7: 0x00cc, 0x23a8: 0x00cc, 0x23a9: 0x00cc,
0x23aa: 0x00cc, 0x23ab: 0x00cc, 0x23ac: 0x00cc, 0x23ad: 0x00cc, 0x23ae: 0x00cc, 0x23af: 0x00cc,
0x23b0: 0x00cc, 0x23b1: 0x00cc, 0x23b2: 0x00cc, 0x23b3: 0x00cc, 0x23b4: 0x00cc, 0x23b5: 0x00cc,
0x23b6: 0x00cc, 0x23b7: 0x00cc, 0x23b8: 0x00cc, 0x23b9: 0x00cc, 0x23ba: 0x00cc, 0x23bb: 0x00cc,
0x23bc: 0x00cc, 0x23bd: 0x00cc, 0x23be: 0x00cc, 0x23bf: 0x00cc,
// Block 0x8f, offset 0x23c0
0x23c0: 0x00c0, 0x23c1: 0x00c0, 0x23c2: 0x00c0, 0x23c3: 0x00c0, 0x23c4: 0x00c0, 0x23c5: 0x00c0,
0x23c6: 0x00c0, 0x23c7: 0x00c0, 0x23c8: 0x00c0, 0x23c9: 0x00c0, 0x23ca: 0x00c0, 0x23cb: 0x00c0,
0x23cc: 0x00c0, 0x23d0: 0x0080, 0x23d1: 0x0080,
0x23d2: 0x0080, 0x23d3: 0x0080, 0x23d4: 0x0080, 0x23d5: 0x0080, 0x23d6: 0x0080, 0x23d7: 0x0080,
0x23d8: 0x0080, 0x23d9: 0x0080, 0x23da: 0x0080, 0x23db: 0x0080, 0x23dc: 0x0080, 0x23dd: 0x0080,
0x23de: 0x0080, 0x23df: 0x0080, 0x23e0: 0x0080, 0x23e1: 0x0080, 0x23e2: 0x0080, 0x23e3: 0x0080,
0x23e4: 0x0080, 0x23e5: 0x0080, 0x23e6: 0x0080, 0x23e7: 0x0080, 0x23e8: 0x0080, 0x23e9: 0x0080,
0x23ea: 0x0080, 0x23eb: 0x0080, 0x23ec: 0x0080, 0x23ed: 0x0080, 0x23ee: 0x0080, 0x23ef: 0x0080,
0x23f0: 0x0080, 0x23f1: 0x0080, 0x23f2: 0x0080, 0x23f3: 0x0080, 0x23f4: 0x0080, 0x23f5: 0x0080,
0x23f6: 0x0080, 0x23f7: 0x0080, 0x23f8: 0x0080, 0x23f9: 0x0080, 0x23fa: 0x0080, 0x23fb: 0x0080,
0x23fc: 0x0080, 0x23fd: 0x0080, 0x23fe: 0x0080, 0x23ff: 0x0080,
// Block 0x90, offset 0x2400
0x2400: 0x0080, 0x2401: 0x0080, 0x2402: 0x0080, 0x2403: 0x0080, 0x2404: 0x0080, 0x2405: 0x0080,
0x2406: 0x0080,
0x2410: 0x00c0, 0x2411: 0x00c0,
0x2412: 0x00c0, 0x2413: 0x00c0, 0x2414: 0x00c0, 0x2415: 0x00c0, 0x2416: 0x00c0, 0x2417: 0x00c0,
0x2418: 0x00c0, 0x2419: 0x00c0, 0x241a: 0x00c0, 0x241b: 0x00c0, 0x241c: 0x00c0, 0x241d: 0x00c0,
0x241e: 0x00c0, 0x241f: 0x00c0, 0x2420: 0x00c0, 0x2421: 0x00c0, 0x2422: 0x00c0, 0x2423: 0x00c0,
0x2424: 0x00c0, 0x2425: 0x00c0, 0x2426: 0x00c0, 0x2427: 0x00c0, 0x2428: 0x00c0, 0x2429: 0x00c0,
0x242a: 0x00c0, 0x242b: 0x00c0, 0x242c: 0x00c0, 0x242d: 0x00c0, 0x242e: 0x00c0, 0x242f: 0x00c0,
0x2430: 0x00c0, 0x2431: 0x00c0, 0x2432: 0x00c0, 0x2433: 0x00c0, 0x2434: 0x00c0, 0x2435: 0x00c0,
0x2436: 0x00c0, 0x2437: 0x00c0, 0x2438: 0x00c0, 0x2439: 0x00c0, 0x243a: 0x00c0, 0x243b: 0x00c0,
0x243c: 0x00c0, 0x243d: 0x00c0, 0x243e: 0x0080, 0x243f: 0x0080,
// Block 0x91, offset 0x2440
0x2440: 0x00c0, 0x2441: 0x00c0, 0x2442: 0x00c0, 0x2443: 0x00c0, 0x2444: 0x00c0, 0x2445: 0x00c0,
0x2446: 0x00c0, 0x2447: 0x00c0, 0x2448: 0x00c0, 0x2449: 0x00c0, 0x244a: 0x00c0, 0x244b: 0x00c0,
0x244c: 0x00c0, 0x244d: 0x0080, 0x244e: 0x0080, 0x244f: 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,
// 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: 0x00c0, 0x248e: 0x00c0, 0x248f: 0x00c0, 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, 0x24ac: 0x00c0, 0x24ad: 0x00c0, 0x24ae: 0x00c0, 0x24af: 0x00c3,
0x24b0: 0x0083, 0x24b1: 0x0083, 0x24b2: 0x0083, 0x24b3: 0x0080, 0x24b4: 0x00c3, 0x24b5: 0x00c3,
0x24b6: 0x00c3, 0x24b7: 0x00c3, 0x24b8: 0x00c3, 0x24b9: 0x00c3, 0x24ba: 0x00c3, 0x24bb: 0x00c3,
0x24bc: 0x00c3, 0x24bd: 0x00c3, 0x24be: 0x0080, 0x24bf: 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: 0x0080, 0x24dd: 0x0080,
0x24de: 0x00c3, 0x24df: 0x00c3, 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: 0x00c0,
0x24f0: 0x00c0, 0x24f1: 0x00c0, 0x24f2: 0x00c0, 0x24f3: 0x00c0, 0x24f4: 0x00c0, 0x24f5: 0x00c0,
0x24f6: 0x00c0, 0x24f7: 0x00c0, 0x24f8: 0x00c0, 0x24f9: 0x00c0, 0x24fa: 0x00c0, 0x24fb: 0x00c0,
0x24fc: 0x00c0, 0x24fd: 0x00c0, 0x24fe: 0x00c0, 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: 0x00c0, 0x251d: 0x00c0,
0x251e: 0x00c0, 0x251f: 0x00c0, 0x2520: 0x00c0, 0x2521: 0x00c0, 0x2522: 0x00c0, 0x2523: 0x00c0,
0x2524: 0x00c0, 0x2525: 0x00c0, 0x2526: 0x0080, 0x2527: 0x0080, 0x2528: 0x0080, 0x2529: 0x0080,
0x252a: 0x0080, 0x252b: 0x0080, 0x252c: 0x0080, 0x252d: 0x0080, 0x252e: 0x0080, 0x252f: 0x0080,
0x2530: 0x00c3, 0x2531: 0x00c3, 0x2532: 0x0080, 0x2533: 0x0080, 0x2534: 0x0080, 0x2535: 0x0080,
0x2536: 0x0080, 0x2537: 0x0080,
// Block 0x95, offset 0x2540
0x2540: 0x0080, 0x2541: 0x0080, 0x2542: 0x0080, 0x2543: 0x0080, 0x2544: 0x0080, 0x2545: 0x0080,
0x2546: 0x0080, 0x2547: 0x0080, 0x2548: 0x0080, 0x2549: 0x0080, 0x254a: 0x0080, 0x254b: 0x0080,
0x254c: 0x0080, 0x254d: 0x0080, 0x254e: 0x0080, 0x254f: 0x0080, 0x2550: 0x0080, 0x2551: 0x0080,
0x2552: 0x0080, 0x2553: 0x0080, 0x2554: 0x0080, 0x2555: 0x0080, 0x2556: 0x0080, 0x2557: 0x00c0,
0x2558: 0x00c0, 0x2559: 0x00c0, 0x255a: 0x00c0, 0x255b: 0x00c0, 0x255c: 0x00c0, 0x255d: 0x00c0,
0x255e: 0x00c0, 0x255f: 0x00c0, 0x2560: 0x0080, 0x2561: 0x0080, 0x2562: 0x00c0, 0x2563: 0x00c0,
0x2564: 0x00c0, 0x2565: 0x00c0, 0x2566: 0x00c0, 0x2567: 0x00c0, 0x2568: 0x00c0, 0x2569: 0x00c0,
0x256a: 0x00c0, 0x256b: 0x00c0, 0x256c: 0x00c0, 0x256d: 0x00c0, 0x256e: 0x00c0, 0x256f: 0x00c0,
0x2570: 0x00c0, 0x2571: 0x00c0, 0x2572: 0x00c0, 0x2573: 0x00c0, 0x2574: 0x00c0, 0x2575: 0x00c0,
0x2576: 0x00c0, 0x2577: 0x00c0, 0x2578: 0x00c0, 0x2579: 0x00c0, 0x257a: 0x00c0, 0x257b: 0x00c0,
0x257c: 0x00c0, 0x257d: 0x00c0, 0x257e: 0x00c0, 0x257f: 0x00c0,
// Block 0x96, offset 0x2580
0x2580: 0x00c0, 0x2581: 0x00c0, 0x2582: 0x00c0, 0x2583: 0x00c0, 0x2584: 0x00c0, 0x2585: 0x00c0,
0x2586: 0x00c0, 0x2587: 0x00c0, 0x2588: 0x00c0, 0x2589: 0x00c0, 0x258a: 0x00c0, 0x258b: 0x00c0,
0x258c: 0x00c0, 0x258d: 0x00c0, 0x258e: 0x00c0, 0x258f: 0x00c0, 0x2590: 0x00c0, 0x2591: 0x00c0,
0x2592: 0x00c0, 0x2593: 0x00c0, 0x2594: 0x00c0, 0x2595: 0x00c0, 0x2596: 0x00c0, 0x2597: 0x00c0,
0x2598: 0x00c0, 0x2599: 0x00c0, 0x259a: 0x00c0, 0x259b: 0x00c0, 0x259c: 0x00c0, 0x259d: 0x00c0,
0x259e: 0x00c0, 0x259f: 0x00c0, 0x25a0: 0x00c0, 0x25a1: 0x00c0, 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: 0x0080, 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: 0x0080, 0x25ca: 0x0080, 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: 0x00c0, 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: 0x00c0, 0x260a: 0x00c0, 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,
0x2631: 0x0080, 0x2632: 0x0080, 0x2633: 0x0080, 0x2634: 0x0080, 0x2635: 0x00c0,
0x2636: 0x00c0, 0x2637: 0x00c0, 0x2638: 0x0080, 0x2639: 0x0080, 0x263a: 0x00c0, 0x263b: 0x00c0,
0x263c: 0x00c0, 0x263d: 0x00c0, 0x263e: 0x00c0, 0x263f: 0x00c0,
// Block 0x99, offset 0x2640
0x2640: 0x00c0, 0x2641: 0x00c0, 0x2642: 0x00c3, 0x2643: 0x00c0, 0x2644: 0x00c0, 0x2645: 0x00c0,
0x2646: 0x00c6, 0x2647: 0x00c0, 0x2648: 0x00c0, 0x2649: 0x00c0, 0x264a: 0x00c0, 0x264b: 0x00c3,
0x264c: 0x00c0, 0x264d: 0x00c0, 0x264e: 0x00c0, 0x264f: 0x00c0, 0x2650: 0x00c0, 0x2651: 0x00c0,
0x2652: 0x00c0, 0x2653: 0x00c0, 0x2654: 0x00c0, 0x2655: 0x00c0, 0x2656: 0x00c0, 0x2657: 0x00c0,
0x2658: 0x00c0, 0x2659: 0x00c0, 0x265a: 0x00c0, 0x265b: 0x00c0, 0x265c: 0x00c0, 0x265d: 0x00c0,
0x265e: 0x00c0, 0x265f: 0x00c0, 0x2660: 0x00c0, 0x2661: 0x00c0, 0x2662: 0x00c0, 0x2663: 0x00c0,
0x2664: 0x00c0, 0x2665: 0x00c3, 0x2666: 0x00c3, 0x2667: 0x00c0, 0x2668: 0x0080, 0x2669: 0x0080,
0x266a: 0x0080, 0x266b: 0x0080, 0x266c: 0x00c6,
0x2670: 0x0080, 0x2671: 0x0080, 0x2672: 0x0080, 0x2673: 0x0080, 0x2674: 0x0080, 0x2675: 0x0080,
0x2676: 0x0080, 0x2677: 0x0080, 0x2678: 0x0080, 0x2679: 0x0080,
// Block 0x9a, offset 0x2680
0x2680: 0x00c2, 0x2681: 0x00c2, 0x2682: 0x00c2, 0x2683: 0x00c2, 0x2684: 0x00c2, 0x2685: 0x00c2,
0x2686: 0x00c2, 0x2687: 0x00c2, 0x2688: 0x00c2, 0x2689: 0x00c2, 0x268a: 0x00c2, 0x268b: 0x00c2,
0x268c: 0x00c2, 0x268d: 0x00c2, 0x268e: 0x00c2, 0x268f: 0x00c2, 0x2690: 0x00c2, 0x2691: 0x00c2,
0x2692: 0x00c2, 0x2693: 0x00c2, 0x2694: 0x00c2, 0x2695: 0x00c2, 0x2696: 0x00c2, 0x2697: 0x00c2,
0x2698: 0x00c2, 0x2699: 0x00c2, 0x269a: 0x00c2, 0x269b: 0x00c2, 0x269c: 0x00c2, 0x269d: 0x00c2,
0x269e: 0x00c2, 0x269f: 0x00c2, 0x26a0: 0x00c2, 0x26a1: 0x00c2, 0x26a2: 0x00c2, 0x26a3: 0x00c2,
0x26a4: 0x00c2, 0x26a5: 0x00c2, 0x26a6: 0x00c2, 0x26a7: 0x00c2, 0x26a8: 0x00c2, 0x26a9: 0x00c2,
0x26aa: 0x00c2, 0x26ab: 0x00c2, 0x26ac: 0x00c2, 0x26ad: 0x00c2, 0x26ae: 0x00c2, 0x26af: 0x00c2,
0x26b0: 0x00c2, 0x26b1: 0x00c2, 0x26b2: 0x00c1, 0x26b3: 0x00c0, 0x26b4: 0x0080, 0x26b5: 0x0080,
0x26b6: 0x0080, 0x26b7: 0x0080,
// Block 0x9b, offset 0x26c0
0x26c0: 0x00c0, 0x26c1: 0x00c0, 0x26c2: 0x00c0, 0x26c3: 0x00c0, 0x26c4: 0x00c6, 0x26c5: 0x00c3,
0x26ce: 0x0080, 0x26cf: 0x0080, 0x26d0: 0x00c0, 0x26d1: 0x00c0,
0x26d2: 0x00c0, 0x26d3: 0x00c0, 0x26d4: 0x00c0, 0x26d5: 0x00c0, 0x26d6: 0x00c0, 0x26d7: 0x00c0,
0x26d8: 0x00c0, 0x26d9: 0x00c0,
0x26e0: 0x00c3, 0x26e1: 0x00c3, 0x26e2: 0x00c3, 0x26e3: 0x00c3,
0x26e4: 0x00c3, 0x26e5: 0x00c3, 0x26e6: 0x00c3, 0x26e7: 0x00c3, 0x26e8: 0x00c3, 0x26e9: 0x00c3,
0x26ea: 0x00c3, 0x26eb: 0x00c3, 0x26ec: 0x00c3, 0x26ed: 0x00c3, 0x26ee: 0x00c3, 0x26ef: 0x00c3,
0x26f0: 0x00c3, 0x26f1: 0x00c3, 0x26f2: 0x00c0, 0x26f3: 0x00c0, 0x26f4: 0x00c0, 0x26f5: 0x00c0,
0x26f6: 0x00c0, 0x26f7: 0x00c0, 0x26f8: 0x0080, 0x26f9: 0x0080, 0x26fa: 0x0080, 0x26fb: 0x00c0,
0x26fc: 0x0080, 0x26fd: 0x00c0, 0x26fe: 0x00c0, 0x26ff: 0x00c3,
// Block 0x9c, offset 0x2700
0x2700: 0x00c0, 0x2701: 0x00c0, 0x2702: 0x00c0, 0x2703: 0x00c0, 0x2704: 0x00c0, 0x2705: 0x00c0,
0x2706: 0x00c0, 0x2707: 0x00c0, 0x2708: 0x00c0, 0x2709: 0x00c0, 0x270a: 0x00c0, 0x270b: 0x00c0,
0x270c: 0x00c0, 0x270d: 0x00c0, 0x270e: 0x00c0, 0x270f: 0x00c0, 0x2710: 0x00c0, 0x2711: 0x00c0,
0x2712: 0x00c0, 0x2713: 0x00c0, 0x2714: 0x00c0, 0x2715: 0x00c0, 0x2716: 0x00c0, 0x2717: 0x00c0,
0x2718: 0x00c0, 0x2719: 0x00c0, 0x271a: 0x00c0, 0x271b: 0x00c0, 0x271c: 0x00c0, 0x271d: 0x00c0,
0x271e: 0x00c0, 0x271f: 0x00c0, 0x2720: 0x00c0, 0x2721: 0x00c0, 0x2722: 0x00c0, 0x2723: 0x00c0,
0x2724: 0x00c0, 0x2725: 0x00c0, 0x2726: 0x00c3, 0x2727: 0x00c3, 0x2728: 0x00c3, 0x2729: 0x00c3,
0x272a: 0x00c3, 0x272b: 0x00c3, 0x272c: 0x00c3, 0x272d: 0x00c3, 0x272e: 0x0080, 0x272f: 0x0080,
0x2730: 0x00c0, 0x2731: 0x00c0, 0x2732: 0x00c0, 0x2733: 0x00c0, 0x2734: 0x00c0, 0x2735: 0x00c0,
0x2736: 0x00c0, 0x2737: 0x00c0, 0x2738: 0x00c0, 0x2739: 0x00c0, 0x273a: 0x00c0, 0x273b: 0x00c0,
0x273c: 0x00c0, 0x273d: 0x00c0, 0x273e: 0x00c0, 0x273f: 0x00c0,
// Block 0x9d, offset 0x2740
0x2740: 0x00c0, 0x2741: 0x00c0, 0x2742: 0x00c0, 0x2743: 0x00c0, 0x2744: 0x00c0, 0x2745: 0x00c0,
0x2746: 0x00c0, 0x2747: 0x00c3, 0x2748: 0x00c3, 0x2749: 0x00c3, 0x274a: 0x00c3, 0x274b: 0x00c3,
0x274c: 0x00c3, 0x274d: 0x00c3, 0x274e: 0x00c3, 0x274f: 0x00c3, 0x2750: 0x00c3, 0x2751: 0x00c3,
0x2752: 0x00c0, 0x2753: 0x00c5,
0x275f: 0x0080, 0x2760: 0x0040, 0x2761: 0x0040, 0x2762: 0x0040, 0x2763: 0x0040,
0x2764: 0x0040, 0x2765: 0x0040, 0x2766: 0x0040, 0x2767: 0x0040, 0x2768: 0x0040, 0x2769: 0x0040,
0x276a: 0x0040, 0x276b: 0x0040, 0x276c: 0x0040, 0x276d: 0x0040, 0x276e: 0x0040, 0x276f: 0x0040,
0x2770: 0x0040, 0x2771: 0x0040, 0x2772: 0x0040, 0x2773: 0x0040, 0x2774: 0x0040, 0x2775: 0x0040,
0x2776: 0x0040, 0x2777: 0x0040, 0x2778: 0x0040, 0x2779: 0x0040, 0x277a: 0x0040, 0x277b: 0x0040,
0x277c: 0x0040,
// Block 0x9e, offset 0x2780
0x2780: 0x00c3, 0x2781: 0x00c3, 0x2782: 0x00c3, 0x2783: 0x00c0, 0x2784: 0x00c0, 0x2785: 0x00c0,
0x2786: 0x00c0, 0x2787: 0x00c0, 0x2788: 0x00c0, 0x2789: 0x00c0, 0x278a: 0x00c0, 0x278b: 0x00c0,
0x278c: 0x00c0, 0x278d: 0x00c0, 0x278e: 0x00c0, 0x278f: 0x00c0, 0x2790: 0x00c0, 0x2791: 0x00c0,
0x2792: 0x00c0, 0x2793: 0x00c0, 0x2794: 0x00c0, 0x2795: 0x00c0, 0x2796: 0x00c0, 0x2797: 0x00c0,
0x2798: 0x00c0, 0x2799: 0x00c0, 0x279a: 0x00c0, 0x279b: 0x00c0, 0x279c: 0x00c0, 0x279d: 0x00c0,
0x279e: 0x00c0, 0x279f: 0x00c0, 0x27a0: 0x00c0, 0x27a1: 0x00c0, 0x27a2: 0x00c0, 0x27a3: 0x00c0,
0x27a4: 0x00c0, 0x27a5: 0x00c0, 0x27a6: 0x00c0, 0x27a7: 0x00c0, 0x27a8: 0x00c0, 0x27a9: 0x00c0,
0x27aa: 0x00c0, 0x27ab: 0x00c0, 0x27ac: 0x00c0, 0x27ad: 0x00c0, 0x27ae: 0x00c0, 0x27af: 0x00c0,
0x27b0: 0x00c0, 0x27b1: 0x00c0, 0x27b2: 0x00c0, 0x27b3: 0x00c3, 0x27b4: 0x00c0, 0x27b5: 0x00c0,
0x27b6: 0x00c3, 0x27b7: 0x00c3, 0x27b8: 0x00c3, 0x27b9: 0x00c3, 0x27ba: 0x00c0, 0x27bb: 0x00c0,
0x27bc: 0x00c3, 0x27bd: 0x00c3, 0x27be: 0x00c0, 0x27bf: 0x00c0,
// Block 0x9f, offset 0x27c0
0x27c0: 0x00c5, 0x27c1: 0x0080, 0x27c2: 0x0080, 0x27c3: 0x0080, 0x27c4: 0x0080, 0x27c5: 0x0080,
0x27c6: 0x0080, 0x27c7: 0x0080, 0x27c8: 0x0080, 0x27c9: 0x0080, 0x27ca: 0x0080, 0x27cb: 0x0080,
0x27cc: 0x0080, 0x27cd: 0x0080, 0x27cf: 0x00c0, 0x27d0: 0x00c0, 0x27d1: 0x00c0,
0x27d2: 0x00c0, 0x27d3: 0x00c0, 0x27d4: 0x00c0, 0x27d5: 0x00c0, 0x27d6: 0x00c0, 0x27d7: 0x00c0,
0x27d8: 0x00c0, 0x27d9: 0x00c0,
0x27de: 0x0080, 0x27df: 0x0080, 0x27e0: 0x00c0, 0x27e1: 0x00c0, 0x27e2: 0x00c0, 0x27e3: 0x00c0,
0x27e4: 0x00c0, 0x27e5: 0x00c3, 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: 0x00c0, 0x27f4: 0x00c0, 0x27f5: 0x00c0,
0x27f6: 0x00c0, 0x27f7: 0x00c0, 0x27f8: 0x00c0, 0x27f9: 0x00c0, 0x27fa: 0x00c0, 0x27fb: 0x00c0,
0x27fc: 0x00c0, 0x27fd: 0x00c0, 0x27fe: 0x00c0,
// Block 0xa0, offset 0x2800
0x2800: 0x00c0, 0x2801: 0x00c0, 0x2802: 0x00c0, 0x2803: 0x00c0, 0x2804: 0x00c0, 0x2805: 0x00c0,
0x2806: 0x00c0, 0x2807: 0x00c0, 0x2808: 0x00c0, 0x2809: 0x00c0, 0x280a: 0x00c0, 0x280b: 0x00c0,
0x280c: 0x00c0, 0x280d: 0x00c0, 0x280e: 0x00c0, 0x280f: 0x00c0, 0x2810: 0x00c0, 0x2811: 0x00c0,
0x2812: 0x00c0, 0x2813: 0x00c0, 0x2814: 0x00c0, 0x2815: 0x00c0, 0x2816: 0x00c0, 0x2817: 0x00c0,
0x2818: 0x00c0, 0x2819: 0x00c0, 0x281a: 0x00c0, 0x281b: 0x00c0, 0x281c: 0x00c0, 0x281d: 0x00c0,
0x281e: 0x00c0, 0x281f: 0x00c0, 0x2820: 0x00c0, 0x2821: 0x00c0, 0x2822: 0x00c0, 0x2823: 0x00c0,
0x2824: 0x00c0, 0x2825: 0x00c0, 0x2826: 0x00c0, 0x2827: 0x00c0, 0x2828: 0x00c0, 0x2829: 0x00c3,
0x282a: 0x00c3, 0x282b: 0x00c3, 0x282c: 0x00c3, 0x282d: 0x00c3, 0x282e: 0x00c3, 0x282f: 0x00c0,
0x2830: 0x00c0, 0x2831: 0x00c3, 0x2832: 0x00c3, 0x2833: 0x00c0, 0x2834: 0x00c0, 0x2835: 0x00c3,
0x2836: 0x00c3,
// Block 0xa1, offset 0x2840
0x2840: 0x00c0, 0x2841: 0x00c0, 0x2842: 0x00c0, 0x2843: 0x00c3, 0x2844: 0x00c0, 0x2845: 0x00c0,
0x2846: 0x00c0, 0x2847: 0x00c0, 0x2848: 0x00c0, 0x2849: 0x00c0, 0x284a: 0x00c0, 0x284b: 0x00c0,
0x284c: 0x00c3, 0x284d: 0x00c0, 0x2850: 0x00c0, 0x2851: 0x00c0,
0x2852: 0x00c0, 0x2853: 0x00c0, 0x2854: 0x00c0, 0x2855: 0x00c0, 0x2856: 0x00c0, 0x2857: 0x00c0,
0x2858: 0x00c0, 0x2859: 0x00c0, 0x285c: 0x0080, 0x285d: 0x0080,
0x285e: 0x0080, 0x285f: 0x0080, 0x2860: 0x00c0, 0x2861: 0x00c0, 0x2862: 0x00c0, 0x2863: 0x00c0,
0x2864: 0x00c0, 0x2865: 0x00c0, 0x2866: 0x00c0, 0x2867: 0x00c0, 0x2868: 0x00c0, 0x2869: 0x00c0,
0x286a: 0x00c0, 0x286b: 0x00c0, 0x286c: 0x00c0, 0x286d: 0x00c0, 0x286e: 0x00c0, 0x286f: 0x00c0,
0x2870: 0x00c0, 0x2871: 0x00c0, 0x2872: 0x00c0, 0x2873: 0x00c0, 0x2874: 0x00c0, 0x2875: 0x00c0,
0x2876: 0x00c0, 0x2877: 0x0080, 0x2878: 0x0080, 0x2879: 0x0080, 0x287a: 0x00c0, 0x287b: 0x00c0,
0x287c: 0x00c3, 0x287d: 0x00c0, 0x287e: 0x00c0, 0x287f: 0x00c0,
// Block 0xa2, offset 0x2880
0x2880: 0x00c0, 0x2881: 0x00c0, 0x2882: 0x00c0, 0x2883: 0x00c0, 0x2884: 0x00c0, 0x2885: 0x00c0,
0x2886: 0x00c0, 0x2887: 0x00c0, 0x2888: 0x00c0, 0x2889: 0x00c0, 0x288a: 0x00c0, 0x288b: 0x00c0,
0x288c: 0x00c0, 0x288d: 0x00c0, 0x288e: 0x00c0, 0x288f: 0x00c0, 0x2890: 0x00c0, 0x2891: 0x00c0,
0x2892: 0x00c0, 0x2893: 0x00c0, 0x2894: 0x00c0, 0x2895: 0x00c0, 0x2896: 0x00c0, 0x2897: 0x00c0,
0x2898: 0x00c0, 0x2899: 0x00c0, 0x289a: 0x00c0, 0x289b: 0x00c0, 0x289c: 0x00c0, 0x289d: 0x00c0,
0x289e: 0x00c0, 0x289f: 0x00c0, 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: 0x00c3, 0x28b1: 0x00c0, 0x28b2: 0x00c3, 0x28b3: 0x00c3, 0x28b4: 0x00c3, 0x28b5: 0x00c0,
0x28b6: 0x00c0, 0x28b7: 0x00c3, 0x28b8: 0x00c3, 0x28b9: 0x00c0, 0x28ba: 0x00c0, 0x28bb: 0x00c0,
0x28bc: 0x00c0, 0x28bd: 0x00c0, 0x28be: 0x00c3, 0x28bf: 0x00c3,
// Block 0xa3, offset 0x28c0
0x28c0: 0x00c0, 0x28c1: 0x00c3, 0x28c2: 0x00c0,
0x28db: 0x00c0, 0x28dc: 0x00c0, 0x28dd: 0x00c0,
0x28de: 0x0080, 0x28df: 0x0080, 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: 0x00c3, 0x28ed: 0x00c3, 0x28ee: 0x00c0, 0x28ef: 0x00c0,
0x28f0: 0x0080, 0x28f1: 0x0080, 0x28f2: 0x00c0, 0x28f3: 0x00c0, 0x28f4: 0x00c0, 0x28f5: 0x00c0,
0x28f6: 0x00c6,
// Block 0xa4, offset 0x2900
0x2901: 0x00c0, 0x2902: 0x00c0, 0x2903: 0x00c0, 0x2904: 0x00c0, 0x2905: 0x00c0,
0x2906: 0x00c0, 0x2909: 0x00c0, 0x290a: 0x00c0, 0x290b: 0x00c0,
0x290c: 0x00c0, 0x290d: 0x00c0, 0x290e: 0x00c0, 0x2911: 0x00c0,
0x2912: 0x00c0, 0x2913: 0x00c0, 0x2914: 0x00c0, 0x2915: 0x00c0, 0x2916: 0x00c0,
0x2920: 0x00c0, 0x2921: 0x00c0, 0x2922: 0x00c0, 0x2923: 0x00c0,
0x2924: 0x00c0, 0x2925: 0x00c0, 0x2926: 0x00c0, 0x2928: 0x00c0, 0x2929: 0x00c0,
0x292a: 0x00c0, 0x292b: 0x00c0, 0x292c: 0x00c0, 0x292d: 0x00c0, 0x292e: 0x00c0,
0x2930: 0x00c0, 0x2931: 0x00c0, 0x2932: 0x00c0, 0x2933: 0x00c0, 0x2934: 0x00c0, 0x2935: 0x00c0,
0x2936: 0x00c0, 0x2937: 0x00c0, 0x2938: 0x00c0, 0x2939: 0x00c0, 0x293a: 0x00c0, 0x293b: 0x00c0,
0x293c: 0x00c0, 0x293d: 0x00c0, 0x293e: 0x00c0, 0x293f: 0x00c0,
// Block 0xa5, offset 0x2940
0x2940: 0x00c0, 0x2941: 0x00c0, 0x2942: 0x00c0, 0x2943: 0x00c0, 0x2944: 0x00c0, 0x2945: 0x00c0,
0x2946: 0x00c0, 0x2947: 0x00c0, 0x2948: 0x00c0, 0x2949: 0x00c0, 0x294a: 0x00c0, 0x294b: 0x00c0,
0x294c: 0x00c0, 0x294d: 0x00c0, 0x294e: 0x00c0, 0x294f: 0x00c0, 0x2950: 0x00c0, 0x2951: 0x00c0,
0x2952: 0x00c0, 0x2953: 0x00c0, 0x2954: 0x00c0, 0x2955: 0x00c0, 0x2956: 0x00c0, 0x2957: 0x00c0,
0x2958: 0x00c0, 0x2959: 0x00c0, 0x295a: 0x00c0, 0x295b: 0x0080, 0x295c: 0x0080, 0x295d: 0x0080,
0x295e: 0x0080, 0x295f: 0x0080, 0x2960: 0x00c0, 0x2961: 0x00c0, 0x2962: 0x00c0, 0x2963: 0x00c0,
0x2964: 0x00c0, 0x2965: 0x00c8, 0x2966: 0x00c0, 0x2967: 0x00c0, 0x2968: 0x00c0, 0x2969: 0x0080,
0x296a: 0x0080, 0x296b: 0x0080,
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: 0x00c0, 0x299c: 0x00c0, 0x299d: 0x00c0,
0x299e: 0x00c0, 0x299f: 0x00c0, 0x29a0: 0x00c0, 0x29a1: 0x00c0, 0x29a2: 0x00c0, 0x29a3: 0x00c0,
0x29a4: 0x00c0, 0x29a5: 0x00c3, 0x29a6: 0x00c0, 0x29a7: 0x00c0, 0x29a8: 0x00c3, 0x29a9: 0x00c0,
0x29aa: 0x00c0, 0x29ab: 0x0080, 0x29ac: 0x00c0, 0x29ad: 0x00c6,
0x29b0: 0x00c0, 0x29b1: 0x00c0, 0x29b2: 0x00c0, 0x29b3: 0x00c0, 0x29b4: 0x00c0, 0x29b5: 0x00c0,
0x29b6: 0x00c0, 0x29b7: 0x00c0, 0x29b8: 0x00c0, 0x29b9: 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,
0x29f0: 0x0040, 0x29f1: 0x0040, 0x29f2: 0x0040, 0x29f3: 0x0040, 0x29f4: 0x0040, 0x29f5: 0x0040,
0x29f6: 0x0040, 0x29f7: 0x0040, 0x29f8: 0x0040, 0x29f9: 0x0040, 0x29fa: 0x0040, 0x29fb: 0x0040,
0x29fc: 0x0040, 0x29fd: 0x0040, 0x29fe: 0x0040, 0x29ff: 0x0040,
// Block 0xa8, offset 0x2a00
0x2a00: 0x0040, 0x2a01: 0x0040, 0x2a02: 0x0040, 0x2a03: 0x0040, 0x2a04: 0x0040, 0x2a05: 0x0040,
0x2a06: 0x0040, 0x2a0b: 0x0040,
0x2a0c: 0x0040, 0x2a0d: 0x0040, 0x2a0e: 0x0040, 0x2a0f: 0x0040, 0x2a10: 0x0040, 0x2a11: 0x0040,
0x2a12: 0x0040, 0x2a13: 0x0040, 0x2a14: 0x0040, 0x2a15: 0x0040, 0x2a16: 0x0040, 0x2a17: 0x0040,
0x2a18: 0x0040, 0x2a19: 0x0040, 0x2a1a: 0x0040, 0x2a1b: 0x0040, 0x2a1c: 0x0040, 0x2a1d: 0x0040,
0x2a1e: 0x0040, 0x2a1f: 0x0040, 0x2a20: 0x0040, 0x2a21: 0x0040, 0x2a22: 0x0040, 0x2a23: 0x0040,
0x2a24: 0x0040, 0x2a25: 0x0040, 0x2a26: 0x0040, 0x2a27: 0x0040, 0x2a28: 0x0040, 0x2a29: 0x0040,
0x2a2a: 0x0040, 0x2a2b: 0x0040, 0x2a2c: 0x0040, 0x2a2d: 0x0040, 0x2a2e: 0x0040, 0x2a2f: 0x0040,
0x2a30: 0x0040, 0x2a31: 0x0040, 0x2a32: 0x0040, 0x2a33: 0x0040, 0x2a34: 0x0040, 0x2a35: 0x0040,
0x2a36: 0x0040, 0x2a37: 0x0040, 0x2a38: 0x0040, 0x2a39: 0x0040, 0x2a3a: 0x0040, 0x2a3b: 0x0040,
// Block 0xa9, offset 0x2a40
0x2a40: 0x008c, 0x2a41: 0x008c, 0x2a42: 0x008c, 0x2a43: 0x008c, 0x2a44: 0x008c, 0x2a45: 0x008c,
0x2a46: 0x008c, 0x2a47: 0x008c, 0x2a48: 0x008c, 0x2a49: 0x008c, 0x2a4a: 0x008c, 0x2a4b: 0x008c,
0x2a4c: 0x008c, 0x2a4d: 0x008c, 0x2a4e: 0x00cc, 0x2a4f: 0x00cc, 0x2a50: 0x008c, 0x2a51: 0x00cc,
0x2a52: 0x008c, 0x2a53: 0x00cc, 0x2a54: 0x00cc, 0x2a55: 0x008c, 0x2a56: 0x008c, 0x2a57: 0x008c,
0x2a58: 0x008c, 0x2a59: 0x008c, 0x2a5a: 0x008c, 0x2a5b: 0x008c, 0x2a5c: 0x008c, 0x2a5d: 0x008c,
0x2a5e: 0x008c, 0x2a5f: 0x00cc, 0x2a60: 0x008c, 0x2a61: 0x00cc, 0x2a62: 0x008c, 0x2a63: 0x00cc,
0x2a64: 0x00cc, 0x2a65: 0x008c, 0x2a66: 0x008c, 0x2a67: 0x00cc, 0x2a68: 0x00cc, 0x2a69: 0x00cc,
0x2a6a: 0x008c, 0x2a6b: 0x008c, 0x2a6c: 0x008c, 0x2a6d: 0x008c, 0x2a6e: 0x008c, 0x2a6f: 0x008c,
0x2a70: 0x008c, 0x2a71: 0x008c, 0x2a72: 0x008c, 0x2a73: 0x008c, 0x2a74: 0x008c, 0x2a75: 0x008c,
0x2a76: 0x008c, 0x2a77: 0x008c, 0x2a78: 0x008c, 0x2a79: 0x008c, 0x2a7a: 0x008c, 0x2a7b: 0x008c,
0x2a7c: 0x008c, 0x2a7d: 0x008c, 0x2a7e: 0x008c, 0x2a7f: 0x008c,
// 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: 0x008c, 0x2a8f: 0x008c, 0x2a90: 0x008c, 0x2a91: 0x008c,
0x2a92: 0x008c, 0x2a93: 0x008c, 0x2a94: 0x008c, 0x2a95: 0x008c, 0x2a96: 0x008c, 0x2a97: 0x008c,
0x2a98: 0x008c, 0x2a99: 0x008c, 0x2a9a: 0x008c, 0x2a9b: 0x008c, 0x2a9c: 0x008c, 0x2a9d: 0x008c,
0x2a9e: 0x008c, 0x2a9f: 0x008c, 0x2aa0: 0x008c, 0x2aa1: 0x008c, 0x2aa2: 0x008c, 0x2aa3: 0x008c,
0x2aa4: 0x008c, 0x2aa5: 0x008c, 0x2aa6: 0x008c, 0x2aa7: 0x008c, 0x2aa8: 0x008c, 0x2aa9: 0x008c,
0x2aaa: 0x008c, 0x2aab: 0x008c, 0x2aac: 0x008c, 0x2aad: 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,
// Block 0xac, offset 0x2b00
0x2b00: 0x0080, 0x2b01: 0x0080, 0x2b02: 0x0080, 0x2b03: 0x0080, 0x2b04: 0x0080, 0x2b05: 0x0080,
0x2b06: 0x0080,
0x2b13: 0x0080, 0x2b14: 0x0080, 0x2b15: 0x0080, 0x2b16: 0x0080, 0x2b17: 0x0080,
0x2b1d: 0x008a,
0x2b1e: 0x00cb, 0x2b1f: 0x008a, 0x2b20: 0x008a, 0x2b21: 0x008a, 0x2b22: 0x008a, 0x2b23: 0x008a,
0x2b24: 0x008a, 0x2b25: 0x008a, 0x2b26: 0x008a, 0x2b27: 0x008a, 0x2b28: 0x008a, 0x2b29: 0x008a,
0x2b2a: 0x008a, 0x2b2b: 0x008a, 0x2b2c: 0x008a, 0x2b2d: 0x008a, 0x2b2e: 0x008a, 0x2b2f: 0x008a,
0x2b30: 0x008a, 0x2b31: 0x008a, 0x2b32: 0x008a, 0x2b33: 0x008a, 0x2b34: 0x008a, 0x2b35: 0x008a,
0x2b36: 0x008a, 0x2b38: 0x008a, 0x2b39: 0x008a, 0x2b3a: 0x008a, 0x2b3b: 0x008a,
0x2b3c: 0x008a, 0x2b3e: 0x008a,
// Block 0xad, offset 0x2b40
0x2b40: 0x008a, 0x2b41: 0x008a, 0x2b43: 0x008a, 0x2b44: 0x008a,
0x2b46: 0x008a, 0x2b47: 0x008a, 0x2b48: 0x008a, 0x2b49: 0x008a, 0x2b4a: 0x008a, 0x2b4b: 0x008a,
0x2b4c: 0x008a, 0x2b4d: 0x008a, 0x2b4e: 0x008a, 0x2b4f: 0x008a, 0x2b50: 0x0080, 0x2b51: 0x0080,
0x2b52: 0x0080, 0x2b53: 0x0080, 0x2b54: 0x0080, 0x2b55: 0x0080, 0x2b56: 0x0080, 0x2b57: 0x0080,
0x2b58: 0x0080, 0x2b59: 0x0080, 0x2b5a: 0x0080, 0x2b5b: 0x0080, 0x2b5c: 0x0080, 0x2b5d: 0x0080,
0x2b5e: 0x0080, 0x2b5f: 0x0080, 0x2b60: 0x0080, 0x2b61: 0x0080, 0x2b62: 0x0080, 0x2b63: 0x0080,
0x2b64: 0x0080, 0x2b65: 0x0080, 0x2b66: 0x0080, 0x2b67: 0x0080, 0x2b68: 0x0080, 0x2b69: 0x0080,
0x2b6a: 0x0080, 0x2b6b: 0x0080, 0x2b6c: 0x0080, 0x2b6d: 0x0080, 0x2b6e: 0x0080, 0x2b6f: 0x0080,
0x2b70: 0x0080, 0x2b71: 0x0080, 0x2b72: 0x0080, 0x2b73: 0x0080, 0x2b74: 0x0080, 0x2b75: 0x0080,
0x2b76: 0x0080, 0x2b77: 0x0080, 0x2b78: 0x0080, 0x2b79: 0x0080, 0x2b7a: 0x0080, 0x2b7b: 0x0080,
0x2b7c: 0x0080, 0x2b7d: 0x0080, 0x2b7e: 0x0080, 0x2b7f: 0x0080,
// Block 0xae, offset 0x2b80
0x2b80: 0x0080, 0x2b81: 0x0080, 0x2b82: 0x0080, 0x2b83: 0x0080, 0x2b84: 0x0080, 0x2b85: 0x0080,
0x2b86: 0x0080, 0x2b87: 0x0080, 0x2b88: 0x0080, 0x2b89: 0x0080, 0x2b8a: 0x0080, 0x2b8b: 0x0080,
0x2b8c: 0x0080, 0x2b8d: 0x0080, 0x2b8e: 0x0080, 0x2b8f: 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: 0x0040, 0x2bc1: 0x0040, 0x2bc2: 0x0040, 0x2bc3: 0x0040, 0x2bc4: 0x0040, 0x2bc5: 0x0040,
0x2bc6: 0x0040, 0x2bc7: 0x0040, 0x2bc8: 0x0040, 0x2bc9: 0x0040, 0x2bca: 0x0040, 0x2bcb: 0x0040,
0x2bcc: 0x0040, 0x2bcd: 0x0040, 0x2bce: 0x0040, 0x2bcf: 0x0040, 0x2bd0: 0x0080, 0x2bd1: 0x0080,
0x2bd2: 0x0080, 0x2bd3: 0x0080, 0x2bd4: 0x0080, 0x2bd5: 0x0080, 0x2bd6: 0x0080, 0x2bd7: 0x0080,
0x2bd8: 0x0080, 0x2bd9: 0x0080,
0x2be0: 0x00c3, 0x2be1: 0x00c3, 0x2be2: 0x00c3, 0x2be3: 0x00c3,
0x2be4: 0x00c3, 0x2be5: 0x00c3, 0x2be6: 0x00c3, 0x2be7: 0x00c3, 0x2be8: 0x00c3, 0x2be9: 0x00c3,
0x2bea: 0x00c3, 0x2beb: 0x00c3, 0x2bec: 0x00c3, 0x2bed: 0x00c3, 0x2bee: 0x00c3, 0x2bef: 0x00c3,
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, 0x2c10: 0x0080, 0x2c11: 0x0080,
0x2c12: 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, 0x2c28: 0x0080, 0x2c29: 0x0080,
0x2c2a: 0x0080, 0x2c2b: 0x0080,
0x2c30: 0x0080, 0x2c31: 0x0080, 0x2c32: 0x0080, 0x2c33: 0x00c0, 0x2c34: 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, 0x2c48: 0x0080, 0x2c49: 0x0080, 0x2c4a: 0x0080, 0x2c4b: 0x0080,
0x2c4c: 0x0080, 0x2c4d: 0x0080, 0x2c4e: 0x0080, 0x2c4f: 0x0080, 0x2c50: 0x0080, 0x2c51: 0x0080,
0x2c52: 0x0080, 0x2c53: 0x0080, 0x2c54: 0x0080, 0x2c55: 0x0080, 0x2c56: 0x0080, 0x2c57: 0x0080,
0x2c58: 0x0080, 0x2c59: 0x0080, 0x2c5a: 0x0080, 0x2c5b: 0x0080, 0x2c5c: 0x0080, 0x2c5d: 0x0080,
0x2c5e: 0x0080, 0x2c5f: 0x0080, 0x2c60: 0x0080, 0x2c61: 0x0080, 0x2c62: 0x0080, 0x2c63: 0x0080,
0x2c64: 0x0080, 0x2c65: 0x0080, 0x2c66: 0x0080, 0x2c67: 0x0080, 0x2c68: 0x0080, 0x2c69: 0x0080,
0x2c6a: 0x0080, 0x2c6b: 0x0080, 0x2c6c: 0x0080, 0x2c6d: 0x0080, 0x2c6e: 0x0080, 0x2c6f: 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, 0x2c7f: 0x0040,
// Block 0xb2, offset 0x2c80
0x2c81: 0x0080, 0x2c82: 0x0080, 0x2c83: 0x0080, 0x2c84: 0x0080, 0x2c85: 0x0080,
0x2c86: 0x0080, 0x2c87: 0x0080, 0x2c88: 0x0080, 0x2c89: 0x0080, 0x2c8a: 0x0080, 0x2c8b: 0x0080,
0x2c8c: 0x0080, 0x2c8d: 0x0080, 0x2c8e: 0x0080, 0x2c8f: 0x0080, 0x2c90: 0x0080, 0x2c91: 0x0080,
0x2c92: 0x0080, 0x2c93: 0x0080, 0x2c94: 0x0080, 0x2c95: 0x0080, 0x2c96: 0x0080, 0x2c97: 0x0080,
0x2c98: 0x0080, 0x2c99: 0x0080, 0x2c9a: 0x0080, 0x2c9b: 0x0080, 0x2c9c: 0x0080, 0x2c9d: 0x0080,
0x2c9e: 0x0080, 0x2c9f: 0x0080, 0x2ca0: 0x0080, 0x2ca1: 0x0080, 0x2ca2: 0x0080, 0x2ca3: 0x0080,
0x2ca4: 0x0080, 0x2ca5: 0x0080, 0x2ca6: 0x0080, 0x2ca7: 0x0080, 0x2ca8: 0x0080, 0x2ca9: 0x0080,
0x2caa: 0x0080, 0x2cab: 0x0080, 0x2cac: 0x0080, 0x2cad: 0x0080, 0x2cae: 0x0080, 0x2caf: 0x0080,
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, 0x2cd3: 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: 0x008c, 0x2ce7: 0x008c, 0x2ce8: 0x008c, 0x2ce9: 0x008c,
0x2cea: 0x008c, 0x2ceb: 0x008c, 0x2cec: 0x008c, 0x2ced: 0x008c, 0x2cee: 0x008c, 0x2cef: 0x008c,
0x2cf0: 0x0080, 0x2cf1: 0x008c, 0x2cf2: 0x008c, 0x2cf3: 0x008c, 0x2cf4: 0x008c, 0x2cf5: 0x008c,
0x2cf6: 0x008c, 0x2cf7: 0x008c, 0x2cf8: 0x008c, 0x2cf9: 0x008c, 0x2cfa: 0x008c, 0x2cfb: 0x008c,
0x2cfc: 0x008c, 0x2cfd: 0x008c, 0x2cfe: 0x008c, 0x2cff: 0x008c,
// Block 0xb4, offset 0x2d00
0x2d00: 0x008c, 0x2d01: 0x008c, 0x2d02: 0x008c, 0x2d03: 0x008c, 0x2d04: 0x008c, 0x2d05: 0x008c,
0x2d06: 0x008c, 0x2d07: 0x008c, 0x2d08: 0x008c, 0x2d09: 0x008c, 0x2d0a: 0x008c, 0x2d0b: 0x008c,
0x2d0c: 0x008c, 0x2d0d: 0x008c, 0x2d0e: 0x008c, 0x2d0f: 0x008c, 0x2d10: 0x008c, 0x2d11: 0x008c,
0x2d12: 0x008c, 0x2d13: 0x008c, 0x2d14: 0x008c, 0x2d15: 0x008c, 0x2d16: 0x008c, 0x2d17: 0x008c,
0x2d18: 0x008c, 0x2d19: 0x008c, 0x2d1a: 0x008c, 0x2d1b: 0x008c, 0x2d1c: 0x008c, 0x2d1d: 0x008c,
0x2d1e: 0x0080, 0x2d1f: 0x0080, 0x2d20: 0x0040, 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, 0x2d3d: 0x0080, 0x2d3e: 0x0080,
// Block 0xb5, offset 0x2d40
0x2d42: 0x0080, 0x2d43: 0x0080, 0x2d44: 0x0080, 0x2d45: 0x0080,
0x2d46: 0x0080, 0x2d47: 0x0080, 0x2d4a: 0x0080, 0x2d4b: 0x0080,
0x2d4c: 0x0080, 0x2d4d: 0x0080, 0x2d4e: 0x0080, 0x2d4f: 0x0080,
0x2d52: 0x0080, 0x2d53: 0x0080, 0x2d54: 0x0080, 0x2d55: 0x0080, 0x2d56: 0x0080, 0x2d57: 0x0080,
0x2d5a: 0x0080, 0x2d5b: 0x0080, 0x2d5c: 0x0080,
0x2d60: 0x0080, 0x2d61: 0x0080, 0x2d62: 0x0080, 0x2d63: 0x0080,
0x2d64: 0x0080, 0x2d65: 0x0080, 0x2d66: 0x0080, 0x2d68: 0x0080, 0x2d69: 0x0080,
0x2d6a: 0x0080, 0x2d6b: 0x0080, 0x2d6c: 0x0080, 0x2d6d: 0x0080, 0x2d6e: 0x0080,
0x2d79: 0x0040, 0x2d7a: 0x0040, 0x2d7b: 0x0040,
0x2d7c: 0x0080, 0x2d7d: 0x0080,
// Block 0xb6, offset 0x2d80
0x2d80: 0x00c0, 0x2d81: 0x00c0, 0x2d82: 0x00c0, 0x2d83: 0x00c0, 0x2d84: 0x00c0, 0x2d85: 0x00c0,
0x2d86: 0x00c0, 0x2d87: 0x00c0, 0x2d88: 0x00c0, 0x2d89: 0x00c0, 0x2d8a: 0x00c0, 0x2d8b: 0x00c0,
0x2d8d: 0x00c0, 0x2d8e: 0x00c0, 0x2d8f: 0x00c0, 0x2d90: 0x00c0, 0x2d91: 0x00c0,
0x2d92: 0x00c0, 0x2d93: 0x00c0, 0x2d94: 0x00c0, 0x2d95: 0x00c0, 0x2d96: 0x00c0, 0x2d97: 0x00c0,
0x2d98: 0x00c0, 0x2d99: 0x00c0, 0x2d9a: 0x00c0, 0x2d9b: 0x00c0, 0x2d9c: 0x00c0, 0x2d9d: 0x00c0,
0x2d9e: 0x00c0, 0x2d9f: 0x00c0, 0x2da0: 0x00c0, 0x2da1: 0x00c0, 0x2da2: 0x00c0, 0x2da3: 0x00c0,
0x2da4: 0x00c0, 0x2da5: 0x00c0, 0x2da6: 0x00c0, 0x2da8: 0x00c0, 0x2da9: 0x00c0,
0x2daa: 0x00c0, 0x2dab: 0x00c0, 0x2dac: 0x00c0, 0x2dad: 0x00c0, 0x2dae: 0x00c0, 0x2daf: 0x00c0,
0x2db0: 0x00c0, 0x2db1: 0x00c0, 0x2db2: 0x00c0, 0x2db3: 0x00c0, 0x2db4: 0x00c0, 0x2db5: 0x00c0,
0x2db6: 0x00c0, 0x2db7: 0x00c0, 0x2db8: 0x00c0, 0x2db9: 0x00c0, 0x2dba: 0x00c0,
0x2dbc: 0x00c0, 0x2dbd: 0x00c0, 0x2dbf: 0x00c0,
// Block 0xb7, offset 0x2dc0
0x2dc0: 0x00c0, 0x2dc1: 0x00c0, 0x2dc2: 0x00c0, 0x2dc3: 0x00c0, 0x2dc4: 0x00c0, 0x2dc5: 0x00c0,
0x2dc6: 0x00c0, 0x2dc7: 0x00c0, 0x2dc8: 0x00c0, 0x2dc9: 0x00c0, 0x2dca: 0x00c0, 0x2dcb: 0x00c0,
0x2dcc: 0x00c0, 0x2dcd: 0x00c0, 0x2dd0: 0x00c0, 0x2dd1: 0x00c0,
0x2dd2: 0x00c0, 0x2dd3: 0x00c0, 0x2dd4: 0x00c0, 0x2dd5: 0x00c0, 0x2dd6: 0x00c0, 0x2dd7: 0x00c0,
0x2dd8: 0x00c0, 0x2dd9: 0x00c0, 0x2dda: 0x00c0, 0x2ddb: 0x00c0, 0x2ddc: 0x00c0, 0x2ddd: 0x00c0,
// Block 0xb8, offset 0x2e00
0x2e00: 0x00c0, 0x2e01: 0x00c0, 0x2e02: 0x00c0, 0x2e03: 0x00c0, 0x2e04: 0x00c0, 0x2e05: 0x00c0,
0x2e06: 0x00c0, 0x2e07: 0x00c0, 0x2e08: 0x00c0, 0x2e09: 0x00c0, 0x2e0a: 0x00c0, 0x2e0b: 0x00c0,
0x2e0c: 0x00c0, 0x2e0d: 0x00c0, 0x2e0e: 0x00c0, 0x2e0f: 0x00c0, 0x2e10: 0x00c0, 0x2e11: 0x00c0,
0x2e12: 0x00c0, 0x2e13: 0x00c0, 0x2e14: 0x00c0, 0x2e15: 0x00c0, 0x2e16: 0x00c0, 0x2e17: 0x00c0,
0x2e18: 0x00c0, 0x2e19: 0x00c0, 0x2e1a: 0x00c0, 0x2e1b: 0x00c0, 0x2e1c: 0x00c0, 0x2e1d: 0x00c0,
0x2e1e: 0x00c0, 0x2e1f: 0x00c0, 0x2e20: 0x00c0, 0x2e21: 0x00c0, 0x2e22: 0x00c0, 0x2e23: 0x00c0,
0x2e24: 0x00c0, 0x2e25: 0x00c0, 0x2e26: 0x00c0, 0x2e27: 0x00c0, 0x2e28: 0x00c0, 0x2e29: 0x00c0,
0x2e2a: 0x00c0, 0x2e2b: 0x00c0, 0x2e2c: 0x00c0, 0x2e2d: 0x00c0, 0x2e2e: 0x00c0, 0x2e2f: 0x00c0,
0x2e30: 0x00c0, 0x2e31: 0x00c0, 0x2e32: 0x00c0, 0x2e33: 0x00c0, 0x2e34: 0x00c0, 0x2e35: 0x00c0,
0x2e36: 0x00c0, 0x2e37: 0x00c0, 0x2e38: 0x00c0, 0x2e39: 0x00c0, 0x2e3a: 0x00c0,
// Block 0xb9, offset 0x2e40
0x2e40: 0x0080, 0x2e41: 0x0080, 0x2e42: 0x0080,
0x2e47: 0x0080, 0x2e48: 0x0080, 0x2e49: 0x0080, 0x2e4a: 0x0080, 0x2e4b: 0x0080,
0x2e4c: 0x0080, 0x2e4d: 0x0080, 0x2e4e: 0x0080, 0x2e4f: 0x0080, 0x2e50: 0x0080, 0x2e51: 0x0080,
0x2e52: 0x0080, 0x2e53: 0x0080, 0x2e54: 0x0080, 0x2e55: 0x0080, 0x2e56: 0x0080, 0x2e57: 0x0080,
0x2e58: 0x0080, 0x2e59: 0x0080, 0x2e5a: 0x0080, 0x2e5b: 0x0080, 0x2e5c: 0x0080, 0x2e5d: 0x0080,
0x2e5e: 0x0080, 0x2e5f: 0x0080, 0x2e60: 0x0080, 0x2e61: 0x0080, 0x2e62: 0x0080, 0x2e63: 0x0080,
0x2e64: 0x0080, 0x2e65: 0x0080, 0x2e66: 0x0080, 0x2e67: 0x0080, 0x2e68: 0x0080, 0x2e69: 0x0080,
0x2e6a: 0x0080, 0x2e6b: 0x0080, 0x2e6c: 0x0080, 0x2e6d: 0x0080, 0x2e6e: 0x0080, 0x2e6f: 0x0080,
0x2e70: 0x0080, 0x2e71: 0x0080, 0x2e72: 0x0080, 0x2e73: 0x0080,
0x2e77: 0x0080, 0x2e78: 0x0080, 0x2e79: 0x0080, 0x2e7a: 0x0080, 0x2e7b: 0x0080,
0x2e7c: 0x0080, 0x2e7d: 0x0080, 0x2e7e: 0x0080, 0x2e7f: 0x0080,
// Block 0xba, offset 0x2e80
0x2e80: 0x0088, 0x2e81: 0x0088, 0x2e82: 0x0088, 0x2e83: 0x0088, 0x2e84: 0x0088, 0x2e85: 0x0088,
0x2e86: 0x0088, 0x2e87: 0x0088, 0x2e88: 0x0088, 0x2e89: 0x0088, 0x2e8a: 0x0088, 0x2e8b: 0x0088,
0x2e8c: 0x0088, 0x2e8d: 0x0088, 0x2e8e: 0x0088, 0x2e8f: 0x0088, 0x2e90: 0x0088, 0x2e91: 0x0088,
0x2e92: 0x0088, 0x2e93: 0x0088, 0x2e94: 0x0088, 0x2e95: 0x0088, 0x2e96: 0x0088, 0x2e97: 0x0088,
0x2e98: 0x0088, 0x2e99: 0x0088, 0x2e9a: 0x0088, 0x2e9b: 0x0088, 0x2e9c: 0x0088, 0x2e9d: 0x0088,
0x2e9e: 0x0088, 0x2e9f: 0x0088, 0x2ea0: 0x0088, 0x2ea1: 0x0088, 0x2ea2: 0x0088, 0x2ea3: 0x0088,
0x2ea4: 0x0088, 0x2ea5: 0x0088, 0x2ea6: 0x0088, 0x2ea7: 0x0088, 0x2ea8: 0x0088, 0x2ea9: 0x0088,
0x2eaa: 0x0088, 0x2eab: 0x0088, 0x2eac: 0x0088, 0x2ead: 0x0088, 0x2eae: 0x0088, 0x2eaf: 0x0088,
0x2eb0: 0x0088, 0x2eb1: 0x0088, 0x2eb2: 0x0088, 0x2eb3: 0x0088, 0x2eb4: 0x0088, 0x2eb5: 0x0088,
0x2eb6: 0x0088, 0x2eb7: 0x0088, 0x2eb8: 0x0088, 0x2eb9: 0x0088, 0x2eba: 0x0088, 0x2ebb: 0x0088,
0x2ebc: 0x0088, 0x2ebd: 0x0088, 0x2ebe: 0x0088, 0x2ebf: 0x0088,
// Block 0xbb, offset 0x2ec0
0x2ec0: 0x0088, 0x2ec1: 0x0088, 0x2ec2: 0x0088, 0x2ec3: 0x0088, 0x2ec4: 0x0088, 0x2ec5: 0x0088,
0x2ec6: 0x0088, 0x2ec7: 0x0088, 0x2ec8: 0x0088, 0x2ec9: 0x0088, 0x2eca: 0x0088, 0x2ecb: 0x0088,
0x2ecc: 0x0088, 0x2ecd: 0x0088, 0x2ece: 0x0088, 0x2ed0: 0x0080, 0x2ed1: 0x0080,
0x2ed2: 0x0080, 0x2ed3: 0x0080, 0x2ed4: 0x0080, 0x2ed5: 0x0080, 0x2ed6: 0x0080, 0x2ed7: 0x0080,
0x2ed8: 0x0080, 0x2ed9: 0x0080, 0x2eda: 0x0080, 0x2edb: 0x0080, 0x2edc: 0x0080,
0x2ee0: 0x0088,
// Block 0xbc, offset 0x2f00
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, 0x2f34: 0x0080, 0x2f35: 0x0080,
0x2f36: 0x0080, 0x2f37: 0x0080, 0x2f38: 0x0080, 0x2f39: 0x0080, 0x2f3a: 0x0080, 0x2f3b: 0x0080,
0x2f3c: 0x0080, 0x2f3d: 0x00c3,
// Block 0xbd, offset 0x2f40
0x2f40: 0x00c0, 0x2f41: 0x00c0, 0x2f42: 0x00c0, 0x2f43: 0x00c0, 0x2f44: 0x00c0, 0x2f45: 0x00c0,
0x2f46: 0x00c0, 0x2f47: 0x00c0, 0x2f48: 0x00c0, 0x2f49: 0x00c0, 0x2f4a: 0x00c0, 0x2f4b: 0x00c0,
0x2f4c: 0x00c0, 0x2f4d: 0x00c0, 0x2f4e: 0x00c0, 0x2f4f: 0x00c0, 0x2f50: 0x00c0, 0x2f51: 0x00c0,
0x2f52: 0x00c0, 0x2f53: 0x00c0, 0x2f54: 0x00c0, 0x2f55: 0x00c0, 0x2f56: 0x00c0, 0x2f57: 0x00c0,
0x2f58: 0x00c0, 0x2f59: 0x00c0, 0x2f5a: 0x00c0, 0x2f5b: 0x00c0, 0x2f5c: 0x00c0,
0x2f60: 0x00c0, 0x2f61: 0x00c0, 0x2f62: 0x00c0, 0x2f63: 0x00c0,
0x2f64: 0x00c0, 0x2f65: 0x00c0, 0x2f66: 0x00c0, 0x2f67: 0x00c0, 0x2f68: 0x00c0, 0x2f69: 0x00c0,
0x2f6a: 0x00c0, 0x2f6b: 0x00c0, 0x2f6c: 0x00c0, 0x2f6d: 0x00c0, 0x2f6e: 0x00c0, 0x2f6f: 0x00c0,
0x2f70: 0x00c0, 0x2f71: 0x00c0, 0x2f72: 0x00c0, 0x2f73: 0x00c0, 0x2f74: 0x00c0, 0x2f75: 0x00c0,
0x2f76: 0x00c0, 0x2f77: 0x00c0, 0x2f78: 0x00c0, 0x2f79: 0x00c0, 0x2f7a: 0x00c0, 0x2f7b: 0x00c0,
0x2f7c: 0x00c0, 0x2f7d: 0x00c0, 0x2f7e: 0x00c0, 0x2f7f: 0x00c0,
// Block 0xbe, offset 0x2f80
0x2f80: 0x00c0, 0x2f81: 0x00c0, 0x2f82: 0x00c0, 0x2f83: 0x00c0, 0x2f84: 0x00c0, 0x2f85: 0x00c0,
0x2f86: 0x00c0, 0x2f87: 0x00c0, 0x2f88: 0x00c0, 0x2f89: 0x00c0, 0x2f8a: 0x00c0, 0x2f8b: 0x00c0,
0x2f8c: 0x00c0, 0x2f8d: 0x00c0, 0x2f8e: 0x00c0, 0x2f8f: 0x00c0, 0x2f90: 0x00c0,
0x2fa0: 0x00c3, 0x2fa1: 0x0080, 0x2fa2: 0x0080, 0x2fa3: 0x0080,
0x2fa4: 0x0080, 0x2fa5: 0x0080, 0x2fa6: 0x0080, 0x2fa7: 0x0080, 0x2fa8: 0x0080, 0x2fa9: 0x0080,
0x2faa: 0x0080, 0x2fab: 0x0080, 0x2fac: 0x0080, 0x2fad: 0x0080, 0x2fae: 0x0080, 0x2faf: 0x0080,
0x2fb0: 0x0080, 0x2fb1: 0x0080, 0x2fb2: 0x0080, 0x2fb3: 0x0080, 0x2fb4: 0x0080, 0x2fb5: 0x0080,
0x2fb6: 0x0080, 0x2fb7: 0x0080, 0x2fb8: 0x0080, 0x2fb9: 0x0080, 0x2fba: 0x0080, 0x2fbb: 0x0080,
// Block 0xbf, offset 0x2fc0
0x2fc0: 0x00c0, 0x2fc1: 0x00c0, 0x2fc2: 0x00c0, 0x2fc3: 0x00c0, 0x2fc4: 0x00c0, 0x2fc5: 0x00c0,
0x2fc6: 0x00c0, 0x2fc7: 0x00c0, 0x2fc8: 0x00c0, 0x2fc9: 0x00c0, 0x2fca: 0x00c0, 0x2fcb: 0x00c0,
0x2fcc: 0x00c0, 0x2fcd: 0x00c0, 0x2fce: 0x00c0, 0x2fcf: 0x00c0, 0x2fd0: 0x00c0, 0x2fd1: 0x00c0,
0x2fd2: 0x00c0, 0x2fd3: 0x00c0, 0x2fd4: 0x00c0, 0x2fd5: 0x00c0, 0x2fd6: 0x00c0, 0x2fd7: 0x00c0,
0x2fd8: 0x00c0, 0x2fd9: 0x00c0, 0x2fda: 0x00c0, 0x2fdb: 0x00c0, 0x2fdc: 0x00c0, 0x2fdd: 0x00c0,
0x2fde: 0x00c0, 0x2fdf: 0x00c0, 0x2fe0: 0x0080, 0x2fe1: 0x0080, 0x2fe2: 0x0080, 0x2fe3: 0x0080,
0x2fed: 0x00c0, 0x2fee: 0x00c0, 0x2fef: 0x00c0,
0x2ff0: 0x00c0, 0x2ff1: 0x00c0, 0x2ff2: 0x00c0, 0x2ff3: 0x00c0, 0x2ff4: 0x00c0, 0x2ff5: 0x00c0,
0x2ff6: 0x00c0, 0x2ff7: 0x00c0, 0x2ff8: 0x00c0, 0x2ff9: 0x00c0, 0x2ffa: 0x00c0, 0x2ffb: 0x00c0,
0x2ffc: 0x00c0, 0x2ffd: 0x00c0, 0x2ffe: 0x00c0, 0x2fff: 0x00c0,
// Block 0xc0, offset 0x3000
0x3000: 0x00c0, 0x3001: 0x0080, 0x3002: 0x00c0, 0x3003: 0x00c0, 0x3004: 0x00c0, 0x3005: 0x00c0,
0x3006: 0x00c0, 0x3007: 0x00c0, 0x3008: 0x00c0, 0x3009: 0x00c0, 0x300a: 0x0080,
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, 0x301d: 0x00c0,
0x301e: 0x00c0, 0x301f: 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: 0x00c3, 0x3037: 0x00c3, 0x3038: 0x00c3, 0x3039: 0x00c3, 0x303a: 0x00c3,
// 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, 0x3051: 0x00c0,
0x3052: 0x00c0, 0x3053: 0x00c0, 0x3054: 0x00c0, 0x3055: 0x00c0, 0x3056: 0x00c0, 0x3057: 0x00c0,
0x3058: 0x00c0, 0x3059: 0x00c0, 0x305a: 0x00c0, 0x305b: 0x00c0, 0x305c: 0x00c0, 0x305d: 0x00c0,
0x305f: 0x0080, 0x3060: 0x00c0, 0x3061: 0x00c0, 0x3062: 0x00c0, 0x3063: 0x00c0,
0x3064: 0x00c0, 0x3065: 0x00c0, 0x3066: 0x00c0, 0x3067: 0x00c0, 0x3068: 0x00c0, 0x3069: 0x00c0,
0x306a: 0x00c0, 0x306b: 0x00c0, 0x306c: 0x00c0, 0x306d: 0x00c0, 0x306e: 0x00c0, 0x306f: 0x00c0,
0x3070: 0x00c0, 0x3071: 0x00c0, 0x3072: 0x00c0, 0x3073: 0x00c0, 0x3074: 0x00c0, 0x3075: 0x00c0,
0x3076: 0x00c0, 0x3077: 0x00c0, 0x3078: 0x00c0, 0x3079: 0x00c0, 0x307a: 0x00c0, 0x307b: 0x00c0,
0x307c: 0x00c0, 0x307d: 0x00c0, 0x307e: 0x00c0, 0x307f: 0x00c0,
// Block 0xc2, offset 0x3080
0x3080: 0x00c0, 0x3081: 0x00c0, 0x3082: 0x00c0, 0x3083: 0x00c0,
0x3088: 0x00c0, 0x3089: 0x00c0, 0x308a: 0x00c0, 0x308b: 0x00c0,
0x308c: 0x00c0, 0x308d: 0x00c0, 0x308e: 0x00c0, 0x308f: 0x00c0, 0x3090: 0x0080, 0x3091: 0x0080,
0x3092: 0x0080, 0x3093: 0x0080, 0x3094: 0x0080, 0x3095: 0x0080,
// Block 0xc3, offset 0x30c0
0x30c0: 0x00c0, 0x30c1: 0x00c0, 0x30c2: 0x00c0, 0x30c3: 0x00c0, 0x30c4: 0x00c0, 0x30c5: 0x00c0,
0x30c6: 0x00c0, 0x30c7: 0x00c0, 0x30c8: 0x00c0, 0x30c9: 0x00c0, 0x30ca: 0x00c0, 0x30cb: 0x00c0,
0x30cc: 0x00c0, 0x30cd: 0x00c0, 0x30ce: 0x00c0, 0x30cf: 0x00c0, 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,
0x30e0: 0x00c0, 0x30e1: 0x00c0, 0x30e2: 0x00c0, 0x30e3: 0x00c0,
0x30e4: 0x00c0, 0x30e5: 0x00c0, 0x30e6: 0x00c0, 0x30e7: 0x00c0, 0x30e8: 0x00c0, 0x30e9: 0x00c0,
0x30f0: 0x00c0, 0x30f1: 0x00c0, 0x30f2: 0x00c0, 0x30f3: 0x00c0, 0x30f4: 0x00c0, 0x30f5: 0x00c0,
0x30f6: 0x00c0, 0x30f7: 0x00c0, 0x30f8: 0x00c0, 0x30f9: 0x00c0, 0x30fa: 0x00c0, 0x30fb: 0x00c0,
0x30fc: 0x00c0, 0x30fd: 0x00c0, 0x30fe: 0x00c0, 0x30ff: 0x00c0,
// 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,
0x3118: 0x00c0, 0x3119: 0x00c0, 0x311a: 0x00c0, 0x311b: 0x00c0, 0x311c: 0x00c0, 0x311d: 0x00c0,
0x311e: 0x00c0, 0x311f: 0x00c0, 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,
// Block 0xc5, offset 0x3140
0x3140: 0x00c0, 0x3141: 0x00c0, 0x3142: 0x00c0, 0x3143: 0x00c0, 0x3144: 0x00c0, 0x3145: 0x00c0,
0x3146: 0x00c0, 0x3147: 0x00c0, 0x3148: 0x00c0, 0x3149: 0x00c0, 0x314a: 0x00c0, 0x314b: 0x00c0,
0x314c: 0x00c0, 0x314d: 0x00c0, 0x314e: 0x00c0, 0x314f: 0x00c0, 0x3150: 0x00c0, 0x3151: 0x00c0,
0x3152: 0x00c0, 0x3153: 0x00c0, 0x3154: 0x00c0, 0x3155: 0x00c0, 0x3156: 0x00c0, 0x3157: 0x00c0,
0x3158: 0x00c0, 0x3159: 0x00c0, 0x315a: 0x00c0, 0x315b: 0x00c0, 0x315c: 0x00c0, 0x315d: 0x00c0,
0x315e: 0x00c0, 0x315f: 0x00c0, 0x3160: 0x00c0, 0x3161: 0x00c0, 0x3162: 0x00c0, 0x3163: 0x00c0,
0x3164: 0x00c0, 0x3165: 0x00c0, 0x3166: 0x00c0, 0x3167: 0x00c0,
0x3170: 0x00c0, 0x3171: 0x00c0, 0x3172: 0x00c0, 0x3173: 0x00c0, 0x3174: 0x00c0, 0x3175: 0x00c0,
0x3176: 0x00c0, 0x3177: 0x00c0, 0x3178: 0x00c0, 0x3179: 0x00c0, 0x317a: 0x00c0, 0x317b: 0x00c0,
0x317c: 0x00c0, 0x317d: 0x00c0, 0x317e: 0x00c0, 0x317f: 0x00c0,
// 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,
0x319e: 0x00c0, 0x319f: 0x00c0, 0x31a0: 0x00c0, 0x31a1: 0x00c0, 0x31a2: 0x00c0, 0x31a3: 0x00c0,
0x31af: 0x0080,
0x31b0: 0x00c0, 0x31b1: 0x00c0, 0x31b2: 0x00c0, 0x31b3: 0x00c0, 0x31b4: 0x00c0, 0x31b5: 0x00c0,
0x31b6: 0x00c0, 0x31b7: 0x00c0, 0x31b8: 0x00c0, 0x31b9: 0x00c0, 0x31ba: 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,
0x31cc: 0x00c0, 0x31cd: 0x00c0, 0x31ce: 0x00c0, 0x31cf: 0x00c0, 0x31d0: 0x00c0, 0x31d1: 0x00c0,
0x31d2: 0x00c0, 0x31d4: 0x00c0, 0x31d5: 0x00c0, 0x31d7: 0x00c0,
0x31d8: 0x00c0, 0x31d9: 0x00c0, 0x31da: 0x00c0, 0x31db: 0x00c0, 0x31dc: 0x00c0, 0x31dd: 0x00c0,
0x31de: 0x00c0, 0x31df: 0x00c0, 0x31e0: 0x00c0, 0x31e1: 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, 0x31f3: 0x00c0, 0x31f4: 0x00c0, 0x31f5: 0x00c0,
0x31f6: 0x00c0, 0x31f7: 0x00c0, 0x31f8: 0x00c0, 0x31f9: 0x00c0, 0x31fb: 0x00c0,
0x31fc: 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, 0x3228: 0x00c0, 0x3229: 0x00c0,
0x322a: 0x00c0, 0x322b: 0x00c0, 0x322c: 0x00c0, 0x322d: 0x00c0, 0x322e: 0x00c0, 0x322f: 0x00c0,
0x3230: 0x00c0, 0x3231: 0x00c0, 0x3232: 0x00c0, 0x3233: 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,
0x3264: 0x00c0, 0x3265: 0x00c0, 0x3266: 0x00c0, 0x3267: 0x00c0, 0x3268: 0x00c0, 0x3269: 0x00c0,
0x326a: 0x00c0, 0x326b: 0x00c0, 0x326c: 0x00c0, 0x326d: 0x00c0, 0x326e: 0x00c0, 0x326f: 0x00c0,
0x3270: 0x00c0, 0x3271: 0x00c0, 0x3272: 0x00c0, 0x3273: 0x00c0, 0x3274: 0x00c0, 0x3275: 0x00c0,
0x3276: 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, 0x328b: 0x00c0,
0x328c: 0x00c0, 0x328d: 0x00c0, 0x328e: 0x00c0, 0x328f: 0x00c0, 0x3290: 0x00c0, 0x3291: 0x00c0,
0x3292: 0x00c0, 0x3293: 0x00c0, 0x3294: 0x00c0, 0x3295: 0x00c0,
0x32a0: 0x00c0, 0x32a1: 0x00c0, 0x32a2: 0x00c0, 0x32a3: 0x00c0,
0x32a4: 0x00c0, 0x32a5: 0x00c0, 0x32a6: 0x00c0, 0x32a7: 0x00c0,
// Block 0xcb, offset 0x32c0
0x32c0: 0x00c0, 0x32c1: 0x0080, 0x32c2: 0x0080, 0x32c3: 0x0080, 0x32c4: 0x0080, 0x32c5: 0x0080,
0x32c7: 0x0080, 0x32c8: 0x0080, 0x32c9: 0x0080, 0x32ca: 0x0080, 0x32cb: 0x0080,
0x32cc: 0x0080, 0x32cd: 0x0080, 0x32ce: 0x0080, 0x32cf: 0x0080, 0x32d0: 0x0080, 0x32d1: 0x0080,
0x32d2: 0x0080, 0x32d3: 0x0080, 0x32d4: 0x0080, 0x32d5: 0x0080, 0x32d6: 0x0080, 0x32d7: 0x0080,
0x32d8: 0x0080, 0x32d9: 0x0080, 0x32da: 0x0080, 0x32db: 0x0080, 0x32dc: 0x0080, 0x32dd: 0x0080,
0x32de: 0x0080, 0x32df: 0x0080, 0x32e0: 0x0080, 0x32e1: 0x0080, 0x32e2: 0x0080, 0x32e3: 0x0080,
0x32e4: 0x0080, 0x32e5: 0x0080, 0x32e6: 0x0080, 0x32e7: 0x0080, 0x32e8: 0x0080, 0x32e9: 0x0080,
0x32ea: 0x0080, 0x32eb: 0x0080, 0x32ec: 0x0080, 0x32ed: 0x0080, 0x32ee: 0x0080, 0x32ef: 0x0080,
0x32f0: 0x0080, 0x32f2: 0x0080, 0x32f3: 0x0080, 0x32f4: 0x0080, 0x32f5: 0x0080,
0x32f6: 0x0080, 0x32f7: 0x0080, 0x32f8: 0x0080, 0x32f9: 0x0080, 0x32fa: 0x0080,
// Block 0xcc, offset 0x3300
0x3300: 0x00c0, 0x3301: 0x00c0, 0x3302: 0x00c0, 0x3303: 0x00c0, 0x3304: 0x00c0, 0x3305: 0x00c0,
0x3308: 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, 0x3316: 0x00c0, 0x3317: 0x00c0,
0x3318: 0x00c0, 0x3319: 0x00c0, 0x331a: 0x00c0, 0x331b: 0x00c0, 0x331c: 0x00c0, 0x331d: 0x00c0,
0x331e: 0x00c0, 0x331f: 0x00c0, 0x3320: 0x00c0, 0x3321: 0x00c0, 0x3322: 0x00c0, 0x3323: 0x00c0,
0x3324: 0x00c0, 0x3325: 0x00c0, 0x3326: 0x00c0, 0x3327: 0x00c0, 0x3328: 0x00c0, 0x3329: 0x00c0,
0x332a: 0x00c0, 0x332b: 0x00c0, 0x332c: 0x00c0, 0x332d: 0x00c0, 0x332e: 0x00c0, 0x332f: 0x00c0,
0x3330: 0x00c0, 0x3331: 0x00c0, 0x3332: 0x00c0, 0x3333: 0x00c0, 0x3334: 0x00c0, 0x3335: 0x00c0,
0x3337: 0x00c0, 0x3338: 0x00c0,
0x333c: 0x00c0, 0x333f: 0x00c0,
// Block 0xcd, offset 0x3340
0x3340: 0x00c0, 0x3341: 0x00c0, 0x3342: 0x00c0, 0x3343: 0x00c0, 0x3344: 0x00c0, 0x3345: 0x00c0,
0x3346: 0x00c0, 0x3347: 0x00c0, 0x3348: 0x00c0, 0x3349: 0x00c0, 0x334a: 0x00c0, 0x334b: 0x00c0,
0x334c: 0x00c0, 0x334d: 0x00c0, 0x334e: 0x00c0, 0x334f: 0x00c0, 0x3350: 0x00c0, 0x3351: 0x00c0,
0x3352: 0x00c0, 0x3353: 0x00c0, 0x3354: 0x00c0, 0x3355: 0x00c0, 0x3357: 0x0080,
0x3358: 0x0080, 0x3359: 0x0080, 0x335a: 0x0080, 0x335b: 0x0080, 0x335c: 0x0080, 0x335d: 0x0080,
0x335e: 0x0080, 0x335f: 0x0080, 0x3360: 0x00c0, 0x3361: 0x00c0, 0x3362: 0x00c0, 0x3363: 0x00c0,
0x3364: 0x00c0, 0x3365: 0x00c0, 0x3366: 0x00c0, 0x3367: 0x00c0, 0x3368: 0x00c0, 0x3369: 0x00c0,
0x336a: 0x00c0, 0x336b: 0x00c0, 0x336c: 0x00c0, 0x336d: 0x00c0, 0x336e: 0x00c0, 0x336f: 0x00c0,
0x3370: 0x00c0, 0x3371: 0x00c0, 0x3372: 0x00c0, 0x3373: 0x00c0, 0x3374: 0x00c0, 0x3375: 0x00c0,
0x3376: 0x00c0, 0x3377: 0x0080, 0x3378: 0x0080, 0x3379: 0x0080, 0x337a: 0x0080, 0x337b: 0x0080,
0x337c: 0x0080, 0x337d: 0x0080, 0x337e: 0x0080, 0x337f: 0x0080,
// Block 0xce, offset 0x3380
0x3380: 0x00c0, 0x3381: 0x00c0, 0x3382: 0x00c0, 0x3383: 0x00c0, 0x3384: 0x00c0, 0x3385: 0x00c0,
0x3386: 0x00c0, 0x3387: 0x00c0, 0x3388: 0x00c0, 0x3389: 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,
0x33a7: 0x0080, 0x33a8: 0x0080, 0x33a9: 0x0080,
0x33aa: 0x0080, 0x33ab: 0x0080, 0x33ac: 0x0080, 0x33ad: 0x0080, 0x33ae: 0x0080, 0x33af: 0x0080,
// Block 0xcf, offset 0x33c0
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, 0x33f4: 0x00c0, 0x33f5: 0x00c0,
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: 0x0080, 0x3417: 0x0080,
0x3418: 0x0080, 0x3419: 0x0080, 0x341a: 0x0080, 0x341b: 0x0080,
0x341f: 0x0080, 0x3420: 0x00c0, 0x3421: 0x00c0, 0x3422: 0x00c0, 0x3423: 0x00c0,
0x3424: 0x00c0, 0x3425: 0x00c0, 0x3426: 0x00c0, 0x3427: 0x00c0, 0x3428: 0x00c0, 0x3429: 0x00c0,
0x342a: 0x00c0, 0x342b: 0x00c0, 0x342c: 0x00c0, 0x342d: 0x00c0, 0x342e: 0x00c0, 0x342f: 0x00c0,
0x3430: 0x00c0, 0x3431: 0x00c0, 0x3432: 0x00c0, 0x3433: 0x00c0, 0x3434: 0x00c0, 0x3435: 0x00c0,
0x3436: 0x00c0, 0x3437: 0x00c0, 0x3438: 0x00c0, 0x3439: 0x00c0,
0x343f: 0x0080,
// Block 0xd1, offset 0x3440
0x3440: 0x00c0, 0x3441: 0x00c0, 0x3442: 0x00c0, 0x3443: 0x00c0, 0x3444: 0x00c0, 0x3445: 0x00c0,
0x3446: 0x00c0, 0x3447: 0x00c0, 0x3448: 0x00c0, 0x3449: 0x00c0, 0x344a: 0x00c0, 0x344b: 0x00c0,
0x344c: 0x00c0, 0x344d: 0x00c0, 0x344e: 0x00c0, 0x344f: 0x00c0, 0x3450: 0x00c0, 0x3451: 0x00c0,
0x3452: 0x00c0, 0x3453: 0x00c0, 0x3454: 0x00c0, 0x3455: 0x00c0, 0x3456: 0x00c0, 0x3457: 0x00c0,
0x3458: 0x00c0, 0x3459: 0x00c0,
// 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: 0x00c0, 0x3497: 0x00c0,
0x3498: 0x00c0, 0x3499: 0x00c0, 0x349a: 0x00c0, 0x349b: 0x00c0, 0x349c: 0x00c0, 0x349d: 0x00c0,
0x349e: 0x00c0, 0x349f: 0x00c0, 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,
0x34bc: 0x0080, 0x34bd: 0x0080, 0x34be: 0x00c0, 0x34bf: 0x00c0,
// Block 0xd3, offset 0x34c0
0x34c0: 0x0080, 0x34c1: 0x0080, 0x34c2: 0x0080, 0x34c3: 0x0080, 0x34c4: 0x0080, 0x34c5: 0x0080,
0x34c6: 0x0080, 0x34c7: 0x0080, 0x34c8: 0x0080, 0x34c9: 0x0080, 0x34ca: 0x0080, 0x34cb: 0x0080,
0x34cc: 0x0080, 0x34cd: 0x0080, 0x34ce: 0x0080, 0x34cf: 0x0080,
0x34d2: 0x0080, 0x34d3: 0x0080, 0x34d4: 0x0080, 0x34d5: 0x0080, 0x34d6: 0x0080, 0x34d7: 0x0080,
0x34d8: 0x0080, 0x34d9: 0x0080, 0x34da: 0x0080, 0x34db: 0x0080, 0x34dc: 0x0080, 0x34dd: 0x0080,
0x34de: 0x0080, 0x34df: 0x0080, 0x34e0: 0x0080, 0x34e1: 0x0080, 0x34e2: 0x0080, 0x34e3: 0x0080,
0x34e4: 0x0080, 0x34e5: 0x0080, 0x34e6: 0x0080, 0x34e7: 0x0080, 0x34e8: 0x0080, 0x34e9: 0x0080,
0x34ea: 0x0080, 0x34eb: 0x0080, 0x34ec: 0x0080, 0x34ed: 0x0080, 0x34ee: 0x0080, 0x34ef: 0x0080,
0x34f0: 0x0080, 0x34f1: 0x0080, 0x34f2: 0x0080, 0x34f3: 0x0080, 0x34f4: 0x0080, 0x34f5: 0x0080,
0x34f6: 0x0080, 0x34f7: 0x0080, 0x34f8: 0x0080, 0x34f9: 0x0080, 0x34fa: 0x0080, 0x34fb: 0x0080,
0x34fc: 0x0080, 0x34fd: 0x0080, 0x34fe: 0x0080, 0x34ff: 0x0080,
// 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
0x37c0: 0x00c0, 0x37c1: 0x00c0, 0x37c2: 0x00c0, 0x37c3: 0x00c0, 0x37c4: 0x00c0, 0x37c5: 0x00c0,
0x37c6: 0x00c0, 0x37c7: 0x00c0, 0x37c8: 0x00c0, 0x37c9: 0x00c0, 0x37ca: 0x00c0, 0x37cb: 0x00c0,
0x37cc: 0x00c0, 0x37cd: 0x00c0, 0x37ce: 0x00c0, 0x37cf: 0x00c0, 0x37d0: 0x00c0, 0x37d1: 0x00c0,
0x37d2: 0x00c0, 0x37d3: 0x00c0, 0x37d4: 0x00c0, 0x37d5: 0x00c0, 0x37d6: 0x00c0, 0x37d7: 0x00c0,
0x37d8: 0x00c0, 0x37d9: 0x00c0, 0x37da: 0x00c0, 0x37db: 0x00c0, 0x37dc: 0x00c0, 0x37dd: 0x00c0,
0x37de: 0x00c0, 0x37df: 0x00c0, 0x37e0: 0x00c0, 0x37e1: 0x00c0, 0x37e2: 0x00c0, 0x37e3: 0x00c0,
0x37e4: 0x00c0, 0x37e5: 0x00c0, 0x37e9: 0x00c3,
0x37ea: 0x00c3, 0x37eb: 0x00c3, 0x37ec: 0x00c3, 0x37ed: 0x00c3, 0x37ee: 0x0080, 0x37ef: 0x00c0,
0x37f0: 0x00c0, 0x37f1: 0x00c0, 0x37f2: 0x00c0, 0x37f3: 0x00c0, 0x37f4: 0x00c0, 0x37f5: 0x00c0,
0x37f6: 0x00c0, 0x37f7: 0x00c0, 0x37f8: 0x00c0, 0x37f9: 0x00c0, 0x37fa: 0x00c0, 0x37fb: 0x00c0,
0x37fc: 0x00c0, 0x37fd: 0x00c0, 0x37fe: 0x00c0, 0x37ff: 0x00c0,
// Block 0xe0, offset 0x3800
0x3800: 0x00c0, 0x3801: 0x00c0, 0x3802: 0x00c0, 0x3803: 0x00c0, 0x3804: 0x00c0, 0x3805: 0x00c0,
0x380e: 0x0080, 0x380f: 0x0080,
// Block 0xe1, offset 0x3840
0x3860: 0x0080, 0x3861: 0x0080, 0x3862: 0x0080, 0x3863: 0x0080,
0x3864: 0x0080, 0x3865: 0x0080, 0x3866: 0x0080, 0x3867: 0x0080, 0x3868: 0x0080, 0x3869: 0x0080,
0x386a: 0x0080, 0x386b: 0x0080, 0x386c: 0x0080, 0x386d: 0x0080, 0x386e: 0x0080, 0x386f: 0x0080,
0x3870: 0x0080, 0x3871: 0x0080, 0x3872: 0x0080, 0x3873: 0x0080, 0x3874: 0x0080, 0x3875: 0x0080,
0x3876: 0x0080, 0x3877: 0x0080, 0x3878: 0x0080, 0x3879: 0x0080, 0x387a: 0x0080, 0x387b: 0x0080,
0x387c: 0x0080, 0x387d: 0x0080, 0x387e: 0x0080,
// 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: 0x00c0,
0x389e: 0x00c0, 0x389f: 0x00c0, 0x38a0: 0x00c0, 0x38a1: 0x00c0, 0x38a2: 0x00c0, 0x38a3: 0x00c0,
0x38a4: 0x00c0, 0x38a5: 0x00c0, 0x38a6: 0x00c0, 0x38a7: 0x00c0, 0x38a8: 0x00c0, 0x38a9: 0x00c0,
0x38ab: 0x00c3, 0x38ac: 0x00c3, 0x38ad: 0x0080,
0x38b0: 0x00c0, 0x38b1: 0x00c0,
// Block 0xe3, offset 0x38c0
0x38c2: 0x00c4, 0x38c3: 0x00c2, 0x38c4: 0x00c2, 0x38c5: 0x00c0,
0x38c6: 0x00c2, 0x38c7: 0x00c2,
0x38d0: 0x0080, 0x38d1: 0x0080,
0x38d2: 0x0080, 0x38d3: 0x0080, 0x38d4: 0x0080, 0x38d5: 0x0080, 0x38d6: 0x0080, 0x38d7: 0x0080,
0x38d8: 0x0080,
0x38fa: 0x00c3, 0x38fb: 0x00c3,
0x38fc: 0x00c3, 0x38fd: 0x00c3, 0x38fe: 0x00c3, 0x38ff: 0x00c3,
// Block 0xe4, offset 0x3900
0x3900: 0x00c0, 0x3901: 0x00c0, 0x3902: 0x00c0, 0x3903: 0x00c0, 0x3904: 0x00c0, 0x3905: 0x00c0,
0x3906: 0x00c0, 0x3907: 0x00c0, 0x3908: 0x00c0, 0x3909: 0x00c0, 0x390a: 0x00c0, 0x390b: 0x00c0,
0x390c: 0x00c0, 0x390d: 0x00c0, 0x390e: 0x00c0, 0x390f: 0x00c0, 0x3910: 0x00c0, 0x3911: 0x00c0,
0x3912: 0x00c0, 0x3913: 0x00c0, 0x3914: 0x00c0, 0x3915: 0x00c0, 0x3916: 0x00c0, 0x3917: 0x00c0,
0x3918: 0x00c0, 0x3919: 0x00c0, 0x391a: 0x00c0, 0x391b: 0x00c0, 0x391c: 0x00c0, 0x391d: 0x0080,
0x391e: 0x0080, 0x391f: 0x0080, 0x3920: 0x0080, 0x3921: 0x0080, 0x3922: 0x0080, 0x3923: 0x0080,
0x3924: 0x0080, 0x3925: 0x0080, 0x3926: 0x0080, 0x3927: 0x00c0,
0x3930: 0x00c2, 0x3931: 0x00c2, 0x3932: 0x00c2, 0x3933: 0x00c4, 0x3934: 0x00c2, 0x3935: 0x00c2,
0x3936: 0x00c2, 0x3937: 0x00c2, 0x3938: 0x00c2, 0x3939: 0x00c2, 0x393a: 0x00c2, 0x393b: 0x00c2,
0x393c: 0x00c2, 0x393d: 0x00c2, 0x393e: 0x00c2, 0x393f: 0x00c2,
// Block 0xe5, offset 0x3940
0x3940: 0x00c2, 0x3941: 0x00c2, 0x3942: 0x00c2, 0x3943: 0x00c2, 0x3944: 0x00c2, 0x3945: 0x00c0,
0x3946: 0x00c3, 0x3947: 0x00c3, 0x3948: 0x00c3, 0x3949: 0x00c3, 0x394a: 0x00c3, 0x394b: 0x00c3,
0x394c: 0x00c3, 0x394d: 0x00c3, 0x394e: 0x00c3, 0x394f: 0x00c3, 0x3950: 0x00c3, 0x3951: 0x0082,
0x3952: 0x0082, 0x3953: 0x0082, 0x3954: 0x0084, 0x3955: 0x0080, 0x3956: 0x0080, 0x3957: 0x0080,
0x3958: 0x0080, 0x3959: 0x0080,
0x3970: 0x00c2, 0x3971: 0x00c2, 0x3972: 0x00c2, 0x3973: 0x00c2, 0x3974: 0x00c4, 0x3975: 0x00c4,
0x3976: 0x00c2, 0x3977: 0x00c2, 0x3978: 0x00c2, 0x3979: 0x00c2, 0x397a: 0x00c2, 0x397b: 0x00c2,
0x397c: 0x00c2, 0x397d: 0x00c2, 0x397e: 0x00c2, 0x397f: 0x00c2,
// Block 0xe6, offset 0x3980
0x3980: 0x00c2, 0x3981: 0x00c2, 0x3982: 0x00c3, 0x3983: 0x00c3, 0x3984: 0x00c3, 0x3985: 0x00c3,
0x3986: 0x0080, 0x3987: 0x0080, 0x3988: 0x0080, 0x3989: 0x0080,
0x39b0: 0x00c2, 0x39b1: 0x00c0, 0x39b2: 0x00c2, 0x39b3: 0x00c2, 0x39b4: 0x00c4, 0x39b5: 0x00c4,
0x39b6: 0x00c4, 0x39b7: 0x00c0, 0x39b8: 0x00c2, 0x39b9: 0x00c4, 0x39ba: 0x00c4, 0x39bb: 0x00c2,
0x39bc: 0x00c2, 0x39bd: 0x00c4, 0x39be: 0x00c2, 0x39bf: 0x00c2,
// Block 0xe7, offset 0x39c0
0x39c0: 0x00c0, 0x39c1: 0x00c2, 0x39c2: 0x00c4, 0x39c3: 0x00c4, 0x39c4: 0x00c2, 0x39c5: 0x0080,
0x39c6: 0x0080, 0x39c7: 0x0080, 0x39c8: 0x0080, 0x39c9: 0x0084, 0x39ca: 0x0082, 0x39cb: 0x0081,
0x39e0: 0x00c0, 0x39e1: 0x00c0, 0x39e2: 0x00c0, 0x39e3: 0x00c0,
0x39e4: 0x00c0, 0x39e5: 0x00c0, 0x39e6: 0x00c0, 0x39e7: 0x00c0, 0x39e8: 0x00c0, 0x39e9: 0x00c0,
0x39ea: 0x00c0, 0x39eb: 0x00c0, 0x39ec: 0x00c0, 0x39ed: 0x00c0, 0x39ee: 0x00c0, 0x39ef: 0x00c0,
0x39f0: 0x00c0, 0x39f1: 0x00c0, 0x39f2: 0x00c0, 0x39f3: 0x00c0, 0x39f4: 0x00c0, 0x39f5: 0x00c0,
0x39f6: 0x00c0,
// Block 0xe8, offset 0x3a00
0x3a00: 0x00c0, 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: 0x00c0, 0x3a34: 0x00c0, 0x3a35: 0x00c0,
0x3a36: 0x00c0, 0x3a37: 0x00c0, 0x3a38: 0x00c3, 0x3a39: 0x00c3, 0x3a3a: 0x00c3, 0x3a3b: 0x00c3,
0x3a3c: 0x00c3, 0x3a3d: 0x00c3, 0x3a3e: 0x00c3, 0x3a3f: 0x00c3,
// Block 0xe9, offset 0x3a40
0x3a40: 0x00c3, 0x3a41: 0x00c3, 0x3a42: 0x00c3, 0x3a43: 0x00c3, 0x3a44: 0x00c3, 0x3a45: 0x00c3,
0x3a46: 0x00c6, 0x3a47: 0x0080, 0x3a48: 0x0080, 0x3a49: 0x0080, 0x3a4a: 0x0080, 0x3a4b: 0x0080,
0x3a4c: 0x0080, 0x3a4d: 0x0080,
0x3a52: 0x0080, 0x3a53: 0x0080, 0x3a54: 0x0080, 0x3a55: 0x0080, 0x3a56: 0x0080, 0x3a57: 0x0080,
0x3a58: 0x0080, 0x3a59: 0x0080, 0x3a5a: 0x0080, 0x3a5b: 0x0080, 0x3a5c: 0x0080, 0x3a5d: 0x0080,
0x3a5e: 0x0080, 0x3a5f: 0x0080, 0x3a60: 0x0080, 0x3a61: 0x0080, 0x3a62: 0x0080, 0x3a63: 0x0080,
0x3a64: 0x0080, 0x3a65: 0x0080, 0x3a66: 0x00c0, 0x3a67: 0x00c0, 0x3a68: 0x00c0, 0x3a69: 0x00c0,
0x3a6a: 0x00c0, 0x3a6b: 0x00c0, 0x3a6c: 0x00c0, 0x3a6d: 0x00c0, 0x3a6e: 0x00c0, 0x3a6f: 0x00c0,
0x3a70: 0x00c6, 0x3a71: 0x00c0, 0x3a72: 0x00c0, 0x3a73: 0x00c3, 0x3a74: 0x00c3, 0x3a75: 0x00c0,
0x3a7f: 0x00c6,
// Block 0xea, offset 0x3a80
0x3a80: 0x00c3, 0x3a81: 0x00c3, 0x3a82: 0x00c0, 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: 0x00c0, 0x3aa8: 0x00c0, 0x3aa9: 0x00c0,
0x3aaa: 0x00c0, 0x3aab: 0x00c0, 0x3aac: 0x00c0, 0x3aad: 0x00c0, 0x3aae: 0x00c0, 0x3aaf: 0x00c0,
0x3ab0: 0x00c0, 0x3ab1: 0x00c0, 0x3ab2: 0x00c0, 0x3ab3: 0x00c3, 0x3ab4: 0x00c3, 0x3ab5: 0x00c3,
0x3ab6: 0x00c3, 0x3ab7: 0x00c0, 0x3ab8: 0x00c0, 0x3ab9: 0x00c6, 0x3aba: 0x00c3, 0x3abb: 0x0080,
0x3abc: 0x0080, 0x3abd: 0x0040, 0x3abe: 0x0080, 0x3abf: 0x0080,
// Block 0xeb, offset 0x3ac0
0x3ac0: 0x0080, 0x3ac1: 0x0080, 0x3ac2: 0x00c3,
0x3acd: 0x0040, 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,
0x3af0: 0x00c0, 0x3af1: 0x00c0, 0x3af2: 0x00c0, 0x3af3: 0x00c0, 0x3af4: 0x00c0, 0x3af5: 0x00c0,
0x3af6: 0x00c0, 0x3af7: 0x00c0, 0x3af8: 0x00c0, 0x3af9: 0x00c0,
// Block 0xec, offset 0x3b00
0x3b00: 0x00c3, 0x3b01: 0x00c3, 0x3b02: 0x00c3, 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: 0x00c3, 0x3b28: 0x00c3, 0x3b29: 0x00c3,
0x3b2a: 0x00c3, 0x3b2b: 0x00c3, 0x3b2c: 0x00c0, 0x3b2d: 0x00c3, 0x3b2e: 0x00c3, 0x3b2f: 0x00c3,
0x3b30: 0x00c3, 0x3b31: 0x00c3, 0x3b32: 0x00c3, 0x3b33: 0x00c6, 0x3b34: 0x00c6,
0x3b36: 0x00c0, 0x3b37: 0x00c0, 0x3b38: 0x00c0, 0x3b39: 0x00c0, 0x3b3a: 0x00c0, 0x3b3b: 0x00c0,
0x3b3c: 0x00c0, 0x3b3d: 0x00c0, 0x3b3e: 0x00c0, 0x3b3f: 0x00c0,
// Block 0xed, offset 0x3b40
0x3b40: 0x0080, 0x3b41: 0x0080, 0x3b42: 0x0080, 0x3b43: 0x0080, 0x3b44: 0x00c0, 0x3b45: 0x00c0,
0x3b46: 0x00c0, 0x3b47: 0x00c0,
0x3b50: 0x00c0, 0x3b51: 0x00c0,
0x3b52: 0x00c0, 0x3b53: 0x00c0, 0x3b54: 0x00c0, 0x3b55: 0x00c0, 0x3b56: 0x00c0, 0x3b57: 0x00c0,
0x3b58: 0x00c0, 0x3b59: 0x00c0, 0x3b5a: 0x00c0, 0x3b5b: 0x00c0, 0x3b5c: 0x00c0, 0x3b5d: 0x00c0,
0x3b5e: 0x00c0, 0x3b5f: 0x00c0, 0x3b60: 0x00c0, 0x3b61: 0x00c0, 0x3b62: 0x00c0, 0x3b63: 0x00c0,
0x3b64: 0x00c0, 0x3b65: 0x00c0, 0x3b66: 0x00c0, 0x3b67: 0x00c0, 0x3b68: 0x00c0, 0x3b69: 0x00c0,
0x3b6a: 0x00c0, 0x3b6b: 0x00c0, 0x3b6c: 0x00c0, 0x3b6d: 0x00c0, 0x3b6e: 0x00c0, 0x3b6f: 0x00c0,
0x3b70: 0x00c0, 0x3b71: 0x00c0, 0x3b72: 0x00c0, 0x3b73: 0x00c3, 0x3b74: 0x0080, 0x3b75: 0x0080,
0x3b76: 0x00c0,
// Block 0xee, offset 0x3b80
0x3b80: 0x00c3, 0x3b81: 0x00c3, 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,
0x3b92: 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: 0x00c0,
0x3bb0: 0x00c0, 0x3bb1: 0x00c0, 0x3bb2: 0x00c0, 0x3bb3: 0x00c0, 0x3bb4: 0x00c0, 0x3bb5: 0x00c0,
0x3bb6: 0x00c3, 0x3bb7: 0x00c3, 0x3bb8: 0x00c3, 0x3bb9: 0x00c3, 0x3bba: 0x00c3, 0x3bbb: 0x00c3,
0x3bbc: 0x00c3, 0x3bbd: 0x00c3, 0x3bbe: 0x00c3, 0x3bbf: 0x00c0,
// Block 0xef, offset 0x3bc0
0x3bc0: 0x00c5, 0x3bc1: 0x00c0, 0x3bc2: 0x00c0, 0x3bc3: 0x00c0, 0x3bc4: 0x00c0, 0x3bc5: 0x0080,
0x3bc6: 0x0080, 0x3bc7: 0x0080, 0x3bc8: 0x0080, 0x3bc9: 0x00c3, 0x3bca: 0x00c3, 0x3bcb: 0x00c3,
0x3bcc: 0x00c3, 0x3bcd: 0x0080, 0x3bce: 0x00c0, 0x3bcf: 0x00c3, 0x3bd0: 0x00c0, 0x3bd1: 0x00c0,
0x3bd2: 0x00c0, 0x3bd3: 0x00c0, 0x3bd4: 0x00c0, 0x3bd5: 0x00c0, 0x3bd6: 0x00c0, 0x3bd7: 0x00c0,
0x3bd8: 0x00c0, 0x3bd9: 0x00c0, 0x3bda: 0x00c0, 0x3bdb: 0x0080, 0x3bdc: 0x00c0, 0x3bdd: 0x0080,
0x3bde: 0x0080, 0x3bdf: 0x0080, 0x3be1: 0x0080, 0x3be2: 0x0080, 0x3be3: 0x0080,
0x3be4: 0x0080, 0x3be5: 0x0080, 0x3be6: 0x0080, 0x3be7: 0x0080, 0x3be8: 0x0080, 0x3be9: 0x0080,
0x3bea: 0x0080, 0x3beb: 0x0080, 0x3bec: 0x0080, 0x3bed: 0x0080, 0x3bee: 0x0080, 0x3bef: 0x0080,
0x3bf0: 0x0080, 0x3bf1: 0x0080, 0x3bf2: 0x0080, 0x3bf3: 0x0080, 0x3bf4: 0x0080,
// Block 0xf0, offset 0x3c00
0x3c00: 0x00c0, 0x3c01: 0x00c0, 0x3c02: 0x00c0, 0x3c03: 0x00c0, 0x3c04: 0x00c0, 0x3c05: 0x00c0,
0x3c06: 0x00c0, 0x3c07: 0x00c0, 0x3c08: 0x00c0, 0x3c09: 0x00c0, 0x3c0a: 0x00c0, 0x3c0b: 0x00c0,
0x3c0c: 0x00c0, 0x3c0d: 0x00c0, 0x3c0e: 0x00c0, 0x3c0f: 0x00c0, 0x3c10: 0x00c0, 0x3c11: 0x00c0,
0x3c13: 0x00c0, 0x3c14: 0x00c0, 0x3c15: 0x00c0, 0x3c16: 0x00c0, 0x3c17: 0x00c0,
0x3c18: 0x00c0, 0x3c19: 0x00c0, 0x3c1a: 0x00c0, 0x3c1b: 0x00c0, 0x3c1c: 0x00c0, 0x3c1d: 0x00c0,
0x3c1e: 0x00c0, 0x3c1f: 0x00c0, 0x3c20: 0x00c0, 0x3c21: 0x00c0, 0x3c22: 0x00c0, 0x3c23: 0x00c0,
0x3c24: 0x00c0, 0x3c25: 0x00c0, 0x3c26: 0x00c0, 0x3c27: 0x00c0, 0x3c28: 0x00c0, 0x3c29: 0x00c0,
0x3c2a: 0x00c0, 0x3c2b: 0x00c0, 0x3c2c: 0x00c0, 0x3c2d: 0x00c0, 0x3c2e: 0x00c0, 0x3c2f: 0x00c3,
0x3c30: 0x00c3, 0x3c31: 0x00c3, 0x3c32: 0x00c0, 0x3c33: 0x00c0, 0x3c34: 0x00c3, 0x3c35: 0x00c5,
0x3c36: 0x00c3, 0x3c37: 0x00c3, 0x3c38: 0x0080, 0x3c39: 0x0080, 0x3c3a: 0x0080, 0x3c3b: 0x0080,
0x3c3c: 0x0080, 0x3c3d: 0x0080, 0x3c3e: 0x00c3, 0x3c3f: 0x00c0,
// Block 0xf1, offset 0x3c40
0x3c40: 0x00c0, 0x3c41: 0x00c3,
// Block 0xf2, offset 0x3c80
0x3c80: 0x00c0, 0x3c81: 0x00c0, 0x3c82: 0x00c0, 0x3c83: 0x00c0, 0x3c84: 0x00c0, 0x3c85: 0x00c0,
0x3c86: 0x00c0, 0x3c88: 0x00c0, 0x3c8a: 0x00c0, 0x3c8b: 0x00c0,
0x3c8c: 0x00c0, 0x3c8d: 0x00c0, 0x3c8f: 0x00c0, 0x3c90: 0x00c0, 0x3c91: 0x00c0,
0x3c92: 0x00c0, 0x3c93: 0x00c0, 0x3c94: 0x00c0, 0x3c95: 0x00c0, 0x3c96: 0x00c0, 0x3c97: 0x00c0,
0x3c98: 0x00c0, 0x3c99: 0x00c0, 0x3c9a: 0x00c0, 0x3c9b: 0x00c0, 0x3c9c: 0x00c0, 0x3c9d: 0x00c0,
0x3c9f: 0x00c0, 0x3ca0: 0x00c0, 0x3ca1: 0x00c0, 0x3ca2: 0x00c0, 0x3ca3: 0x00c0,
0x3ca4: 0x00c0, 0x3ca5: 0x00c0, 0x3ca6: 0x00c0, 0x3ca7: 0x00c0, 0x3ca8: 0x00c0, 0x3ca9: 0x0080,
0x3cb0: 0x00c0, 0x3cb1: 0x00c0, 0x3cb2: 0x00c0, 0x3cb3: 0x00c0, 0x3cb4: 0x00c0, 0x3cb5: 0x00c0,
0x3cb6: 0x00c0, 0x3cb7: 0x00c0, 0x3cb8: 0x00c0, 0x3cb9: 0x00c0, 0x3cba: 0x00c0, 0x3cbb: 0x00c0,
0x3cbc: 0x00c0, 0x3cbd: 0x00c0, 0x3cbe: 0x00c0, 0x3cbf: 0x00c0,
// Block 0xf3, offset 0x3cc0
0x3cc0: 0x00c0, 0x3cc1: 0x00c0, 0x3cc2: 0x00c0, 0x3cc3: 0x00c0, 0x3cc4: 0x00c0, 0x3cc5: 0x00c0,
0x3cc6: 0x00c0, 0x3cc7: 0x00c0, 0x3cc8: 0x00c0, 0x3cc9: 0x00c0, 0x3cca: 0x00c0, 0x3ccb: 0x00c0,
0x3ccc: 0x00c0, 0x3ccd: 0x00c0, 0x3cce: 0x00c0, 0x3ccf: 0x00c0, 0x3cd0: 0x00c0, 0x3cd1: 0x00c0,
0x3cd2: 0x00c0, 0x3cd3: 0x00c0, 0x3cd4: 0x00c0, 0x3cd5: 0x00c0, 0x3cd6: 0x00c0, 0x3cd7: 0x00c0,
0x3cd8: 0x00c0, 0x3cd9: 0x00c0, 0x3cda: 0x00c0, 0x3cdb: 0x00c0, 0x3cdc: 0x00c0, 0x3cdd: 0x00c0,
0x3cde: 0x00c0, 0x3cdf: 0x00c3, 0x3ce0: 0x00c0, 0x3ce1: 0x00c0, 0x3ce2: 0x00c0, 0x3ce3: 0x00c3,
0x3ce4: 0x00c3, 0x3ce5: 0x00c3, 0x3ce6: 0x00c3, 0x3ce7: 0x00c3, 0x3ce8: 0x00c3, 0x3ce9: 0x00c3,
0x3cea: 0x00c6,
0x3cf0: 0x00c0, 0x3cf1: 0x00c0, 0x3cf2: 0x00c0, 0x3cf3: 0x00c0, 0x3cf4: 0x00c0, 0x3cf5: 0x00c0,
0x3cf6: 0x00c0, 0x3cf7: 0x00c0, 0x3cf8: 0x00c0, 0x3cf9: 0x00c0,
// Block 0xf4, offset 0x3d00
0x3d00: 0x00c3, 0x3d01: 0x00c3, 0x3d02: 0x00c0, 0x3d03: 0x00c0, 0x3d05: 0x00c0,
0x3d06: 0x00c0, 0x3d07: 0x00c0, 0x3d08: 0x00c0, 0x3d09: 0x00c0, 0x3d0a: 0x00c0, 0x3d0b: 0x00c0,
0x3d0c: 0x00c0, 0x3d0f: 0x00c0, 0x3d10: 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,
0x3d2a: 0x00c0, 0x3d2b: 0x00c0, 0x3d2c: 0x00c0, 0x3d2d: 0x00c0, 0x3d2e: 0x00c0, 0x3d2f: 0x00c0,
0x3d30: 0x00c0, 0x3d32: 0x00c0, 0x3d33: 0x00c0, 0x3d35: 0x00c0,
0x3d36: 0x00c0, 0x3d37: 0x00c0, 0x3d38: 0x00c0, 0x3d39: 0x00c0, 0x3d3b: 0x00c3,
0x3d3c: 0x00c3, 0x3d3d: 0x00c0, 0x3d3e: 0x00c0, 0x3d3f: 0x00c0,
// Block 0xf5, offset 0x3d40
0x3d40: 0x00c3, 0x3d41: 0x00c0, 0x3d42: 0x00c0, 0x3d43: 0x00c0, 0x3d44: 0x00c0,
0x3d47: 0x00c0, 0x3d48: 0x00c0, 0x3d4b: 0x00c0,
0x3d4c: 0x00c0, 0x3d4d: 0x00c5, 0x3d50: 0x00c0,
0x3d57: 0x00c0,
0x3d5d: 0x00c0,
0x3d5e: 0x00c0, 0x3d5f: 0x00c0, 0x3d60: 0x00c0, 0x3d61: 0x00c0, 0x3d62: 0x00c0, 0x3d63: 0x00c0,
0x3d66: 0x00c3, 0x3d67: 0x00c3, 0x3d68: 0x00c3, 0x3d69: 0x00c3,
0x3d6a: 0x00c3, 0x3d6b: 0x00c3, 0x3d6c: 0x00c3,
0x3d70: 0x00c3, 0x3d71: 0x00c3, 0x3d72: 0x00c3, 0x3d73: 0x00c3, 0x3d74: 0x00c3,
// Block 0xf6, offset 0x3d80
0x3d80: 0x00c0, 0x3d81: 0x00c0, 0x3d82: 0x00c0, 0x3d83: 0x00c0, 0x3d84: 0x00c0, 0x3d85: 0x00c0,
0x3d86: 0x00c0, 0x3d87: 0x00c0, 0x3d88: 0x00c0, 0x3d89: 0x00c0, 0x3d8b: 0x00c0,
0x3d8e: 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: 0x00c0, 0x3db4: 0x00c0, 0x3db5: 0x00c0,
0x3db7: 0x00c0, 0x3db8: 0x00c0, 0x3db9: 0x00c0, 0x3dba: 0x00c0, 0x3dbb: 0x00c3,
0x3dbc: 0x00c3, 0x3dbd: 0x00c3, 0x3dbe: 0x00c3, 0x3dbf: 0x00c3,
// Block 0xf7, offset 0x3dc0
0x3dc0: 0x00c3, 0x3dc2: 0x00c0, 0x3dc5: 0x00c0,
0x3dc7: 0x00c0, 0x3dc8: 0x00c0, 0x3dc9: 0x00c0, 0x3dca: 0x00c0,
0x3dcc: 0x00c0, 0x3dcd: 0x00c0, 0x3dce: 0x00c6, 0x3dcf: 0x00c5, 0x3dd0: 0x00c6, 0x3dd1: 0x00c0,
0x3dd2: 0x00c3, 0x3dd3: 0x00c0, 0x3dd4: 0x0080, 0x3dd5: 0x0080, 0x3dd7: 0x0080,
0x3dd8: 0x0080,
0x3de1: 0x00c3, 0x3de2: 0x00c3,
// 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: 0x00c0, 0x3e33: 0x00c0, 0x3e34: 0x00c0, 0x3e35: 0x00c0,
0x3e36: 0x00c0, 0x3e37: 0x00c0, 0x3e38: 0x00c3, 0x3e39: 0x00c3, 0x3e3a: 0x00c3, 0x3e3b: 0x00c3,
0x3e3c: 0x00c3, 0x3e3d: 0x00c3, 0x3e3e: 0x00c3, 0x3e3f: 0x00c3,
// Block 0xf9, offset 0x3e40
0x3e40: 0x00c0, 0x3e41: 0x00c0, 0x3e42: 0x00c6, 0x3e43: 0x00c3, 0x3e44: 0x00c3, 0x3e45: 0x00c0,
0x3e46: 0x00c3, 0x3e47: 0x00c0, 0x3e48: 0x00c0, 0x3e49: 0x00c0, 0x3e4a: 0x00c0, 0x3e4b: 0x0080,
0x3e4c: 0x0080, 0x3e4d: 0x0080, 0x3e4e: 0x0080, 0x3e4f: 0x0080, 0x3e50: 0x00c0, 0x3e51: 0x00c0,
0x3e52: 0x00c0, 0x3e53: 0x00c0, 0x3e54: 0x00c0, 0x3e55: 0x00c0, 0x3e56: 0x00c0, 0x3e57: 0x00c0,
0x3e58: 0x00c0, 0x3e59: 0x00c0, 0x3e5a: 0x0080, 0x3e5b: 0x0080, 0x3e5d: 0x0080,
0x3e5e: 0x00c3, 0x3e5f: 0x00c0, 0x3e60: 0x00c0, 0x3e61: 0x00c0,
// 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: 0x00c0, 0x3eba: 0x00c3, 0x3ebb: 0x00c0,
0x3ebc: 0x00c0, 0x3ebd: 0x00c0, 0x3ebe: 0x00c0, 0x3ebf: 0x00c3,
// Block 0xfb, offset 0x3ec0
0x3ec0: 0x00c3, 0x3ec1: 0x00c0, 0x3ec2: 0x00c6, 0x3ec3: 0x00c3, 0x3ec4: 0x00c0, 0x3ec5: 0x00c0,
0x3ec6: 0x0080, 0x3ec7: 0x00c0,
0x3ed0: 0x00c0, 0x3ed1: 0x00c0,
0x3ed2: 0x00c0, 0x3ed3: 0x00c0, 0x3ed4: 0x00c0, 0x3ed5: 0x00c0, 0x3ed6: 0x00c0, 0x3ed7: 0x00c0,
0x3ed8: 0x00c0, 0x3ed9: 0x00c0,
// 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: 0x00c0, 0x3f2c: 0x00c0, 0x3f2d: 0x00c0, 0x3f2e: 0x00c0, 0x3f2f: 0x00c0,
0x3f30: 0x00c0, 0x3f31: 0x00c0, 0x3f32: 0x00c3, 0x3f33: 0x00c3, 0x3f34: 0x00c3, 0x3f35: 0x00c3,
0x3f38: 0x00c0, 0x3f39: 0x00c0, 0x3f3a: 0x00c0, 0x3f3b: 0x00c0,
0x3f3c: 0x00c3, 0x3f3d: 0x00c3, 0x3f3e: 0x00c0, 0x3f3f: 0x00c6,
// Block 0xfd, offset 0x3f40
0x3f40: 0x00c3, 0x3f41: 0x0080, 0x3f42: 0x0080, 0x3f43: 0x0080, 0x3f44: 0x0080, 0x3f45: 0x0080,
0x3f46: 0x0080, 0x3f47: 0x0080, 0x3f48: 0x0080, 0x3f49: 0x0080, 0x3f4a: 0x0080, 0x3f4b: 0x0080,
0x3f4c: 0x0080, 0x3f4d: 0x0080, 0x3f4e: 0x0080, 0x3f4f: 0x0080, 0x3f50: 0x0080, 0x3f51: 0x0080,
0x3f52: 0x0080, 0x3f53: 0x0080, 0x3f54: 0x0080, 0x3f55: 0x0080, 0x3f56: 0x0080, 0x3f57: 0x0080,
0x3f58: 0x00c0, 0x3f59: 0x00c0, 0x3f5a: 0x00c0, 0x3f5b: 0x00c0, 0x3f5c: 0x00c3, 0x3f5d: 0x00c3,
// 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, 0x3f9b: 0x00c0, 0x3f9c: 0x00c0, 0x3f9d: 0x00c0,
0x3f9e: 0x00c0, 0x3f9f: 0x00c0, 0x3fa0: 0x00c0, 0x3fa1: 0x00c0, 0x3fa2: 0x00c0, 0x3fa3: 0x00c0,
0x3fa4: 0x00c0, 0x3fa5: 0x00c0, 0x3fa6: 0x00c0, 0x3fa7: 0x00c0, 0x3fa8: 0x00c0, 0x3fa9: 0x00c0,
0x3faa: 0x00c0, 0x3fab: 0x00c0, 0x3fac: 0x00c0, 0x3fad: 0x00c0, 0x3fae: 0x00c0, 0x3faf: 0x00c0,
0x3fb0: 0x00c0, 0x3fb1: 0x00c0, 0x3fb2: 0x00c0, 0x3fb3: 0x00c3, 0x3fb4: 0x00c3, 0x3fb5: 0x00c3,
0x3fb6: 0x00c3, 0x3fb7: 0x00c3, 0x3fb8: 0x00c3, 0x3fb9: 0x00c3, 0x3fba: 0x00c3, 0x3fbb: 0x00c0,
0x3fbc: 0x00c0, 0x3fbd: 0x00c3, 0x3fbe: 0x00c0, 0x3fbf: 0x00c6,
// Block 0xff, offset 0x3fc0
0x3fc0: 0x00c3, 0x3fc1: 0x0080, 0x3fc2: 0x0080, 0x3fc3: 0x0080, 0x3fc4: 0x00c0,
0x3fd0: 0x00c0, 0x3fd1: 0x00c0,
0x3fd2: 0x00c0, 0x3fd3: 0x00c0, 0x3fd4: 0x00c0, 0x3fd5: 0x00c0, 0x3fd6: 0x00c0, 0x3fd7: 0x00c0,
0x3fd8: 0x00c0, 0x3fd9: 0x00c0,
0x3fe0: 0x0080, 0x3fe1: 0x0080, 0x3fe2: 0x0080, 0x3fe3: 0x0080,
0x3fe4: 0x0080, 0x3fe5: 0x0080, 0x3fe6: 0x0080, 0x3fe7: 0x0080, 0x3fe8: 0x0080, 0x3fe9: 0x0080,
0x3fea: 0x0080, 0x3feb: 0x0080, 0x3fec: 0x0080,
// 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: 0x00c3, 0x402c: 0x00c0, 0x402d: 0x00c3, 0x402e: 0x00c0, 0x402f: 0x00c0,
0x4030: 0x00c3, 0x4031: 0x00c3, 0x4032: 0x00c3, 0x4033: 0x00c3, 0x4034: 0x00c3, 0x4035: 0x00c3,
0x4036: 0x00c5, 0x4037: 0x00c3, 0x4038: 0x00c0, 0x4039: 0x0080,
// Block 0x101, offset 0x4040
0x4040: 0x00c0, 0x4041: 0x00c0, 0x4042: 0x00c0, 0x4043: 0x00c0, 0x4044: 0x00c0, 0x4045: 0x00c0,
0x4046: 0x00c0, 0x4047: 0x00c0, 0x4048: 0x00c0, 0x4049: 0x00c0,
0x4050: 0x00c0, 0x4051: 0x00c0,
0x4052: 0x00c0, 0x4053: 0x00c0, 0x4054: 0x00c0, 0x4055: 0x00c0, 0x4056: 0x00c0, 0x4057: 0x00c0,
0x4058: 0x00c0, 0x4059: 0x00c0, 0x405a: 0x00c0, 0x405b: 0x00c0, 0x405c: 0x00c0, 0x405d: 0x00c0,
0x405e: 0x00c0, 0x405f: 0x00c0, 0x4060: 0x00c0, 0x4061: 0x00c0, 0x4062: 0x00c0, 0x4063: 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, 0x409d: 0x00c3,
0x409e: 0x00c0, 0x409f: 0x00c3, 0x40a0: 0x00c0, 0x40a1: 0x00c0, 0x40a2: 0x00c3, 0x40a3: 0x00c3,
0x40a4: 0x00c3, 0x40a5: 0x00c3, 0x40a6: 0x00c0, 0x40a7: 0x00c3, 0x40a8: 0x00c3, 0x40a9: 0x00c3,
0x40aa: 0x00c3, 0x40ab: 0x00c6,
0x40b0: 0x00c0, 0x40b1: 0x00c0, 0x40b2: 0x00c0, 0x40b3: 0x00c0, 0x40b4: 0x00c0, 0x40b5: 0x00c0,
0x40b6: 0x00c0, 0x40b7: 0x00c0, 0x40b8: 0x00c0, 0x40b9: 0x00c0, 0x40ba: 0x0080, 0x40bb: 0x0080,
0x40bc: 0x0080, 0x40bd: 0x0080, 0x40be: 0x0080, 0x40bf: 0x0080,
// Block 0x103, offset 0x40c0
0x40c0: 0x00c0, 0x40c1: 0x00c0, 0x40c2: 0x00c0, 0x40c3: 0x00c0, 0x40c4: 0x00c0, 0x40c5: 0x00c0,
0x40c6: 0x00c0,
// Block 0x104, offset 0x4100
0x4100: 0x00c0, 0x4101: 0x00c0, 0x4102: 0x00c0, 0x4103: 0x00c0, 0x4104: 0x00c0, 0x4105: 0x00c0,
0x4106: 0x00c0, 0x4107: 0x00c0, 0x4108: 0x00c0, 0x4109: 0x00c0, 0x410a: 0x00c0, 0x410b: 0x00c0,
0x410c: 0x00c0, 0x410d: 0x00c0, 0x410e: 0x00c0, 0x410f: 0x00c0, 0x4110: 0x00c0, 0x4111: 0x00c0,
0x4112: 0x00c0, 0x4113: 0x00c0, 0x4114: 0x00c0, 0x4115: 0x00c0, 0x4116: 0x00c0, 0x4117: 0x00c0,
0x4118: 0x00c0, 0x4119: 0x00c0, 0x411a: 0x00c0, 0x411b: 0x00c0, 0x411c: 0x00c0, 0x411d: 0x00c0,
0x411e: 0x00c0, 0x411f: 0x00c0, 0x4120: 0x00c0, 0x4121: 0x00c0, 0x4122: 0x00c0, 0x4123: 0x00c0,
0x4124: 0x00c0, 0x4125: 0x00c0, 0x4126: 0x00c0, 0x4127: 0x00c0, 0x4128: 0x00c0, 0x4129: 0x00c0,
0x412a: 0x00c0, 0x412b: 0x00c0, 0x412c: 0x00c0, 0x412d: 0x00c0, 0x412e: 0x00c0, 0x412f: 0x00c3,
0x4130: 0x00c3, 0x4131: 0x00c3, 0x4132: 0x00c3, 0x4133: 0x00c3, 0x4134: 0x00c3, 0x4135: 0x00c3,
0x4136: 0x00c3, 0x4137: 0x00c3, 0x4138: 0x00c0, 0x4139: 0x00c6, 0x413a: 0x00c3, 0x413b: 0x0080,
// Block 0x105, offset 0x4140
0x4160: 0x00c0, 0x4161: 0x00c0, 0x4162: 0x00c0, 0x4163: 0x00c0,
0x4164: 0x00c0, 0x4165: 0x00c0, 0x4166: 0x00c0, 0x4167: 0x00c0, 0x4168: 0x00c0, 0x4169: 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: 0x00c0, 0x4195: 0x00c0, 0x4196: 0x00c0, 0x4197: 0x00c0,
0x4198: 0x00c0, 0x4199: 0x00c0, 0x419a: 0x00c0, 0x419b: 0x00c0, 0x419c: 0x00c0, 0x419d: 0x00c0,
0x419e: 0x00c0, 0x419f: 0x00c0, 0x41a0: 0x00c0, 0x41a1: 0x00c0, 0x41a2: 0x00c0, 0x41a3: 0x00c0,
0x41a4: 0x00c0, 0x41a5: 0x00c0, 0x41a6: 0x00c0, 0x41a7: 0x00c0, 0x41a8: 0x00c0, 0x41a9: 0x00c0,
0x41aa: 0x0080, 0x41ab: 0x0080, 0x41ac: 0x0080, 0x41ad: 0x0080, 0x41ae: 0x0080, 0x41af: 0x0080,
0x41b0: 0x0080, 0x41b1: 0x0080, 0x41b2: 0x0080,
0x41bf: 0x00c0,
// Block 0x107, offset 0x41c0
0x41c0: 0x00c0, 0x41c1: 0x00c0, 0x41c2: 0x00c0, 0x41c3: 0x00c0, 0x41c4: 0x00c0, 0x41c5: 0x00c0,
0x41c6: 0x00c0, 0x41c9: 0x00c0,
0x41cc: 0x00c0, 0x41cd: 0x00c0, 0x41ce: 0x00c0, 0x41cf: 0x00c0, 0x41d0: 0x00c0, 0x41d1: 0x00c0,
0x41d2: 0x00c0, 0x41d3: 0x00c0, 0x41d5: 0x00c0, 0x41d6: 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: 0x00c0, 0x41f4: 0x00c0, 0x41f5: 0x00c0,
0x41f7: 0x00c0, 0x41f8: 0x00c0, 0x41fb: 0x00c3,
0x41fc: 0x00c3, 0x41fd: 0x00c5, 0x41fe: 0x00c6, 0x41ff: 0x00c0,
// Block 0x108, offset 0x4200
0x4200: 0x00c0, 0x4201: 0x00c0, 0x4202: 0x00c0, 0x4203: 0x00c3, 0x4204: 0x0080, 0x4205: 0x0080,
0x4206: 0x0080,
0x4210: 0x00c0, 0x4211: 0x00c0,
0x4212: 0x00c0, 0x4213: 0x00c0, 0x4214: 0x00c0, 0x4215: 0x00c0, 0x4216: 0x00c0, 0x4217: 0x00c0,
0x4218: 0x00c0, 0x4219: 0x00c0,
// Block 0x109, offset 0x4240
0x4260: 0x00c0, 0x4261: 0x00c0, 0x4262: 0x00c0, 0x4263: 0x00c0,
0x4264: 0x00c0, 0x4265: 0x00c0, 0x4266: 0x00c0, 0x4267: 0x00c0,
0x426a: 0x00c0, 0x426b: 0x00c0, 0x426c: 0x00c0, 0x426d: 0x00c0, 0x426e: 0x00c0, 0x426f: 0x00c0,
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: 0x00c3, 0x4295: 0x00c3, 0x4296: 0x00c3, 0x4297: 0x00c3,
0x429a: 0x00c3, 0x429b: 0x00c3, 0x429c: 0x00c0, 0x429d: 0x00c0,
0x429e: 0x00c0, 0x429f: 0x00c0, 0x42a0: 0x00c6, 0x42a1: 0x00c0, 0x42a2: 0x0080, 0x42a3: 0x00c0,
0x42a4: 0x00c0,
// Block 0x10b, offset 0x42c0
0x42c0: 0x00c0, 0x42c1: 0x00c3, 0x42c2: 0x00c3, 0x42c3: 0x00c3, 0x42c4: 0x00c3, 0x42c5: 0x00c3,
0x42c6: 0x00c3, 0x42c7: 0x00c3, 0x42c8: 0x00c3, 0x42c9: 0x00c3, 0x42ca: 0x00c3, 0x42cb: 0x00c0,
0x42cc: 0x00c0, 0x42cd: 0x00c0, 0x42ce: 0x00c0, 0x42cf: 0x00c0, 0x42d0: 0x00c0, 0x42d1: 0x00c0,
0x42d2: 0x00c0, 0x42d3: 0x00c0, 0x42d4: 0x00c0, 0x42d5: 0x00c0, 0x42d6: 0x00c0, 0x42d7: 0x00c0,
0x42d8: 0x00c0, 0x42d9: 0x00c0, 0x42da: 0x00c0, 0x42db: 0x00c0, 0x42dc: 0x00c0, 0x42dd: 0x00c0,
0x42de: 0x00c0, 0x42df: 0x00c0, 0x42e0: 0x00c0, 0x42e1: 0x00c0, 0x42e2: 0x00c0, 0x42e3: 0x00c0,
0x42e4: 0x00c0, 0x42e5: 0x00c0, 0x42e6: 0x00c0, 0x42e7: 0x00c0, 0x42e8: 0x00c0, 0x42e9: 0x00c0,
0x42ea: 0x00c0, 0x42eb: 0x00c0, 0x42ec: 0x00c0, 0x42ed: 0x00c0, 0x42ee: 0x00c0, 0x42ef: 0x00c0,
0x42f0: 0x00c0, 0x42f1: 0x00c0, 0x42f2: 0x00c0, 0x42f3: 0x00c3, 0x42f4: 0x00c6, 0x42f5: 0x00c3,
0x42f6: 0x00c3, 0x42f7: 0x00c3, 0x42f8: 0x00c3, 0x42f9: 0x00c0, 0x42fa: 0x00c0, 0x42fb: 0x00c3,
0x42fc: 0x00c3, 0x42fd: 0x00c3, 0x42fe: 0x00c3, 0x42ff: 0x0080,
// Block 0x10c, offset 0x4300
0x4300: 0x0080, 0x4301: 0x0080, 0x4302: 0x0080, 0x4303: 0x0080, 0x4304: 0x0080, 0x4305: 0x0080,
0x4306: 0x0080, 0x4307: 0x00c6,
0x4310: 0x00c0, 0x4311: 0x00c3,
0x4312: 0x00c3, 0x4313: 0x00c3, 0x4314: 0x00c3, 0x4315: 0x00c3, 0x4316: 0x00c3, 0x4317: 0x00c0,
0x4318: 0x00c0, 0x4319: 0x00c3, 0x431a: 0x00c3, 0x431b: 0x00c3, 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: 0x00c0, 0x4331: 0x00c0, 0x4332: 0x00c0, 0x4333: 0x00c0, 0x4334: 0x00c0, 0x4335: 0x00c0,
0x4336: 0x00c0, 0x4337: 0x00c0, 0x4338: 0x00c0, 0x4339: 0x00c0, 0x433a: 0x00c0, 0x433b: 0x00c0,
0x433c: 0x00c0, 0x433d: 0x00c0, 0x433e: 0x00c0, 0x433f: 0x00c0,
// Block 0x10d, offset 0x4340
0x4340: 0x00c0, 0x4341: 0x00c0, 0x4342: 0x00c0, 0x4343: 0x00c0, 0x4344: 0x00c0, 0x4345: 0x00c0,
0x4346: 0x00c0, 0x4347: 0x00c0, 0x4348: 0x00c0, 0x4349: 0x00c0, 0x434a: 0x00c3, 0x434b: 0x00c3,
0x434c: 0x00c3, 0x434d: 0x00c3, 0x434e: 0x00c3, 0x434f: 0x00c3, 0x4350: 0x00c3, 0x4351: 0x00c3,
0x4352: 0x00c3, 0x4353: 0x00c3, 0x4354: 0x00c3, 0x4355: 0x00c3, 0x4356: 0x00c3, 0x4357: 0x00c0,
0x4358: 0x00c3, 0x4359: 0x00c6, 0x435a: 0x0080, 0x435b: 0x0080, 0x435c: 0x0080, 0x435d: 0x00c0,
0x435e: 0x0080, 0x435f: 0x0080, 0x4360: 0x0080, 0x4361: 0x0080, 0x4362: 0x0080,
0x4370: 0x00c0, 0x4371: 0x00c0, 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, 0x4390: 0x00c0, 0x4391: 0x00c0,
0x4392: 0x00c0, 0x4393: 0x00c0, 0x4394: 0x00c0, 0x4395: 0x00c0, 0x4396: 0x00c0, 0x4397: 0x00c0,
0x4398: 0x00c0, 0x4399: 0x00c0, 0x439a: 0x00c0, 0x439b: 0x00c0, 0x439c: 0x00c0, 0x439d: 0x00c0,
0x439e: 0x00c0, 0x439f: 0x00c0, 0x43a0: 0x00c0, 0x43a1: 0x00c0, 0x43a2: 0x00c0, 0x43a3: 0x00c0,
0x43a4: 0x00c0, 0x43a5: 0x00c0, 0x43a6: 0x00c0, 0x43a7: 0x00c0, 0x43a8: 0x00c0, 0x43a9: 0x00c0,
0x43aa: 0x00c0, 0x43ab: 0x00c0, 0x43ac: 0x00c0, 0x43ad: 0x00c0, 0x43ae: 0x00c0, 0x43af: 0x00c0,
0x43b0: 0x00c0, 0x43b1: 0x00c0, 0x43b2: 0x00c0, 0x43b3: 0x00c0, 0x43b4: 0x00c0, 0x43b5: 0x00c0,
0x43b6: 0x00c0, 0x43b7: 0x00c0, 0x43b8: 0x00c0,
// Block 0x10f, offset 0x43c0
0x43c0: 0x0080, 0x43c1: 0x0080, 0x43c2: 0x0080, 0x43c3: 0x0080, 0x43c4: 0x0080, 0x43c5: 0x0080,
0x43c6: 0x0080, 0x43c7: 0x0080, 0x43c8: 0x0080, 0x43c9: 0x0080,
// Block 0x110, offset 0x4400
0x4420: 0x00c3, 0x4421: 0x00c0, 0x4422: 0x00c3, 0x4423: 0x00c3,
0x4424: 0x00c3, 0x4425: 0x00c0, 0x4426: 0x00c3, 0x4427: 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, 0x444f: 0x00c0, 0x4450: 0x00c0, 0x4451: 0x00c0,
0x4452: 0x00c0, 0x4453: 0x00c0, 0x4454: 0x00c0, 0x4455: 0x00c0, 0x4456: 0x00c0, 0x4457: 0x00c0,
0x4458: 0x00c0, 0x4459: 0x00c0, 0x445a: 0x00c0, 0x445b: 0x00c0, 0x445c: 0x00c0, 0x445d: 0x00c0,
0x445e: 0x00c0, 0x445f: 0x00c0, 0x4460: 0x00c0, 0x4461: 0x0080,
0x4470: 0x00c0, 0x4471: 0x00c0, 0x4472: 0x00c0, 0x4473: 0x00c0, 0x4474: 0x00c0, 0x4475: 0x00c0,
0x4476: 0x00c0, 0x4477: 0x00c0, 0x4478: 0x00c0, 0x4479: 0x00c0,
// Block 0x112, offset 0x4480
0x4480: 0x00c0, 0x4481: 0x00c0, 0x4482: 0x00c0, 0x4483: 0x00c0, 0x4484: 0x00c0, 0x4485: 0x00c0,
0x4486: 0x00c0, 0x4487: 0x00c0, 0x4488: 0x00c0, 0x448a: 0x00c0, 0x448b: 0x00c0,
0x448c: 0x00c0, 0x448d: 0x00c0, 0x448e: 0x00c0, 0x448f: 0x00c0, 0x4490: 0x00c0, 0x4491: 0x00c0,
0x4492: 0x00c0, 0x4493: 0x00c0, 0x4494: 0x00c0, 0x4495: 0x00c0, 0x4496: 0x00c0, 0x4497: 0x00c0,
0x4498: 0x00c0, 0x4499: 0x00c0, 0x449a: 0x00c0, 0x449b: 0x00c0, 0x449c: 0x00c0, 0x449d: 0x00c0,
0x449e: 0x00c0, 0x449f: 0x00c0, 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: 0x00c3, 0x44b1: 0x00c3, 0x44b2: 0x00c3, 0x44b3: 0x00c3, 0x44b4: 0x00c3, 0x44b5: 0x00c3,
0x44b6: 0x00c3, 0x44b8: 0x00c3, 0x44b9: 0x00c3, 0x44ba: 0x00c3, 0x44bb: 0x00c3,
0x44bc: 0x00c3, 0x44bd: 0x00c3, 0x44be: 0x00c0, 0x44bf: 0x00c6,
// Block 0x113, offset 0x44c0
0x44c0: 0x00c0, 0x44c1: 0x0080, 0x44c2: 0x0080, 0x44c3: 0x0080, 0x44c4: 0x0080, 0x44c5: 0x0080,
0x44d0: 0x00c0, 0x44d1: 0x00c0,
0x44d2: 0x00c0, 0x44d3: 0x00c0, 0x44d4: 0x00c0, 0x44d5: 0x00c0, 0x44d6: 0x00c0, 0x44d7: 0x00c0,
0x44d8: 0x00c0, 0x44d9: 0x00c0, 0x44da: 0x0080, 0x44db: 0x0080, 0x44dc: 0x0080, 0x44dd: 0x0080,
0x44de: 0x0080, 0x44df: 0x0080, 0x44e0: 0x0080, 0x44e1: 0x0080, 0x44e2: 0x0080, 0x44e3: 0x0080,
0x44e4: 0x0080, 0x44e5: 0x0080, 0x44e6: 0x0080, 0x44e7: 0x0080, 0x44e8: 0x0080, 0x44e9: 0x0080,
0x44ea: 0x0080, 0x44eb: 0x0080, 0x44ec: 0x0080,
0x44f0: 0x0080, 0x44f1: 0x0080, 0x44f2: 0x00c0, 0x44f3: 0x00c0, 0x44f4: 0x00c0, 0x44f5: 0x00c0,
0x44f6: 0x00c0, 0x44f7: 0x00c0, 0x44f8: 0x00c0, 0x44f9: 0x00c0, 0x44fa: 0x00c0, 0x44fb: 0x00c0,
0x44fc: 0x00c0, 0x44fd: 0x00c0, 0x44fe: 0x00c0, 0x44ff: 0x00c0,
// Block 0x114, offset 0x4500
0x4500: 0x00c0, 0x4501: 0x00c0, 0x4502: 0x00c0, 0x4503: 0x00c0, 0x4504: 0x00c0, 0x4505: 0x00c0,
0x4506: 0x00c0, 0x4507: 0x00c0, 0x4508: 0x00c0, 0x4509: 0x00c0, 0x450a: 0x00c0, 0x450b: 0x00c0,
0x450c: 0x00c0, 0x450d: 0x00c0, 0x450e: 0x00c0, 0x450f: 0x00c0,
0x4512: 0x00c3, 0x4513: 0x00c3, 0x4514: 0x00c3, 0x4515: 0x00c3, 0x4516: 0x00c3, 0x4517: 0x00c3,
0x4518: 0x00c3, 0x4519: 0x00c3, 0x451a: 0x00c3, 0x451b: 0x00c3, 0x451c: 0x00c3, 0x451d: 0x00c3,
0x451e: 0x00c3, 0x451f: 0x00c3, 0x4520: 0x00c3, 0x4521: 0x00c3, 0x4522: 0x00c3, 0x4523: 0x00c3,
0x4524: 0x00c3, 0x4525: 0x00c3, 0x4526: 0x00c3, 0x4527: 0x00c3, 0x4529: 0x00c0,
0x452a: 0x00c3, 0x452b: 0x00c3, 0x452c: 0x00c3, 0x452d: 0x00c3, 0x452e: 0x00c3, 0x452f: 0x00c3,
0x4530: 0x00c3, 0x4531: 0x00c0, 0x4532: 0x00c3, 0x4533: 0x00c3, 0x4534: 0x00c0, 0x4535: 0x00c3,
0x4536: 0x00c3,
// Block 0x115, offset 0x4540
0x4540: 0x00c0, 0x4541: 0x00c0, 0x4542: 0x00c0, 0x4543: 0x00c0, 0x4544: 0x00c0, 0x4545: 0x00c0,
0x4546: 0x00c0, 0x4548: 0x00c0, 0x4549: 0x00c0, 0x454b: 0x00c0,
0x454c: 0x00c0, 0x454d: 0x00c0, 0x454e: 0x00c0, 0x454f: 0x00c0, 0x4550: 0x00c0, 0x4551: 0x00c0,
0x4552: 0x00c0, 0x4553: 0x00c0, 0x4554: 0x00c0, 0x4555: 0x00c0, 0x4556: 0x00c0, 0x4557: 0x00c0,
0x4558: 0x00c0, 0x4559: 0x00c0, 0x455a: 0x00c0, 0x455b: 0x00c0, 0x455c: 0x00c0, 0x455d: 0x00c0,
0x455e: 0x00c0, 0x455f: 0x00c0, 0x4560: 0x00c0, 0x4561: 0x00c0, 0x4562: 0x00c0, 0x4563: 0x00c0,
0x4564: 0x00c0, 0x4565: 0x00c0, 0x4566: 0x00c0, 0x4567: 0x00c0, 0x4568: 0x00c0, 0x4569: 0x00c0,
0x456a: 0x00c0, 0x456b: 0x00c0, 0x456c: 0x00c0, 0x456d: 0x00c0, 0x456e: 0x00c0, 0x456f: 0x00c0,
0x4570: 0x00c0, 0x4571: 0x00c3, 0x4572: 0x00c3, 0x4573: 0x00c3, 0x4574: 0x00c3, 0x4575: 0x00c3,
0x4576: 0x00c3, 0x457a: 0x00c3,
0x457c: 0x00c3, 0x457d: 0x00c3, 0x457f: 0x00c3,
// Block 0x116, offset 0x4580
0x4580: 0x00c3, 0x4581: 0x00c3, 0x4582: 0x00c3, 0x4583: 0x00c3, 0x4584: 0x00c6, 0x4585: 0x00c6,
0x4586: 0x00c0, 0x4587: 0x00c3,
0x4590: 0x00c0, 0x4591: 0x00c0,
0x4592: 0x00c0, 0x4593: 0x00c0, 0x4594: 0x00c0, 0x4595: 0x00c0, 0x4596: 0x00c0, 0x4597: 0x00c0,
0x4598: 0x00c0, 0x4599: 0x00c0,
0x45a0: 0x00c0, 0x45a1: 0x00c0, 0x45a2: 0x00c0, 0x45a3: 0x00c0,
0x45a4: 0x00c0, 0x45a5: 0x00c0, 0x45a7: 0x00c0, 0x45a8: 0x00c0,
0x45aa: 0x00c0, 0x45ab: 0x00c0, 0x45ac: 0x00c0, 0x45ad: 0x00c0, 0x45ae: 0x00c0, 0x45af: 0x00c0,
0x45b0: 0x00c0, 0x45b1: 0x00c0, 0x45b2: 0x00c0, 0x45b3: 0x00c0, 0x45b4: 0x00c0, 0x45b5: 0x00c0,
0x45b6: 0x00c0, 0x45b7: 0x00c0, 0x45b8: 0x00c0, 0x45b9: 0x00c0, 0x45ba: 0x00c0, 0x45bb: 0x00c0,
0x45bc: 0x00c0, 0x45bd: 0x00c0, 0x45be: 0x00c0, 0x45bf: 0x00c0,
// 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, 0x45d0: 0x00c3, 0x45d1: 0x00c3,
0x45d3: 0x00c0, 0x45d4: 0x00c0, 0x45d5: 0x00c3, 0x45d6: 0x00c0, 0x45d7: 0x00c6,
0x45d8: 0x00c0,
0x45e0: 0x00c0, 0x45e1: 0x00c0, 0x45e2: 0x00c0, 0x45e3: 0x00c0,
0x45e4: 0x00c0, 0x45e5: 0x00c0, 0x45e6: 0x00c0, 0x45e7: 0x00c0, 0x45e8: 0x00c0, 0x45e9: 0x00c0,
0x45f0: 0x00c0, 0x45f1: 0x00c0, 0x45f2: 0x00c0, 0x45f3: 0x00c0, 0x45f4: 0x00c0, 0x45f5: 0x00c0,
0x45f6: 0x00c0, 0x45f7: 0x00c0, 0x45f8: 0x00c0, 0x45f9: 0x00c0, 0x45fa: 0x00c0, 0x45fb: 0x00c0,
0x45fc: 0x00c0, 0x45fd: 0x00c0, 0x45fe: 0x00c0, 0x45ff: 0x00c0,
// Block 0x118, offset 0x4600
0x4600: 0x00c0, 0x4601: 0x00c0, 0x4602: 0x00c0, 0x4603: 0x00c0, 0x4604: 0x00c0, 0x4605: 0x00c0,
0x4606: 0x00c0, 0x4607: 0x00c0, 0x4608: 0x00c0, 0x4609: 0x00c0, 0x460a: 0x00c0, 0x460b: 0x00c0,
0x460c: 0x00c0, 0x460d: 0x00c0, 0x460e: 0x00c0, 0x460f: 0x00c0, 0x4610: 0x00c0, 0x4611: 0x00c0,
0x4612: 0x00c0, 0x4613: 0x00c0, 0x4614: 0x00c0, 0x4615: 0x00c0, 0x4616: 0x00c0, 0x4617: 0x00c0,
0x4618: 0x00c0, 0x4619: 0x00c0, 0x461a: 0x00c0, 0x461b: 0x00c0,
0x4620: 0x00c0, 0x4621: 0x00c0, 0x4622: 0x00c0, 0x4623: 0x00c0,
0x4624: 0x00c0, 0x4625: 0x00c0, 0x4626: 0x00c0, 0x4627: 0x00c0, 0x4628: 0x00c0, 0x4629: 0x00c0,
// Block 0x119, offset 0x4640
0x4660: 0x00c0, 0x4661: 0x00c0, 0x4662: 0x00c0, 0x4663: 0x00c0,
0x4664: 0x00c0, 0x4665: 0x00c0, 0x4666: 0x00c0, 0x4667: 0x00c0, 0x4668: 0x00c0, 0x4669: 0x00c0,
0x466a: 0x00c0, 0x466b: 0x00c0, 0x466c: 0x00c0, 0x466d: 0x00c0, 0x466e: 0x00c0, 0x466f: 0x00c0,
0x4670: 0x00c0, 0x4671: 0x00c0, 0x4672: 0x00c0, 0x4673: 0x00c3, 0x4674: 0x00c3, 0x4675: 0x00c0,
0x4676: 0x00c0, 0x4677: 0x0080, 0x4678: 0x0080,
// Block 0x11a, offset 0x4680
0x4680: 0x00c3, 0x4681: 0x00c3, 0x4682: 0x00c0, 0x4683: 0x00c0, 0x4684: 0x00c0, 0x4685: 0x00c0,
0x4686: 0x00c0, 0x4687: 0x00c0, 0x4688: 0x00c0, 0x4689: 0x00c0, 0x468a: 0x00c0, 0x468b: 0x00c0,
0x468c: 0x00c0, 0x468d: 0x00c0, 0x468e: 0x00c0, 0x468f: 0x00c0, 0x4690: 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: 0x00c3, 0x46b7: 0x00c3, 0x46b8: 0x00c3, 0x46b9: 0x00c3, 0x46ba: 0x00c3,
0x46be: 0x00c0, 0x46bf: 0x00c0,
// Block 0x11b, offset 0x46c0
0x46c0: 0x00c3, 0x46c1: 0x00c5, 0x46c2: 0x00c6, 0x46c3: 0x0080, 0x46c4: 0x0080, 0x46c5: 0x0080,
0x46c6: 0x0080, 0x46c7: 0x0080, 0x46c8: 0x0080, 0x46c9: 0x0080, 0x46ca: 0x0080, 0x46cb: 0x0080,
0x46cc: 0x0080, 0x46cd: 0x0080, 0x46ce: 0x0080, 0x46cf: 0x0080, 0x46d0: 0x00c0, 0x46d1: 0x00c0,
0x46d2: 0x00c0, 0x46d3: 0x00c0, 0x46d4: 0x00c0, 0x46d5: 0x00c0, 0x46d6: 0x00c0, 0x46d7: 0x00c0,
0x46d8: 0x00c0, 0x46d9: 0x00c0, 0x46da: 0x00c3,
// Block 0x11c, offset 0x4700
0x4730: 0x00c0,
// Block 0x11d, offset 0x4740
0x4740: 0x0080, 0x4741: 0x0080, 0x4742: 0x0080, 0x4743: 0x0080, 0x4744: 0x0080, 0x4745: 0x0080,
0x4746: 0x0080, 0x4747: 0x0080, 0x4748: 0x0080, 0x4749: 0x0080, 0x474a: 0x0080, 0x474b: 0x0080,
0x474c: 0x0080, 0x474d: 0x0080, 0x474e: 0x0080, 0x474f: 0x0080, 0x4750: 0x0080, 0x4751: 0x0080,
0x4752: 0x0080, 0x4753: 0x0080, 0x4754: 0x0080, 0x4755: 0x0080, 0x4756: 0x0080, 0x4757: 0x0080,
0x4758: 0x0080, 0x4759: 0x0080, 0x475a: 0x0080, 0x475b: 0x0080, 0x475c: 0x0080, 0x475d: 0x0080,
0x475e: 0x0080, 0x475f: 0x0080, 0x4760: 0x0080, 0x4761: 0x0080, 0x4762: 0x0080, 0x4763: 0x0080,
0x4764: 0x0080, 0x4765: 0x0080, 0x4766: 0x0080, 0x4767: 0x0080, 0x4768: 0x0080, 0x4769: 0x0080,
0x476a: 0x0080, 0x476b: 0x0080, 0x476c: 0x0080, 0x476d: 0x0080, 0x476e: 0x0080, 0x476f: 0x0080,
0x4770: 0x0080, 0x4771: 0x0080,
0x477f: 0x0080,
// Block 0x11e, offset 0x4780
0x4780: 0x0080, 0x4781: 0x0080, 0x4782: 0x0080, 0x4783: 0x0080, 0x4784: 0x0080, 0x4785: 0x0080,
0x4786: 0x0080, 0x4787: 0x0080, 0x4788: 0x0080, 0x4789: 0x0080, 0x478a: 0x0080, 0x478b: 0x0080,
0x478c: 0x0080, 0x478d: 0x0080, 0x478e: 0x0080, 0x478f: 0x0080, 0x4790: 0x0080, 0x4791: 0x0080,
0x4792: 0x0080, 0x4793: 0x0080, 0x4794: 0x0080, 0x4795: 0x0080, 0x4796: 0x0080, 0x4797: 0x0080,
0x4798: 0x0080, 0x4799: 0x0080, 0x479a: 0x0080, 0x479b: 0x0080, 0x479c: 0x0080, 0x479d: 0x0080,
0x479e: 0x0080, 0x479f: 0x0080, 0x47a0: 0x0080, 0x47a1: 0x0080, 0x47a2: 0x0080, 0x47a3: 0x0080,
0x47a4: 0x0080, 0x47a5: 0x0080, 0x47a6: 0x0080, 0x47a7: 0x0080, 0x47a8: 0x0080, 0x47a9: 0x0080,
0x47aa: 0x0080, 0x47ab: 0x0080, 0x47ac: 0x0080, 0x47ad: 0x0080, 0x47ae: 0x0080,
0x47b0: 0x0080, 0x47b1: 0x0080, 0x47b2: 0x0080, 0x47b3: 0x0080, 0x47b4: 0x0080,
// Block 0x11f, offset 0x47c0
0x47c0: 0x00c0, 0x47c1: 0x00c0, 0x47c2: 0x00c0, 0x47c3: 0x00c0,
// Block 0x120, offset 0x4800
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, 0x482e: 0x00c0, 0x482f: 0x00c0,
0x4830: 0x00c0, 0x4831: 0x00c0, 0x4832: 0x00c0, 0x4833: 0x00c0, 0x4834: 0x00c0, 0x4835: 0x00c0,
0x4836: 0x00c0, 0x4837: 0x00c0, 0x4838: 0x00c0, 0x4839: 0x00c0, 0x483a: 0x00c0, 0x483b: 0x00c0,
0x483c: 0x00c0, 0x483d: 0x00c0, 0x483e: 0x00c0, 0x483f: 0x00c0,
// 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: 0x00c0, 0x4871: 0x0080, 0x4872: 0x0080,
// Block 0x122, offset 0x4880
0x4880: 0x00c0, 0x4881: 0x00c0, 0x4882: 0x00c0, 0x4883: 0x00c0, 0x4884: 0x00c0, 0x4885: 0x00c0,
0x4886: 0x00c0, 0x4887: 0x00c0, 0x4888: 0x00c0, 0x4889: 0x00c0, 0x488a: 0x00c0, 0x488b: 0x00c0,
0x488c: 0x00c0, 0x488d: 0x00c0, 0x488e: 0x00c0, 0x488f: 0x00c0, 0x4890: 0x00c0, 0x4891: 0x00c0,
0x4892: 0x00c0, 0x4893: 0x00c0, 0x4894: 0x00c0, 0x4895: 0x00c0, 0x4896: 0x00c0, 0x4897: 0x00c0,
0x4898: 0x00c0, 0x4899: 0x00c0, 0x489a: 0x00c0, 0x489b: 0x00c0, 0x489c: 0x00c0, 0x489d: 0x00c0,
0x489e: 0x00c0, 0x489f: 0x00c0, 0x48a0: 0x00c0, 0x48a1: 0x00c0, 0x48a2: 0x00c0, 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: 0x0040, 0x48b1: 0x0040, 0x48b2: 0x0040, 0x48b3: 0x0040, 0x48b4: 0x0040, 0x48b5: 0x0040,
0x48b6: 0x0040, 0x48b7: 0x0040, 0x48b8: 0x0040, 0x48b9: 0x0040, 0x48ba: 0x0040, 0x48bb: 0x0040,
0x48bc: 0x0040, 0x48bd: 0x0040, 0x48be: 0x0040, 0x48bf: 0x0040,
// Block 0x123, offset 0x48c0
0x48c0: 0x00c3, 0x48c1: 0x00c0, 0x48c2: 0x00c0, 0x48c3: 0x00c0, 0x48c4: 0x00c0, 0x48c5: 0x00c0,
0x48c6: 0x00c0, 0x48c7: 0x00c3, 0x48c8: 0x00c3, 0x48c9: 0x00c3, 0x48ca: 0x00c3, 0x48cb: 0x00c3,
0x48cc: 0x00c3, 0x48cd: 0x00c3, 0x48ce: 0x00c3, 0x48cf: 0x00c3, 0x48d0: 0x00c3, 0x48d1: 0x00c3,
0x48d2: 0x00c3, 0x48d3: 0x00c3, 0x48d4: 0x00c3, 0x48d5: 0x00c3,
0x48e0: 0x00c0, 0x48e1: 0x00c0, 0x48e2: 0x00c0, 0x48e3: 0x00c0,
0x48e4: 0x00c0, 0x48e5: 0x00c0, 0x48e6: 0x00c0, 0x48e7: 0x00c0, 0x48e8: 0x00c0, 0x48e9: 0x00c0,
0x48ea: 0x00c0, 0x48eb: 0x00c0, 0x48ec: 0x00c0, 0x48ed: 0x00c0, 0x48ee: 0x00c0, 0x48ef: 0x00c0,
0x48f0: 0x00c0, 0x48f1: 0x00c0, 0x48f2: 0x00c0, 0x48f3: 0x00c0, 0x48f4: 0x00c0, 0x48f5: 0x00c0,
0x48f6: 0x00c0, 0x48f7: 0x00c0, 0x48f8: 0x00c0, 0x48f9: 0x00c0, 0x48fa: 0x00c0, 0x48fb: 0x00c0,
0x48fc: 0x00c0, 0x48fd: 0x00c0, 0x48fe: 0x00c0, 0x48ff: 0x00c0,
// Block 0x124, offset 0x4900
0x4900: 0x00c0, 0x4901: 0x00c0, 0x4902: 0x00c0, 0x4903: 0x00c0, 0x4904: 0x00c0, 0x4905: 0x00c0,
0x4906: 0x00c0, 0x4907: 0x00c0, 0x4908: 0x00c0, 0x4909: 0x00c0, 0x490a: 0x00c0, 0x490b: 0x00c0,
0x490c: 0x00c0, 0x490d: 0x00c0, 0x490e: 0x00c0, 0x490f: 0x00c0, 0x4910: 0x00c0, 0x4911: 0x00c0,
0x4912: 0x00c0, 0x4913: 0x00c0, 0x4914: 0x00c0, 0x4915: 0x00c0, 0x4916: 0x00c0, 0x4917: 0x00c0,
0x4918: 0x00c0, 0x4919: 0x00c0, 0x491a: 0x00c0, 0x491b: 0x00c0, 0x491c: 0x00c0, 0x491d: 0x00c0,
0x491e: 0x00c3, 0x491f: 0x00c3, 0x4920: 0x00c3, 0x4921: 0x00c3, 0x4922: 0x00c3, 0x4923: 0x00c3,
0x4924: 0x00c3, 0x4925: 0x00c3, 0x4926: 0x00c3, 0x4927: 0x00c3, 0x4928: 0x00c3, 0x4929: 0x00c3,
0x492a: 0x00c0, 0x492b: 0x00c0, 0x492c: 0x00c0, 0x492d: 0x00c3, 0x492e: 0x00c3, 0x492f: 0x00c6,
0x4930: 0x00c0, 0x4931: 0x00c0, 0x4932: 0x00c0, 0x4933: 0x00c0, 0x4934: 0x00c0, 0x4935: 0x00c0,
0x4936: 0x00c0, 0x4937: 0x00c0, 0x4938: 0x00c0, 0x4939: 0x00c0,
// 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, 0x494b: 0x00c0,
0x494c: 0x00c0, 0x494d: 0x00c0, 0x494e: 0x00c0, 0x494f: 0x00c0, 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, 0x4960: 0x00c0, 0x4961: 0x00c0, 0x4962: 0x00c0, 0x4963: 0x00c0,
0x4964: 0x00c0, 0x4965: 0x00c0, 0x4966: 0x00c0, 0x4967: 0x00c0, 0x4968: 0x00c0, 0x4969: 0x00c0,
0x496e: 0x0080, 0x496f: 0x0080,
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, 0x4988: 0x00c0, 0x4989: 0x00c0, 0x498a: 0x00c0, 0x498b: 0x00c0,
0x498c: 0x00c0, 0x498d: 0x00c0, 0x498e: 0x00c0, 0x498f: 0x00c0, 0x4990: 0x00c0, 0x4991: 0x00c0,
0x4992: 0x00c0, 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, 0x49a0: 0x00c0, 0x49a1: 0x00c0, 0x49a2: 0x00c0, 0x49a3: 0x00c0,
0x49a4: 0x00c0, 0x49a5: 0x00c0, 0x49a6: 0x00c0, 0x49a7: 0x00c0, 0x49a8: 0x00c0, 0x49a9: 0x00c0,
0x49aa: 0x00c0, 0x49ab: 0x00c0, 0x49ac: 0x00c0, 0x49ad: 0x00c0, 0x49ae: 0x00c0, 0x49af: 0x00c0,
0x49b0: 0x00c0, 0x49b1: 0x00c0, 0x49b2: 0x00c0, 0x49b3: 0x00c0, 0x49b4: 0x00c0, 0x49b5: 0x00c0,
0x49b6: 0x00c0, 0x49b7: 0x00c0, 0x49b8: 0x00c0, 0x49b9: 0x00c0, 0x49ba: 0x00c0, 0x49bb: 0x00c0,
0x49bc: 0x00c0, 0x49bd: 0x00c0, 0x49be: 0x00c0,
// Block 0x127, offset 0x49c0
0x49c0: 0x00c0, 0x49c1: 0x00c0, 0x49c2: 0x00c0, 0x49c3: 0x00c0, 0x49c4: 0x00c0, 0x49c5: 0x00c0,
0x49c6: 0x00c0, 0x49c7: 0x00c0, 0x49c8: 0x00c0, 0x49c9: 0x00c0,
0x49d0: 0x00c0, 0x49d1: 0x00c0,
0x49d2: 0x00c0, 0x49d3: 0x00c0, 0x49d4: 0x00c0, 0x49d5: 0x00c0, 0x49d6: 0x00c0, 0x49d7: 0x00c0,
0x49d8: 0x00c0, 0x49d9: 0x00c0, 0x49da: 0x00c0, 0x49db: 0x00c0, 0x49dc: 0x00c0, 0x49dd: 0x00c0,
0x49de: 0x00c0, 0x49df: 0x00c0, 0x49e0: 0x00c0, 0x49e1: 0x00c0, 0x49e2: 0x00c0, 0x49e3: 0x00c0,
0x49e4: 0x00c0, 0x49e5: 0x00c0, 0x49e6: 0x00c0, 0x49e7: 0x00c0, 0x49e8: 0x00c0, 0x49e9: 0x00c0,
0x49ea: 0x00c0, 0x49eb: 0x00c0, 0x49ec: 0x00c0, 0x49ed: 0x00c0,
0x49f0: 0x00c3, 0x49f1: 0x00c3, 0x49f2: 0x00c3, 0x49f3: 0x00c3, 0x49f4: 0x00c3, 0x49f5: 0x0080,
// 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: 0x00c3, 0x4a31: 0x00c3, 0x4a32: 0x00c3, 0x4a33: 0x00c3, 0x4a34: 0x00c3, 0x4a35: 0x00c3,
0x4a36: 0x00c3, 0x4a37: 0x0080, 0x4a38: 0x0080, 0x4a39: 0x0080, 0x4a3a: 0x0080, 0x4a3b: 0x0080,
0x4a3c: 0x0080, 0x4a3d: 0x0080, 0x4a3e: 0x0080, 0x4a3f: 0x0080,
// Block 0x129, offset 0x4a40
0x4a40: 0x00c0, 0x4a41: 0x00c0, 0x4a42: 0x00c0, 0x4a43: 0x00c0, 0x4a44: 0x0080, 0x4a45: 0x0080,
0x4a50: 0x00c0, 0x4a51: 0x00c0,
0x4a52: 0x00c0, 0x4a53: 0x00c0, 0x4a54: 0x00c0, 0x4a55: 0x00c0, 0x4a56: 0x00c0, 0x4a57: 0x00c0,
0x4a58: 0x00c0, 0x4a59: 0x00c0, 0x4a5b: 0x0080, 0x4a5c: 0x0080, 0x4a5d: 0x0080,
0x4a5e: 0x0080, 0x4a5f: 0x0080, 0x4a60: 0x0080, 0x4a61: 0x0080, 0x4a63: 0x00c0,
0x4a64: 0x00c0, 0x4a65: 0x00c0, 0x4a66: 0x00c0, 0x4a67: 0x00c0, 0x4a68: 0x00c0, 0x4a69: 0x00c0,
0x4a6a: 0x00c0, 0x4a6b: 0x00c0, 0x4a6c: 0x00c0, 0x4a6d: 0x00c0, 0x4a6e: 0x00c0, 0x4a6f: 0x00c0,
0x4a70: 0x00c0, 0x4a71: 0x00c0, 0x4a72: 0x00c0, 0x4a73: 0x00c0, 0x4a74: 0x00c0, 0x4a75: 0x00c0,
0x4a76: 0x00c0, 0x4a77: 0x00c0,
0x4a7d: 0x00c0, 0x4a7e: 0x00c0, 0x4a7f: 0x00c0,
// Block 0x12a, offset 0x4a80
0x4a80: 0x00c0, 0x4a81: 0x00c0, 0x4a82: 0x00c0, 0x4a83: 0x00c0, 0x4a84: 0x00c0, 0x4a85: 0x00c0,
0x4a86: 0x00c0, 0x4a87: 0x00c0, 0x4a88: 0x00c0, 0x4a89: 0x00c0, 0x4a8a: 0x00c0, 0x4a8b: 0x00c0,
0x4a8c: 0x00c0, 0x4a8d: 0x00c0, 0x4a8e: 0x00c0, 0x4a8f: 0x00c0,
// Block 0x12b, offset 0x4ac0
0x4ac0: 0x00c0, 0x4ac1: 0x00c0, 0x4ac2: 0x00c0, 0x4ac3: 0x00c0, 0x4ac4: 0x00c0, 0x4ac5: 0x00c0,
0x4ac6: 0x00c0, 0x4ac7: 0x00c0, 0x4ac8: 0x00c0, 0x4ac9: 0x00c0, 0x4aca: 0x00c0, 0x4acb: 0x00c0,
0x4acc: 0x00c0, 0x4acd: 0x00c0, 0x4ace: 0x00c0, 0x4acf: 0x00c0, 0x4ad0: 0x00c0, 0x4ad1: 0x00c0,
0x4ad2: 0x00c0, 0x4ad3: 0x00c0, 0x4ad4: 0x00c0, 0x4ad5: 0x00c0, 0x4ad6: 0x00c0, 0x4ad7: 0x00c0,
0x4ad8: 0x00c0, 0x4ad9: 0x00c0, 0x4ada: 0x00c0, 0x4adb: 0x00c0, 0x4adc: 0x00c0, 0x4add: 0x00c0,
0x4ade: 0x00c0, 0x4adf: 0x00c0, 0x4ae0: 0x00c0, 0x4ae1: 0x00c0, 0x4ae2: 0x00c0, 0x4ae3: 0x00c0,
0x4ae4: 0x00c0, 0x4ae5: 0x00c0, 0x4ae6: 0x00c0, 0x4ae7: 0x00c0, 0x4ae8: 0x00c0, 0x4ae9: 0x00c0,
0x4aea: 0x00c0, 0x4aeb: 0x00c0, 0x4aec: 0x00c0, 0x4aed: 0x0080, 0x4aee: 0x0080, 0x4aef: 0x0080,
0x4af0: 0x00c0, 0x4af1: 0x00c0, 0x4af2: 0x00c0, 0x4af3: 0x00c0, 0x4af4: 0x00c0, 0x4af5: 0x00c0,
0x4af6: 0x00c0, 0x4af7: 0x00c0, 0x4af8: 0x00c0, 0x4af9: 0x00c0,
// Block 0x12c, offset 0x4b00
0x4b00: 0x0080, 0x4b01: 0x0080, 0x4b02: 0x0080, 0x4b03: 0x0080, 0x4b04: 0x0080, 0x4b05: 0x0080,
0x4b06: 0x0080, 0x4b07: 0x0080, 0x4b08: 0x0080, 0x4b09: 0x0080, 0x4b0a: 0x0080, 0x4b0b: 0x0080,
0x4b0c: 0x0080, 0x4b0d: 0x0080, 0x4b0e: 0x0080, 0x4b0f: 0x0080, 0x4b10: 0x0080, 0x4b11: 0x0080,
0x4b12: 0x0080, 0x4b13: 0x0080, 0x4b14: 0x0080, 0x4b15: 0x0080, 0x4b16: 0x0080, 0x4b17: 0x0080,
0x4b18: 0x0080, 0x4b19: 0x0080, 0x4b1a: 0x0080,
0x4b20: 0x00c0, 0x4b21: 0x00c0, 0x4b22: 0x00c0, 0x4b23: 0x00c0,
0x4b24: 0x00c0, 0x4b25: 0x00c0, 0x4b26: 0x00c0, 0x4b27: 0x00c0, 0x4b28: 0x00c0, 0x4b29: 0x00c0,
0x4b2a: 0x00c0, 0x4b2b: 0x00c0, 0x4b2c: 0x00c0, 0x4b2d: 0x00c0, 0x4b2e: 0x00c0, 0x4b2f: 0x00c0,
0x4b30: 0x00c0, 0x4b31: 0x00c0, 0x4b32: 0x00c0, 0x4b33: 0x00c0, 0x4b34: 0x00c0, 0x4b35: 0x00c0,
0x4b36: 0x00c0, 0x4b37: 0x00c0, 0x4b38: 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,
// 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,
0x4b8f: 0x00c3, 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, 0x4bab: 0x00c0, 0x4bac: 0x00c0, 0x4bad: 0x00c0, 0x4bae: 0x00c0, 0x4baf: 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, 0x4bbd: 0x00c0, 0x4bbe: 0x00c0, 0x4bbf: 0x00c0,
// Block 0x12f, offset 0x4bc0
0x4bc0: 0x00c0, 0x4bc1: 0x00c0, 0x4bc2: 0x00c0, 0x4bc3: 0x00c0, 0x4bc4: 0x00c0, 0x4bc5: 0x00c0,
0x4bc6: 0x00c0, 0x4bc7: 0x00c0,
0x4bcf: 0x00c3, 0x4bd0: 0x00c3, 0x4bd1: 0x00c3,
0x4bd2: 0x00c3, 0x4bd3: 0x00c0, 0x4bd4: 0x00c0, 0x4bd5: 0x00c0, 0x4bd6: 0x00c0, 0x4bd7: 0x00c0,
0x4bd8: 0x00c0, 0x4bd9: 0x00c0, 0x4bda: 0x00c0, 0x4bdb: 0x00c0, 0x4bdc: 0x00c0, 0x4bdd: 0x00c0,
0x4bde: 0x00c0, 0x4bdf: 0x00c0,
// Block 0x130, offset 0x4c00
0x4c20: 0x00c0, 0x4c21: 0x00c0, 0x4c22: 0x008c, 0x4c23: 0x00cc,
0x4c24: 0x00c3,
0x4c30: 0x00cc, 0x4c31: 0x00cc, 0x4c32: 0x00cc, 0x4c33: 0x00cc, 0x4c34: 0x008c, 0x4c35: 0x008c,
0x4c36: 0x008c,
// Block 0x131, offset 0x4c40
0x4c40: 0x00c0, 0x4c41: 0x00c0, 0x4c42: 0x00c0, 0x4c43: 0x00c0, 0x4c44: 0x00c0, 0x4c45: 0x00c0,
0x4c46: 0x00c0, 0x4c47: 0x00c0, 0x4c48: 0x00c0, 0x4c49: 0x00c0, 0x4c4a: 0x00c0, 0x4c4b: 0x00c0,
0x4c4c: 0x00c0, 0x4c4d: 0x00c0, 0x4c4e: 0x00c0, 0x4c4f: 0x00c0, 0x4c50: 0x00c0, 0x4c51: 0x00c0,
0x4c52: 0x00c0, 0x4c53: 0x00c0, 0x4c54: 0x00c0, 0x4c55: 0x00c0,
0x4c7f: 0x00c0,
// Block 0x132, offset 0x4c80
0x4c80: 0x00c0, 0x4c81: 0x00c0, 0x4c82: 0x00c0, 0x4c83: 0x00c0, 0x4c84: 0x00c0, 0x4c85: 0x00c0,
0x4c86: 0x00c0, 0x4c87: 0x00c0, 0x4c88: 0x00c0, 0x4c89: 0x00c0, 0x4c8a: 0x00c0, 0x4c8b: 0x00c0,
0x4c8c: 0x00c0, 0x4c8d: 0x00c0, 0x4c8e: 0x00c0, 0x4c8f: 0x00c0, 0x4c90: 0x00c0, 0x4c91: 0x00c0,
0x4c92: 0x00c0, 0x4c93: 0x00c0, 0x4c94: 0x00c0, 0x4c95: 0x00c0, 0x4c96: 0x00c0, 0x4c97: 0x00c0,
0x4c98: 0x00c0, 0x4c99: 0x00c0, 0x4c9a: 0x00c0, 0x4c9b: 0x00c0, 0x4c9c: 0x00c0, 0x4c9d: 0x00c0,
0x4c9e: 0x00c0,
// Block 0x133, offset 0x4cc0
0x4cf0: 0x00cc, 0x4cf1: 0x00cc, 0x4cf2: 0x00cc, 0x4cf3: 0x00cc, 0x4cf5: 0x00cc,
0x4cf6: 0x00cc, 0x4cf7: 0x00cc, 0x4cf8: 0x00cc, 0x4cf9: 0x00cc, 0x4cfa: 0x00cc, 0x4cfb: 0x00cc,
0x4cfd: 0x00cc, 0x4cfe: 0x00cc,
// Block 0x134, offset 0x4d00
0x4d00: 0x00cc, 0x4d01: 0x00cc, 0x4d02: 0x00cc, 0x4d03: 0x00cc, 0x4d04: 0x00cc, 0x4d05: 0x00cc,
0x4d06: 0x00cc, 0x4d07: 0x00cc, 0x4d08: 0x00cc, 0x4d09: 0x00cc, 0x4d0a: 0x00cc, 0x4d0b: 0x00cc,
0x4d0c: 0x00cc, 0x4d0d: 0x00cc, 0x4d0e: 0x00cc, 0x4d0f: 0x00cc, 0x4d10: 0x00cc, 0x4d11: 0x00cc,
0x4d12: 0x00cc, 0x4d13: 0x00cc, 0x4d14: 0x00cc, 0x4d15: 0x00cc, 0x4d16: 0x00cc, 0x4d17: 0x00cc,
0x4d18: 0x00cc, 0x4d19: 0x00cc, 0x4d1a: 0x00cc, 0x4d1b: 0x00cc, 0x4d1c: 0x00cc, 0x4d1d: 0x00cc,
0x4d1e: 0x00cc, 0x4d1f: 0x00cc, 0x4d20: 0x00cc, 0x4d21: 0x00cc, 0x4d22: 0x00cc,
0x4d32: 0x00cc,
// Block 0x135, offset 0x4d40
0x4d50: 0x00cc, 0x4d51: 0x00cc,
0x4d52: 0x00cc, 0x4d55: 0x00cc,
0x4d64: 0x00cc, 0x4d65: 0x00cc, 0x4d66: 0x00cc, 0x4d67: 0x00cc,
0x4d70: 0x00c0, 0x4d71: 0x00c0, 0x4d72: 0x00c0, 0x4d73: 0x00c0, 0x4d74: 0x00c0, 0x4d75: 0x00c0,
0x4d76: 0x00c0, 0x4d77: 0x00c0, 0x4d78: 0x00c0, 0x4d79: 0x00c0, 0x4d7a: 0x00c0, 0x4d7b: 0x00c0,
0x4d7c: 0x00c0, 0x4d7d: 0x00c0, 0x4d7e: 0x00c0, 0x4d7f: 0x00c0,
// Block 0x136, offset 0x4d80
0x4d80: 0x00c0, 0x4d81: 0x00c0, 0x4d82: 0x00c0, 0x4d83: 0x00c0, 0x4d84: 0x00c0, 0x4d85: 0x00c0,
0x4d86: 0x00c0, 0x4d87: 0x00c0, 0x4d88: 0x00c0, 0x4d89: 0x00c0, 0x4d8a: 0x00c0, 0x4d8b: 0x00c0,
0x4d8c: 0x00c0, 0x4d8d: 0x00c0, 0x4d8e: 0x00c0, 0x4d8f: 0x00c0, 0x4d90: 0x00c0, 0x4d91: 0x00c0,
0x4d92: 0x00c0, 0x4d93: 0x00c0, 0x4d94: 0x00c0, 0x4d95: 0x00c0, 0x4d96: 0x00c0, 0x4d97: 0x00c0,
0x4d98: 0x00c0, 0x4d99: 0x00c0, 0x4d9a: 0x00c0, 0x4d9b: 0x00c0, 0x4d9c: 0x00c0, 0x4d9d: 0x00c0,
0x4d9e: 0x00c0, 0x4d9f: 0x00c0, 0x4da0: 0x00c0, 0x4da1: 0x00c0, 0x4da2: 0x00c0, 0x4da3: 0x00c0,
0x4da4: 0x00c0, 0x4da5: 0x00c0, 0x4da6: 0x00c0, 0x4da7: 0x00c0, 0x4da8: 0x00c0, 0x4da9: 0x00c0,
0x4daa: 0x00c0, 0x4dab: 0x00c0, 0x4dac: 0x00c0, 0x4dad: 0x00c0, 0x4dae: 0x00c0, 0x4daf: 0x00c0,
0x4db0: 0x00c0, 0x4db1: 0x00c0, 0x4db2: 0x00c0, 0x4db3: 0x00c0, 0x4db4: 0x00c0, 0x4db5: 0x00c0,
0x4db6: 0x00c0, 0x4db7: 0x00c0, 0x4db8: 0x00c0, 0x4db9: 0x00c0, 0x4dba: 0x00c0, 0x4dbb: 0x00c0,
// Block 0x137, offset 0x4dc0
0x4dc0: 0x00c0, 0x4dc1: 0x00c0, 0x4dc2: 0x00c0, 0x4dc3: 0x00c0, 0x4dc4: 0x00c0, 0x4dc5: 0x00c0,
0x4dc6: 0x00c0, 0x4dc7: 0x00c0, 0x4dc8: 0x00c0, 0x4dc9: 0x00c0, 0x4dca: 0x00c0, 0x4dcb: 0x00c0,
0x4dcc: 0x00c0, 0x4dcd: 0x00c0, 0x4dce: 0x00c0, 0x4dcf: 0x00c0, 0x4dd0: 0x00c0, 0x4dd1: 0x00c0,
0x4dd2: 0x00c0, 0x4dd3: 0x00c0, 0x4dd4: 0x00c0, 0x4dd5: 0x00c0, 0x4dd6: 0x00c0, 0x4dd7: 0x00c0,
0x4dd8: 0x00c0, 0x4dd9: 0x00c0, 0x4dda: 0x00c0, 0x4ddb: 0x00c0, 0x4ddc: 0x00c0, 0x4ddd: 0x00c0,
0x4dde: 0x00c0, 0x4ddf: 0x00c0, 0x4de0: 0x00c0, 0x4de1: 0x00c0, 0x4de2: 0x00c0, 0x4de3: 0x00c0,
0x4de4: 0x00c0, 0x4de5: 0x00c0, 0x4de6: 0x00c0, 0x4de7: 0x00c0, 0x4de8: 0x00c0, 0x4de9: 0x00c0,
0x4dea: 0x00c0,
0x4df0: 0x00c0, 0x4df1: 0x00c0, 0x4df2: 0x00c0, 0x4df3: 0x00c0, 0x4df4: 0x00c0, 0x4df5: 0x00c0,
0x4df6: 0x00c0, 0x4df7: 0x00c0, 0x4df8: 0x00c0, 0x4df9: 0x00c0, 0x4dfa: 0x00c0, 0x4dfb: 0x00c0,
0x4dfc: 0x00c0,
// Block 0x138, offset 0x4e00
0x4e00: 0x00c0, 0x4e01: 0x00c0, 0x4e02: 0x00c0, 0x4e03: 0x00c0, 0x4e04: 0x00c0, 0x4e05: 0x00c0,
0x4e06: 0x00c0, 0x4e07: 0x00c0, 0x4e08: 0x00c0,
0x4e10: 0x00c0, 0x4e11: 0x00c0,
0x4e12: 0x00c0, 0x4e13: 0x00c0, 0x4e14: 0x00c0, 0x4e15: 0x00c0, 0x4e16: 0x00c0, 0x4e17: 0x00c0,
0x4e18: 0x00c0, 0x4e19: 0x00c0, 0x4e1c: 0x0080, 0x4e1d: 0x00c3,
0x4e1e: 0x00c3, 0x4e1f: 0x0080, 0x4e20: 0x0040, 0x4e21: 0x0040, 0x4e22: 0x0040, 0x4e23: 0x0040,
// 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, 0x4e54: 0x0080, 0x4e55: 0x0080, 0x4e56: 0x0080, 0x4e57: 0x0080,
0x4e58: 0x0080, 0x4e59: 0x0080, 0x4e5a: 0x0080, 0x4e5b: 0x0080, 0x4e5c: 0x0080, 0x4e5d: 0x0080,
0x4e5e: 0x0080, 0x4e5f: 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, 0x4e74: 0x0080, 0x4e75: 0x0080,
0x4e76: 0x0080, 0x4e77: 0x0080, 0x4e78: 0x0080, 0x4e79: 0x0080, 0x4e7a: 0x0080, 0x4e7b: 0x0080,
0x4e7c: 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, 0x4e97: 0x0080,
0x4e98: 0x0080, 0x4e99: 0x0080, 0x4e9a: 0x0080, 0x4e9b: 0x0080, 0x4e9c: 0x0080, 0x4e9d: 0x0080,
0x4e9e: 0x0080, 0x4e9f: 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,
0x4eba: 0x0080, 0x4ebb: 0x0080,
0x4ebc: 0x0080, 0x4ebd: 0x0080, 0x4ebe: 0x0080, 0x4ebf: 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,
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,
// Block 0x13c, offset 0x4f00
0x4f00: 0x00c3, 0x4f01: 0x00c3, 0x4f02: 0x00c3, 0x4f03: 0x00c3, 0x4f04: 0x00c3, 0x4f05: 0x00c3,
0x4f06: 0x00c3, 0x4f07: 0x00c3, 0x4f08: 0x00c3, 0x4f09: 0x00c3, 0x4f0a: 0x00c3, 0x4f0b: 0x00c3,
0x4f0c: 0x00c3, 0x4f0d: 0x00c3, 0x4f0e: 0x00c3, 0x4f0f: 0x00c3, 0x4f10: 0x00c3, 0x4f11: 0x00c3,
0x4f12: 0x00c3, 0x4f13: 0x00c3, 0x4f14: 0x00c3, 0x4f15: 0x00c3, 0x4f16: 0x00c3, 0x4f17: 0x00c3,
0x4f18: 0x00c3, 0x4f19: 0x00c3, 0x4f1a: 0x00c3, 0x4f1b: 0x00c3, 0x4f1c: 0x00c3, 0x4f1d: 0x00c3,
0x4f1e: 0x00c3, 0x4f1f: 0x00c3, 0x4f20: 0x00c3, 0x4f21: 0x00c3, 0x4f22: 0x00c3, 0x4f23: 0x00c3,
0x4f24: 0x00c3, 0x4f25: 0x00c3, 0x4f26: 0x00c3, 0x4f27: 0x00c3, 0x4f28: 0x00c3, 0x4f29: 0x00c3,
0x4f2a: 0x00c3, 0x4f2b: 0x00c3, 0x4f2c: 0x00c3, 0x4f2d: 0x00c3,
0x4f30: 0x00c3, 0x4f31: 0x00c3, 0x4f32: 0x00c3, 0x4f33: 0x00c3, 0x4f34: 0x00c3, 0x4f35: 0x00c3,
0x4f36: 0x00c3, 0x4f37: 0x00c3, 0x4f38: 0x00c3, 0x4f39: 0x00c3, 0x4f3a: 0x00c3, 0x4f3b: 0x00c3,
0x4f3c: 0x00c3, 0x4f3d: 0x00c3, 0x4f3e: 0x00c3, 0x4f3f: 0x00c3,
// Block 0x13d, offset 0x4f40
0x4f40: 0x00c3, 0x4f41: 0x00c3, 0x4f42: 0x00c3, 0x4f43: 0x00c3, 0x4f44: 0x00c3, 0x4f45: 0x00c3,
0x4f46: 0x00c3,
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,
// Block 0x13f, offset 0x4fc0
0x4fc0: 0x0080, 0x4fc1: 0x0080, 0x4fc2: 0x0080, 0x4fc3: 0x0080, 0x4fc4: 0x0080, 0x4fc5: 0x0080,
0x4fc6: 0x0080, 0x4fc7: 0x0080, 0x4fc8: 0x0080, 0x4fc9: 0x0080, 0x4fca: 0x0080, 0x4fcb: 0x0080,
0x4fcc: 0x0080, 0x4fcd: 0x0080, 0x4fce: 0x0080, 0x4fcf: 0x0080, 0x4fd0: 0x0080, 0x4fd1: 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,
// 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, 0x5026: 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,
0x504c: 0x0080, 0x504d: 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: 0x00c0, 0x5066: 0x00c0, 0x5067: 0x00c3, 0x5068: 0x00c3, 0x5069: 0x00c3,
0x506a: 0x0080, 0x506b: 0x0080, 0x506c: 0x0080, 0x506d: 0x00c0, 0x506e: 0x00c0, 0x506f: 0x00c0,
0x5070: 0x00c0, 0x5071: 0x00c0, 0x5072: 0x00c0, 0x5073: 0x0040, 0x5074: 0x0040, 0x5075: 0x0040,
0x5076: 0x0040, 0x5077: 0x0040, 0x5078: 0x0040, 0x5079: 0x0040, 0x507a: 0x0040, 0x507b: 0x00c3,
0x507c: 0x00c3, 0x507d: 0x00c3, 0x507e: 0x00c3, 0x507f: 0x00c3,
// Block 0x142, offset 0x5080
0x5080: 0x00c3, 0x5081: 0x00c3, 0x5082: 0x00c3, 0x5083: 0x0080, 0x5084: 0x0080, 0x5085: 0x00c3,
0x5086: 0x00c3, 0x5087: 0x00c3, 0x5088: 0x00c3, 0x5089: 0x00c3, 0x508a: 0x00c3, 0x508b: 0x00c3,
0x508c: 0x0080, 0x508d: 0x0080, 0x508e: 0x0080, 0x508f: 0x0080, 0x5090: 0x0080, 0x5091: 0x0080,
0x5092: 0x0080, 0x5093: 0x0080, 0x5094: 0x0080, 0x5095: 0x0080, 0x5096: 0x0080, 0x5097: 0x0080,
0x5098: 0x0080, 0x5099: 0x0080, 0x509a: 0x0080, 0x509b: 0x0080, 0x509c: 0x0080, 0x509d: 0x0080,
0x509e: 0x0080, 0x509f: 0x0080, 0x50a0: 0x0080, 0x50a1: 0x0080, 0x50a2: 0x0080, 0x50a3: 0x0080,
0x50a4: 0x0080, 0x50a5: 0x0080, 0x50a6: 0x0080, 0x50a7: 0x0080, 0x50a8: 0x0080, 0x50a9: 0x0080,
0x50aa: 0x00c3, 0x50ab: 0x00c3, 0x50ac: 0x00c3, 0x50ad: 0x00c3, 0x50ae: 0x0080, 0x50af: 0x0080,
0x50b0: 0x0080, 0x50b1: 0x0080, 0x50b2: 0x0080, 0x50b3: 0x0080, 0x50b4: 0x0080, 0x50b5: 0x0080,
0x50b6: 0x0080, 0x50b7: 0x0080, 0x50b8: 0x0080, 0x50b9: 0x0080, 0x50ba: 0x0080, 0x50bb: 0x0080,
0x50bc: 0x0080, 0x50bd: 0x0080, 0x50be: 0x0080, 0x50bf: 0x0080,
// Block 0x143, offset 0x50c0
0x50c0: 0x0080, 0x50c1: 0x0080, 0x50c2: 0x0080, 0x50c3: 0x0080, 0x50c4: 0x0080, 0x50c5: 0x0080,
0x50c6: 0x0080, 0x50c7: 0x0080, 0x50c8: 0x0080, 0x50c9: 0x0080, 0x50ca: 0x0080, 0x50cb: 0x0080,
0x50cc: 0x0080, 0x50cd: 0x0080, 0x50ce: 0x0080, 0x50cf: 0x0080, 0x50d0: 0x0080, 0x50d1: 0x0080,
0x50d2: 0x0080, 0x50d3: 0x0080, 0x50d4: 0x0080, 0x50d5: 0x0080, 0x50d6: 0x0080, 0x50d7: 0x0080,
0x50d8: 0x0080, 0x50d9: 0x0080, 0x50da: 0x0080, 0x50db: 0x0080, 0x50dc: 0x0080, 0x50dd: 0x0080,
0x50de: 0x0080, 0x50df: 0x0080, 0x50e0: 0x0080, 0x50e1: 0x0080, 0x50e2: 0x0080, 0x50e3: 0x0080,
0x50e4: 0x0080, 0x50e5: 0x0080, 0x50e6: 0x0080, 0x50e7: 0x0080, 0x50e8: 0x0080, 0x50e9: 0x0080,
0x50ea: 0x0080,
// Block 0x144, offset 0x5100
0x5100: 0x0088, 0x5101: 0x0088, 0x5102: 0x00c9, 0x5103: 0x00c9, 0x5104: 0x00c9, 0x5105: 0x0088,
// Block 0x145, offset 0x5140
0x5140: 0x0080, 0x5141: 0x0080, 0x5142: 0x0080, 0x5143: 0x0080, 0x5144: 0x0080, 0x5145: 0x0080,
0x5146: 0x0080, 0x5147: 0x0080, 0x5148: 0x0080, 0x5149: 0x0080, 0x514a: 0x0080, 0x514b: 0x0080,
0x514c: 0x0080, 0x514d: 0x0080, 0x514e: 0x0080, 0x514f: 0x0080, 0x5150: 0x0080, 0x5151: 0x0080,
0x5152: 0x0080, 0x5153: 0x0080,
0x5160: 0x0080, 0x5161: 0x0080, 0x5162: 0x0080, 0x5163: 0x0080,
0x5164: 0x0080, 0x5165: 0x0080, 0x5166: 0x0080, 0x5167: 0x0080, 0x5168: 0x0080, 0x5169: 0x0080,
0x516a: 0x0080, 0x516b: 0x0080, 0x516c: 0x0080, 0x516d: 0x0080, 0x516e: 0x0080, 0x516f: 0x0080,
0x5170: 0x0080, 0x5171: 0x0080, 0x5172: 0x0080, 0x5173: 0x0080,
// Block 0x146, offset 0x5180
0x5180: 0x0080, 0x5181: 0x0080, 0x5182: 0x0080, 0x5183: 0x0080, 0x5184: 0x0080, 0x5185: 0x0080,
0x5186: 0x0080, 0x5187: 0x0080, 0x5188: 0x0080, 0x5189: 0x0080, 0x518a: 0x0080, 0x518b: 0x0080,
0x518c: 0x0080, 0x518d: 0x0080, 0x518e: 0x0080, 0x518f: 0x0080, 0x5190: 0x0080, 0x5191: 0x0080,
0x5192: 0x0080, 0x5193: 0x0080, 0x5194: 0x0080, 0x5195: 0x0080, 0x5196: 0x0080,
0x51a0: 0x0080, 0x51a1: 0x0080, 0x51a2: 0x0080, 0x51a3: 0x0080,
0x51a4: 0x0080, 0x51a5: 0x0080, 0x51a6: 0x0080, 0x51a7: 0x0080, 0x51a8: 0x0080, 0x51a9: 0x0080,
0x51aa: 0x0080, 0x51ab: 0x0080, 0x51ac: 0x0080, 0x51ad: 0x0080, 0x51ae: 0x0080, 0x51af: 0x0080,
0x51b0: 0x0080, 0x51b1: 0x0080, 0x51b2: 0x0080, 0x51b3: 0x0080, 0x51b4: 0x0080, 0x51b5: 0x0080,
0x51b6: 0x0080, 0x51b7: 0x0080, 0x51b8: 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, 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, 0x51ee: 0x0080, 0x51ef: 0x0080,
0x51f0: 0x0080, 0x51f1: 0x0080, 0x51f2: 0x0080, 0x51f3: 0x0080, 0x51f4: 0x0080, 0x51f5: 0x0080,
0x51f6: 0x0080, 0x51f7: 0x0080, 0x51f8: 0x0080, 0x51f9: 0x0080, 0x51fa: 0x0080, 0x51fb: 0x0080,
0x51fc: 0x0080, 0x51fd: 0x0080, 0x51fe: 0x0080, 0x51ff: 0x0080,
// Block 0x148, offset 0x5200
0x5200: 0x0080, 0x5201: 0x0080, 0x5202: 0x0080, 0x5203: 0x0080, 0x5204: 0x0080, 0x5205: 0x0080,
0x5206: 0x0080, 0x5207: 0x0080, 0x5208: 0x0080, 0x5209: 0x0080, 0x520a: 0x0080, 0x520b: 0x0080,
0x520c: 0x0080, 0x520d: 0x0080, 0x520e: 0x0080, 0x520f: 0x0080, 0x5210: 0x0080, 0x5211: 0x0080,
0x5212: 0x0080, 0x5213: 0x0080, 0x5214: 0x0080, 0x5215: 0x0080, 0x5216: 0x0080, 0x5217: 0x0080,
0x5218: 0x0080, 0x5219: 0x0080, 0x521a: 0x0080, 0x521b: 0x0080, 0x521c: 0x0080,
0x521e: 0x0080, 0x521f: 0x0080, 0x5222: 0x0080,
0x5225: 0x0080, 0x5226: 0x0080, 0x5229: 0x0080,
0x522a: 0x0080, 0x522b: 0x0080, 0x522c: 0x0080, 0x522e: 0x0080, 0x522f: 0x0080,
0x5230: 0x0080, 0x5231: 0x0080, 0x5232: 0x0080, 0x5233: 0x0080, 0x5234: 0x0080, 0x5235: 0x0080,
0x5236: 0x0080, 0x5237: 0x0080, 0x5238: 0x0080, 0x5239: 0x0080, 0x523b: 0x0080,
0x523d: 0x0080, 0x523e: 0x0080, 0x523f: 0x0080,
// Block 0x149, offset 0x5240
0x5240: 0x0080, 0x5241: 0x0080, 0x5242: 0x0080, 0x5243: 0x0080, 0x5245: 0x0080,
0x5246: 0x0080, 0x5247: 0x0080, 0x5248: 0x0080, 0x5249: 0x0080, 0x524a: 0x0080, 0x524b: 0x0080,
0x524c: 0x0080, 0x524d: 0x0080, 0x524e: 0x0080, 0x524f: 0x0080, 0x5250: 0x0080, 0x5251: 0x0080,
0x5252: 0x0080, 0x5253: 0x0080, 0x5254: 0x0080, 0x5255: 0x0080, 0x5256: 0x0080, 0x5257: 0x0080,
0x5258: 0x0080, 0x5259: 0x0080, 0x525a: 0x0080, 0x525b: 0x0080, 0x525c: 0x0080, 0x525d: 0x0080,
0x525e: 0x0080, 0x525f: 0x0080, 0x5260: 0x0080, 0x5261: 0x0080, 0x5262: 0x0080, 0x5263: 0x0080,
0x5264: 0x0080, 0x5265: 0x0080, 0x5266: 0x0080, 0x5267: 0x0080, 0x5268: 0x0080, 0x5269: 0x0080,
0x526a: 0x0080, 0x526b: 0x0080, 0x526c: 0x0080, 0x526d: 0x0080, 0x526e: 0x0080, 0x526f: 0x0080,
0x5270: 0x0080, 0x5271: 0x0080, 0x5272: 0x0080, 0x5273: 0x0080, 0x5274: 0x0080, 0x5275: 0x0080,
0x5276: 0x0080, 0x5277: 0x0080, 0x5278: 0x0080, 0x5279: 0x0080, 0x527a: 0x0080, 0x527b: 0x0080,
0x527c: 0x0080, 0x527d: 0x0080, 0x527e: 0x0080, 0x527f: 0x0080,
// Block 0x14a, offset 0x5280
0x5280: 0x0080, 0x5281: 0x0080, 0x5282: 0x0080, 0x5283: 0x0080, 0x5284: 0x0080, 0x5285: 0x0080,
0x5287: 0x0080, 0x5288: 0x0080, 0x5289: 0x0080, 0x528a: 0x0080,
0x528d: 0x0080, 0x528e: 0x0080, 0x528f: 0x0080, 0x5290: 0x0080, 0x5291: 0x0080,
0x5292: 0x0080, 0x5293: 0x0080, 0x5294: 0x0080, 0x5296: 0x0080, 0x5297: 0x0080,
0x5298: 0x0080, 0x5299: 0x0080, 0x529a: 0x0080, 0x529b: 0x0080, 0x529c: 0x0080,
0x529e: 0x0080, 0x529f: 0x0080, 0x52a0: 0x0080, 0x52a1: 0x0080, 0x52a2: 0x0080, 0x52a3: 0x0080,
0x52a4: 0x0080, 0x52a5: 0x0080, 0x52a6: 0x0080, 0x52a7: 0x0080, 0x52a8: 0x0080, 0x52a9: 0x0080,
0x52aa: 0x0080, 0x52ab: 0x0080, 0x52ac: 0x0080, 0x52ad: 0x0080, 0x52ae: 0x0080, 0x52af: 0x0080,
0x52b0: 0x0080, 0x52b1: 0x0080, 0x52b2: 0x0080, 0x52b3: 0x0080, 0x52b4: 0x0080, 0x52b5: 0x0080,
0x52b6: 0x0080, 0x52b7: 0x0080, 0x52b8: 0x0080, 0x52b9: 0x0080, 0x52bb: 0x0080,
0x52bc: 0x0080, 0x52bd: 0x0080, 0x52be: 0x0080,
// Block 0x14b, offset 0x52c0
0x52c0: 0x0080, 0x52c1: 0x0080, 0x52c2: 0x0080, 0x52c3: 0x0080, 0x52c4: 0x0080,
0x52c6: 0x0080, 0x52ca: 0x0080, 0x52cb: 0x0080,
0x52cc: 0x0080, 0x52cd: 0x0080, 0x52ce: 0x0080, 0x52cf: 0x0080, 0x52d0: 0x0080,
0x52d2: 0x0080, 0x52d3: 0x0080, 0x52d4: 0x0080, 0x52d5: 0x0080, 0x52d6: 0x0080, 0x52d7: 0x0080,
0x52d8: 0x0080, 0x52d9: 0x0080, 0x52da: 0x0080, 0x52db: 0x0080, 0x52dc: 0x0080, 0x52dd: 0x0080,
0x52de: 0x0080, 0x52df: 0x0080, 0x52e0: 0x0080, 0x52e1: 0x0080, 0x52e2: 0x0080, 0x52e3: 0x0080,
0x52e4: 0x0080, 0x52e5: 0x0080, 0x52e6: 0x0080, 0x52e7: 0x0080, 0x52e8: 0x0080, 0x52e9: 0x0080,
0x52ea: 0x0080, 0x52eb: 0x0080, 0x52ec: 0x0080, 0x52ed: 0x0080, 0x52ee: 0x0080, 0x52ef: 0x0080,
0x52f0: 0x0080, 0x52f1: 0x0080, 0x52f2: 0x0080, 0x52f3: 0x0080, 0x52f4: 0x0080, 0x52f5: 0x0080,
0x52f6: 0x0080, 0x52f7: 0x0080, 0x52f8: 0x0080, 0x52f9: 0x0080, 0x52fa: 0x0080, 0x52fb: 0x0080,
0x52fc: 0x0080, 0x52fd: 0x0080, 0x52fe: 0x0080, 0x52ff: 0x0080,
// Block 0x14c, offset 0x5300
0x5300: 0x0080, 0x5301: 0x0080, 0x5302: 0x0080, 0x5303: 0x0080, 0x5304: 0x0080, 0x5305: 0x0080,
0x5306: 0x0080, 0x5307: 0x0080, 0x5308: 0x0080, 0x5309: 0x0080, 0x530a: 0x0080, 0x530b: 0x0080,
0x530c: 0x0080, 0x530d: 0x0080, 0x530e: 0x0080, 0x530f: 0x0080, 0x5310: 0x0080, 0x5311: 0x0080,
0x5312: 0x0080, 0x5313: 0x0080, 0x5314: 0x0080, 0x5315: 0x0080, 0x5316: 0x0080, 0x5317: 0x0080,
0x5318: 0x0080, 0x5319: 0x0080, 0x531a: 0x0080, 0x531b: 0x0080, 0x531c: 0x0080, 0x531d: 0x0080,
0x531e: 0x0080, 0x531f: 0x0080, 0x5320: 0x0080, 0x5321: 0x0080, 0x5322: 0x0080, 0x5323: 0x0080,
0x5324: 0x0080, 0x5325: 0x0080, 0x5328: 0x0080, 0x5329: 0x0080,
0x532a: 0x0080, 0x532b: 0x0080, 0x532c: 0x0080, 0x532d: 0x0080, 0x532e: 0x0080, 0x532f: 0x0080,
0x5330: 0x0080, 0x5331: 0x0080, 0x5332: 0x0080, 0x5333: 0x0080, 0x5334: 0x0080, 0x5335: 0x0080,
0x5336: 0x0080, 0x5337: 0x0080, 0x5338: 0x0080, 0x5339: 0x0080, 0x533a: 0x0080, 0x533b: 0x0080,
0x533c: 0x0080, 0x533d: 0x0080, 0x533e: 0x0080, 0x533f: 0x0080,
// Block 0x14d, offset 0x5340
0x5340: 0x0080, 0x5341: 0x0080, 0x5342: 0x0080, 0x5343: 0x0080, 0x5344: 0x0080, 0x5345: 0x0080,
0x5346: 0x0080, 0x5347: 0x0080, 0x5348: 0x0080, 0x5349: 0x0080, 0x534a: 0x0080, 0x534b: 0x0080,
0x534e: 0x0080, 0x534f: 0x0080, 0x5350: 0x0080, 0x5351: 0x0080,
0x5352: 0x0080, 0x5353: 0x0080, 0x5354: 0x0080, 0x5355: 0x0080, 0x5356: 0x0080, 0x5357: 0x0080,
0x5358: 0x0080, 0x5359: 0x0080, 0x535a: 0x0080, 0x535b: 0x0080, 0x535c: 0x0080, 0x535d: 0x0080,
0x535e: 0x0080, 0x535f: 0x0080, 0x5360: 0x0080, 0x5361: 0x0080, 0x5362: 0x0080, 0x5363: 0x0080,
0x5364: 0x0080, 0x5365: 0x0080, 0x5366: 0x0080, 0x5367: 0x0080, 0x5368: 0x0080, 0x5369: 0x0080,
0x536a: 0x0080, 0x536b: 0x0080, 0x536c: 0x0080, 0x536d: 0x0080, 0x536e: 0x0080, 0x536f: 0x0080,
0x5370: 0x0080, 0x5371: 0x0080, 0x5372: 0x0080, 0x5373: 0x0080, 0x5374: 0x0080, 0x5375: 0x0080,
0x5376: 0x0080, 0x5377: 0x0080, 0x5378: 0x0080, 0x5379: 0x0080, 0x537a: 0x0080, 0x537b: 0x0080,
0x537c: 0x0080, 0x537d: 0x0080, 0x537e: 0x0080, 0x537f: 0x0080,
// Block 0x14e, offset 0x5380
0x5380: 0x00c3, 0x5381: 0x00c3, 0x5382: 0x00c3, 0x5383: 0x00c3, 0x5384: 0x00c3, 0x5385: 0x00c3,
0x5386: 0x00c3, 0x5387: 0x00c3, 0x5388: 0x00c3, 0x5389: 0x00c3, 0x538a: 0x00c3, 0x538b: 0x00c3,
0x538c: 0x00c3, 0x538d: 0x00c3, 0x538e: 0x00c3, 0x538f: 0x00c3, 0x5390: 0x00c3, 0x5391: 0x00c3,
0x5392: 0x00c3, 0x5393: 0x00c3, 0x5394: 0x00c3, 0x5395: 0x00c3, 0x5396: 0x00c3, 0x5397: 0x00c3,
0x5398: 0x00c3, 0x5399: 0x00c3, 0x539a: 0x00c3, 0x539b: 0x00c3, 0x539c: 0x00c3, 0x539d: 0x00c3,
0x539e: 0x00c3, 0x539f: 0x00c3, 0x53a0: 0x00c3, 0x53a1: 0x00c3, 0x53a2: 0x00c3, 0x53a3: 0x00c3,
0x53a4: 0x00c3, 0x53a5: 0x00c3, 0x53a6: 0x00c3, 0x53a7: 0x00c3, 0x53a8: 0x00c3, 0x53a9: 0x00c3,
0x53aa: 0x00c3, 0x53ab: 0x00c3, 0x53ac: 0x00c3, 0x53ad: 0x00c3, 0x53ae: 0x00c3, 0x53af: 0x00c3,
0x53b0: 0x00c3, 0x53b1: 0x00c3, 0x53b2: 0x00c3, 0x53b3: 0x00c3, 0x53b4: 0x00c3, 0x53b5: 0x00c3,
0x53b6: 0x00c3, 0x53b7: 0x0080, 0x53b8: 0x0080, 0x53b9: 0x0080, 0x53ba: 0x0080, 0x53bb: 0x00c3,
0x53bc: 0x00c3, 0x53bd: 0x00c3, 0x53be: 0x00c3, 0x53bf: 0x00c3,
// Block 0x14f, offset 0x53c0
0x53c0: 0x00c3, 0x53c1: 0x00c3, 0x53c2: 0x00c3, 0x53c3: 0x00c3, 0x53c4: 0x00c3, 0x53c5: 0x00c3,
0x53c6: 0x00c3, 0x53c7: 0x00c3, 0x53c8: 0x00c3, 0x53c9: 0x00c3, 0x53ca: 0x00c3, 0x53cb: 0x00c3,
0x53cc: 0x00c3, 0x53cd: 0x00c3, 0x53ce: 0x00c3, 0x53cf: 0x00c3, 0x53d0: 0x00c3, 0x53d1: 0x00c3,
0x53d2: 0x00c3, 0x53d3: 0x00c3, 0x53d4: 0x00c3, 0x53d5: 0x00c3, 0x53d6: 0x00c3, 0x53d7: 0x00c3,
0x53d8: 0x00c3, 0x53d9: 0x00c3, 0x53da: 0x00c3, 0x53db: 0x00c3, 0x53dc: 0x00c3, 0x53dd: 0x00c3,
0x53de: 0x00c3, 0x53df: 0x00c3, 0x53e0: 0x00c3, 0x53e1: 0x00c3, 0x53e2: 0x00c3, 0x53e3: 0x00c3,
0x53e4: 0x00c3, 0x53e5: 0x00c3, 0x53e6: 0x00c3, 0x53e7: 0x00c3, 0x53e8: 0x00c3, 0x53e9: 0x00c3,
0x53ea: 0x00c3, 0x53eb: 0x00c3, 0x53ec: 0x00c3, 0x53ed: 0x0080, 0x53ee: 0x0080, 0x53ef: 0x0080,
0x53f0: 0x0080, 0x53f1: 0x0080, 0x53f2: 0x0080, 0x53f3: 0x0080, 0x53f4: 0x0080, 0x53f5: 0x00c3,
0x53f6: 0x0080, 0x53f7: 0x0080, 0x53f8: 0x0080, 0x53f9: 0x0080, 0x53fa: 0x0080, 0x53fb: 0x0080,
0x53fc: 0x0080, 0x53fd: 0x0080, 0x53fe: 0x0080, 0x53ff: 0x0080,
// Block 0x150, offset 0x5400
0x5400: 0x0080, 0x5401: 0x0080, 0x5402: 0x0080, 0x5403: 0x0080, 0x5404: 0x00c3, 0x5405: 0x0080,
0x5406: 0x0080, 0x5407: 0x0080, 0x5408: 0x0080, 0x5409: 0x0080, 0x540a: 0x0080, 0x540b: 0x0080,
0x541b: 0x00c3, 0x541c: 0x00c3, 0x541d: 0x00c3,
0x541e: 0x00c3, 0x541f: 0x00c3, 0x5421: 0x00c3, 0x5422: 0x00c3, 0x5423: 0x00c3,
0x5424: 0x00c3, 0x5425: 0x00c3, 0x5426: 0x00c3, 0x5427: 0x00c3, 0x5428: 0x00c3, 0x5429: 0x00c3,
0x542a: 0x00c3, 0x542b: 0x00c3, 0x542c: 0x00c3, 0x542d: 0x00c3, 0x542e: 0x00c3, 0x542f: 0x00c3,
// Block 0x151, offset 0x5440
0x5440: 0x00c0, 0x5441: 0x00c0, 0x5442: 0x00c0, 0x5443: 0x00c0, 0x5444: 0x00c0, 0x5445: 0x00c0,
0x5446: 0x00c0, 0x5447: 0x00c0, 0x5448: 0x00c0, 0x5449: 0x00c0, 0x544a: 0x00c0, 0x544b: 0x00c0,
0x544c: 0x00c0, 0x544d: 0x00c0, 0x544e: 0x00c0, 0x544f: 0x00c0, 0x5450: 0x00c0, 0x5451: 0x00c0,
0x5452: 0x00c0, 0x5453: 0x00c0, 0x5454: 0x00c0, 0x5455: 0x00c0, 0x5456: 0x00c0, 0x5457: 0x00c0,
0x5458: 0x00c0, 0x5459: 0x00c0, 0x545a: 0x00c0, 0x545b: 0x00c0, 0x545c: 0x00c0, 0x545d: 0x00c0,
0x545e: 0x00c0,
0x5465: 0x00c0, 0x5466: 0x00c0, 0x5467: 0x00c0, 0x5468: 0x00c0, 0x5469: 0x00c0,
0x546a: 0x00c0,
// Block 0x152, offset 0x5480
0x5480: 0x00c3, 0x5481: 0x00c3, 0x5482: 0x00c3, 0x5483: 0x00c3, 0x5484: 0x00c3, 0x5485: 0x00c3,
0x5486: 0x00c3, 0x5488: 0x00c3, 0x5489: 0x00c3, 0x548a: 0x00c3, 0x548b: 0x00c3,
0x548c: 0x00c3, 0x548d: 0x00c3, 0x548e: 0x00c3, 0x548f: 0x00c3, 0x5490: 0x00c3, 0x5491: 0x00c3,
0x5492: 0x00c3, 0x5493: 0x00c3, 0x5494: 0x00c3, 0x5495: 0x00c3, 0x5496: 0x00c3, 0x5497: 0x00c3,
0x5498: 0x00c3, 0x549b: 0x00c3, 0x549c: 0x00c3, 0x549d: 0x00c3,
0x549e: 0x00c3, 0x549f: 0x00c3, 0x54a0: 0x00c3, 0x54a1: 0x00c3, 0x54a3: 0x00c3,
0x54a4: 0x00c3, 0x54a6: 0x00c3, 0x54a7: 0x00c3, 0x54a8: 0x00c3, 0x54a9: 0x00c3,
0x54aa: 0x00c3,
0x54b0: 0x0080, 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,
// Block 0x154, offset 0x5500
0x550f: 0x00c3,
// Block 0x155, offset 0x5540
0x5540: 0x00c0, 0x5541: 0x00c0, 0x5542: 0x00c0, 0x5543: 0x00c0, 0x5544: 0x00c0, 0x5545: 0x00c0,
0x5546: 0x00c0, 0x5547: 0x00c0, 0x5548: 0x00c0, 0x5549: 0x00c0, 0x554a: 0x00c0, 0x554b: 0x00c0,
0x554c: 0x00c0, 0x554d: 0x00c0, 0x554e: 0x00c0, 0x554f: 0x00c0, 0x5550: 0x00c0, 0x5551: 0x00c0,
0x5552: 0x00c0, 0x5553: 0x00c0, 0x5554: 0x00c0, 0x5555: 0x00c0, 0x5556: 0x00c0, 0x5557: 0x00c0,
0x5558: 0x00c0, 0x5559: 0x00c0, 0x555a: 0x00c0, 0x555b: 0x00c0, 0x555c: 0x00c0, 0x555d: 0x00c0,
0x555e: 0x00c0, 0x555f: 0x00c0, 0x5560: 0x00c0, 0x5561: 0x00c0, 0x5562: 0x00c0, 0x5563: 0x00c0,
0x5564: 0x00c0, 0x5565: 0x00c0, 0x5566: 0x00c0, 0x5567: 0x00c0, 0x5568: 0x00c0, 0x5569: 0x00c0,
0x556a: 0x00c0, 0x556b: 0x00c0, 0x556c: 0x00c0,
0x5570: 0x00c3, 0x5571: 0x00c3, 0x5572: 0x00c3, 0x5573: 0x00c3, 0x5574: 0x00c3, 0x5575: 0x00c3,
0x5576: 0x00c3, 0x5577: 0x00c0, 0x5578: 0x00c0, 0x5579: 0x00c0, 0x557a: 0x00c0, 0x557b: 0x00c0,
0x557c: 0x00c0, 0x557d: 0x00c0,
// Block 0x156, offset 0x5580
0x5580: 0x00c0, 0x5581: 0x00c0, 0x5582: 0x00c0, 0x5583: 0x00c0, 0x5584: 0x00c0, 0x5585: 0x00c0,
0x5586: 0x00c0, 0x5587: 0x00c0, 0x5588: 0x00c0, 0x5589: 0x00c0,
0x558e: 0x00c0, 0x558f: 0x0080,
// Block 0x157, offset 0x55c0
0x55d0: 0x00c0, 0x55d1: 0x00c0,
0x55d2: 0x00c0, 0x55d3: 0x00c0, 0x55d4: 0x00c0, 0x55d5: 0x00c0, 0x55d6: 0x00c0, 0x55d7: 0x00c0,
0x55d8: 0x00c0, 0x55d9: 0x00c0, 0x55da: 0x00c0, 0x55db: 0x00c0, 0x55dc: 0x00c0, 0x55dd: 0x00c0,
0x55de: 0x00c0, 0x55df: 0x00c0, 0x55e0: 0x00c0, 0x55e1: 0x00c0, 0x55e2: 0x00c0, 0x55e3: 0x00c0,
0x55e4: 0x00c0, 0x55e5: 0x00c0, 0x55e6: 0x00c0, 0x55e7: 0x00c0, 0x55e8: 0x00c0, 0x55e9: 0x00c0,
0x55ea: 0x00c0, 0x55eb: 0x00c0, 0x55ec: 0x00c0, 0x55ed: 0x00c0, 0x55ee: 0x00c3,
// Block 0x158, offset 0x5600
0x5600: 0x00c0, 0x5601: 0x00c0, 0x5602: 0x00c0, 0x5603: 0x00c0, 0x5604: 0x00c0, 0x5605: 0x00c0,
0x5606: 0x00c0, 0x5607: 0x00c0, 0x5608: 0x00c0, 0x5609: 0x00c0, 0x560a: 0x00c0, 0x560b: 0x00c0,
0x560c: 0x00c0, 0x560d: 0x00c0, 0x560e: 0x00c0, 0x560f: 0x00c0, 0x5610: 0x00c0, 0x5611: 0x00c0,
0x5612: 0x00c0, 0x5613: 0x00c0, 0x5614: 0x00c0, 0x5615: 0x00c0, 0x5616: 0x00c0, 0x5617: 0x00c0,
0x5618: 0x00c0, 0x5619: 0x00c0, 0x561a: 0x00c0, 0x561b: 0x00c0, 0x561c: 0x00c0, 0x561d: 0x00c0,
0x561e: 0x00c0, 0x561f: 0x00c0, 0x5620: 0x00c0, 0x5621: 0x00c0, 0x5622: 0x00c0, 0x5623: 0x00c0,
0x5624: 0x00c0, 0x5625: 0x00c0, 0x5626: 0x00c0, 0x5627: 0x00c0, 0x5628: 0x00c0, 0x5629: 0x00c0,
0x562a: 0x00c0, 0x562b: 0x00c0, 0x562c: 0x00c3, 0x562d: 0x00c3, 0x562e: 0x00c3, 0x562f: 0x00c3,
0x5630: 0x00c0, 0x5631: 0x00c0, 0x5632: 0x00c0, 0x5633: 0x00c0, 0x5634: 0x00c0, 0x5635: 0x00c0,
0x5636: 0x00c0, 0x5637: 0x00c0, 0x5638: 0x00c0, 0x5639: 0x00c0,
0x563f: 0x0080,
// Block 0x159, offset 0x5640
0x5650: 0x00c0, 0x5651: 0x00c0,
0x5652: 0x00c0, 0x5653: 0x00c0, 0x5654: 0x00c0, 0x5655: 0x00c0, 0x5656: 0x00c0, 0x5657: 0x00c0,
0x5658: 0x00c0, 0x5659: 0x00c0, 0x565a: 0x00c0, 0x565b: 0x00c0, 0x565c: 0x00c0, 0x565d: 0x00c0,
0x565e: 0x00c0, 0x565f: 0x00c0, 0x5660: 0x00c0, 0x5661: 0x00c0, 0x5662: 0x00c0, 0x5663: 0x00c0,
0x5664: 0x00c0, 0x5665: 0x00c0, 0x5666: 0x00c0, 0x5667: 0x00c0, 0x5668: 0x00c0, 0x5669: 0x00c0,
0x566a: 0x00c0, 0x566b: 0x00c0, 0x566c: 0x00c3, 0x566d: 0x00c3, 0x566e: 0x00c3, 0x566f: 0x00c3,
0x5670: 0x00c0, 0x5671: 0x00c0, 0x5672: 0x00c0, 0x5673: 0x00c0, 0x5674: 0x00c0, 0x5675: 0x00c0,
0x5676: 0x00c0, 0x5677: 0x00c0, 0x5678: 0x00c0, 0x5679: 0x00c0,
// Block 0x15a, offset 0x5680
0x5690: 0x00c0, 0x5691: 0x00c0,
0x5692: 0x00c0, 0x5693: 0x00c0, 0x5694: 0x00c0, 0x5695: 0x00c0, 0x5696: 0x00c0, 0x5697: 0x00c0,
0x5698: 0x00c0, 0x5699: 0x00c0, 0x569a: 0x00c0, 0x569b: 0x00c0, 0x569c: 0x00c0, 0x569d: 0x00c0,
0x569e: 0x00c0, 0x569f: 0x00c0, 0x56a0: 0x00c0, 0x56a1: 0x00c0, 0x56a2: 0x00c0, 0x56a3: 0x00c0,
0x56a4: 0x00c0, 0x56a5: 0x00c0, 0x56a6: 0x00c0, 0x56a7: 0x00c0, 0x56a8: 0x00c0, 0x56a9: 0x00c0,
0x56aa: 0x00c0, 0x56ab: 0x00c0, 0x56ac: 0x00c0, 0x56ad: 0x00c0, 0x56ae: 0x00c3, 0x56af: 0x00c3,
0x56b0: 0x00c0, 0x56b1: 0x00c0, 0x56b2: 0x00c0, 0x56b3: 0x00c0, 0x56b4: 0x00c0, 0x56b5: 0x00c0,
0x56b6: 0x00c0, 0x56b7: 0x00c0, 0x56b8: 0x00c0, 0x56b9: 0x00c0, 0x56ba: 0x00c0,
0x56bf: 0x0080,
// Block 0x15b, offset 0x56c0
0x56c0: 0x00c0, 0x56c1: 0x00c0, 0x56c2: 0x00c0, 0x56c3: 0x00c0, 0x56c4: 0x00c0, 0x56c5: 0x00c0,
0x56c6: 0x00c0, 0x56c7: 0x00c0, 0x56c8: 0x00c0, 0x56c9: 0x00c0, 0x56ca: 0x00c0, 0x56cb: 0x00c0,
0x56cc: 0x00c0, 0x56cd: 0x00c0, 0x56ce: 0x00c0, 0x56cf: 0x00c0, 0x56d0: 0x00c0, 0x56d1: 0x00c0,
0x56d2: 0x00c0, 0x56d3: 0x00c0, 0x56d4: 0x00c0, 0x56d5: 0x00c0, 0x56d6: 0x00c0, 0x56d7: 0x00c0,
0x56d8: 0x00c0, 0x56d9: 0x00c0, 0x56da: 0x00c0, 0x56db: 0x00c0, 0x56dc: 0x00c0, 0x56dd: 0x00c0,
0x56de: 0x00c0, 0x56e0: 0x00c0, 0x56e1: 0x00c0, 0x56e2: 0x00c0, 0x56e3: 0x00c3,
0x56e4: 0x00c0, 0x56e5: 0x00c0, 0x56e6: 0x00c3, 0x56e7: 0x00c0, 0x56e8: 0x00c0, 0x56e9: 0x00c0,
0x56ea: 0x00c0, 0x56eb: 0x00c0, 0x56ec: 0x00c0, 0x56ed: 0x00c0, 0x56ee: 0x00c3, 0x56ef: 0x00c3,
0x56f0: 0x00c0, 0x56f1: 0x00c0, 0x56f2: 0x00c0, 0x56f3: 0x00c0, 0x56f4: 0x00c0, 0x56f5: 0x00c3,
0x56fe: 0x00c0, 0x56ff: 0x00c0,
// Block 0x15c, offset 0x5700
0x5720: 0x00c0, 0x5721: 0x00c0, 0x5722: 0x00c0, 0x5723: 0x00c0,
0x5724: 0x00c0, 0x5725: 0x00c0, 0x5726: 0x00c0, 0x5728: 0x00c0, 0x5729: 0x00c0,
0x572a: 0x00c0, 0x572b: 0x00c0, 0x572d: 0x00c0, 0x572e: 0x00c0,
0x5730: 0x00c0, 0x5731: 0x00c0, 0x5732: 0x00c0, 0x5733: 0x00c0, 0x5734: 0x00c0, 0x5735: 0x00c0,
0x5736: 0x00c0, 0x5737: 0x00c0, 0x5738: 0x00c0, 0x5739: 0x00c0, 0x573a: 0x00c0, 0x573b: 0x00c0,
0x573c: 0x00c0, 0x573d: 0x00c0, 0x573e: 0x00c0,
// Block 0x15d, offset 0x5740
0x5740: 0x00c0, 0x5741: 0x00c0, 0x5742: 0x00c0, 0x5743: 0x00c0, 0x5744: 0x00c0,
0x5747: 0x0080, 0x5748: 0x0080, 0x5749: 0x0080, 0x574a: 0x0080, 0x574b: 0x0080,
0x574c: 0x0080, 0x574d: 0x0080, 0x574e: 0x0080, 0x574f: 0x0080, 0x5750: 0x00c3, 0x5751: 0x00c3,
0x5752: 0x00c3, 0x5753: 0x00c3, 0x5754: 0x00c3, 0x5755: 0x00c3, 0x5756: 0x00c3,
// Block 0x15e, offset 0x5780
0x5780: 0x00c2, 0x5781: 0x00c2, 0x5782: 0x00c2, 0x5783: 0x00c2, 0x5784: 0x00c2, 0x5785: 0x00c2,
0x5786: 0x00c2, 0x5787: 0x00c2, 0x5788: 0x00c2, 0x5789: 0x00c2, 0x578a: 0x00c2, 0x578b: 0x00c2,
0x578c: 0x00c2, 0x578d: 0x00c2, 0x578e: 0x00c2, 0x578f: 0x00c2, 0x5790: 0x00c2, 0x5791: 0x00c2,
0x5792: 0x00c2, 0x5793: 0x00c2, 0x5794: 0x00c2, 0x5795: 0x00c2, 0x5796: 0x00c2, 0x5797: 0x00c2,
0x5798: 0x00c2, 0x5799: 0x00c2, 0x579a: 0x00c2, 0x579b: 0x00c2, 0x579c: 0x00c2, 0x579d: 0x00c2,
0x579e: 0x00c2, 0x579f: 0x00c2, 0x57a0: 0x00c2, 0x57a1: 0x00c2, 0x57a2: 0x00c2, 0x57a3: 0x00c2,
0x57a4: 0x00c2, 0x57a5: 0x00c2, 0x57a6: 0x00c2, 0x57a7: 0x00c2, 0x57a8: 0x00c2, 0x57a9: 0x00c2,
0x57aa: 0x00c2, 0x57ab: 0x00c2, 0x57ac: 0x00c2, 0x57ad: 0x00c2, 0x57ae: 0x00c2, 0x57af: 0x00c2,
0x57b0: 0x00c2, 0x57b1: 0x00c2, 0x57b2: 0x00c2, 0x57b3: 0x00c2, 0x57b4: 0x00c2, 0x57b5: 0x00c2,
0x57b6: 0x00c2, 0x57b7: 0x00c2, 0x57b8: 0x00c2, 0x57b9: 0x00c2, 0x57ba: 0x00c2, 0x57bb: 0x00c2,
0x57bc: 0x00c2, 0x57bd: 0x00c2, 0x57be: 0x00c2, 0x57bf: 0x00c2,
// Block 0x15f, offset 0x57c0
0x57c0: 0x00c2, 0x57c1: 0x00c2, 0x57c2: 0x00c2, 0x57c3: 0x00c2, 0x57c4: 0x00c3, 0x57c5: 0x00c3,
0x57c6: 0x00c3, 0x57c7: 0x00c3, 0x57c8: 0x00c3, 0x57c9: 0x00c3, 0x57ca: 0x00c3, 0x57cb: 0x00c3,
0x57d0: 0x00c0, 0x57d1: 0x00c0,
0x57d2: 0x00c0, 0x57d3: 0x00c0, 0x57d4: 0x00c0, 0x57d5: 0x00c0, 0x57d6: 0x00c0, 0x57d7: 0x00c0,
0x57d8: 0x00c0, 0x57d9: 0x00c0,
0x57de: 0x0080, 0x57df: 0x0080,
// Block 0x160, offset 0x5800
0x5831: 0x0080, 0x5832: 0x0080, 0x5833: 0x0080, 0x5834: 0x0080, 0x5835: 0x0080,
0x5836: 0x0080, 0x5837: 0x0080, 0x5838: 0x0080, 0x5839: 0x0080, 0x583a: 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, 0x585a: 0x0080, 0x585b: 0x0080, 0x585c: 0x0080, 0x585d: 0x0080,
0x585e: 0x0080, 0x585f: 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, 0x586c: 0x0080, 0x586d: 0x0080, 0x586e: 0x0080, 0x586f: 0x0080,
0x5870: 0x0080, 0x5871: 0x0080, 0x5872: 0x0080, 0x5873: 0x0080, 0x5874: 0x0080,
// Block 0x162, offset 0x5880
0x5881: 0x0080, 0x5882: 0x0080, 0x5883: 0x0080, 0x5884: 0x0080, 0x5885: 0x0080,
0x5886: 0x0080, 0x5887: 0x0080, 0x5888: 0x0080, 0x5889: 0x0080, 0x588a: 0x0080, 0x588b: 0x0080,
0x588c: 0x0080, 0x588d: 0x0080, 0x588e: 0x0080, 0x588f: 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,
// Block 0x163, offset 0x58c0
0x58c0: 0x0080, 0x58c1: 0x0080, 0x58c2: 0x0080, 0x58c3: 0x0080, 0x58c5: 0x0080,
0x58c6: 0x0080, 0x58c7: 0x0080, 0x58c8: 0x0080, 0x58c9: 0x0080, 0x58ca: 0x0080, 0x58cb: 0x0080,
0x58cc: 0x0080, 0x58cd: 0x0080, 0x58ce: 0x0080, 0x58cf: 0x0080, 0x58d0: 0x0080, 0x58d1: 0x0080,
0x58d2: 0x0080, 0x58d3: 0x0080, 0x58d4: 0x0080, 0x58d5: 0x0080, 0x58d6: 0x0080, 0x58d7: 0x0080,
0x58d8: 0x0080, 0x58d9: 0x0080, 0x58da: 0x0080, 0x58db: 0x0080, 0x58dc: 0x0080, 0x58dd: 0x0080,
0x58de: 0x0080, 0x58df: 0x0080, 0x58e1: 0x0080, 0x58e2: 0x0080,
0x58e4: 0x0080, 0x58e7: 0x0080, 0x58e9: 0x0080,
0x58ea: 0x0080, 0x58eb: 0x0080, 0x58ec: 0x0080, 0x58ed: 0x0080, 0x58ee: 0x0080, 0x58ef: 0x0080,
0x58f0: 0x0080, 0x58f1: 0x0080, 0x58f2: 0x0080, 0x58f4: 0x0080, 0x58f5: 0x0080,
0x58f6: 0x0080, 0x58f7: 0x0080, 0x58f9: 0x0080, 0x58fb: 0x0080,
// Block 0x164, offset 0x5900
0x5902: 0x0080,
0x5907: 0x0080, 0x5909: 0x0080, 0x590b: 0x0080,
0x590d: 0x0080, 0x590e: 0x0080, 0x590f: 0x0080, 0x5911: 0x0080,
0x5912: 0x0080, 0x5914: 0x0080, 0x5917: 0x0080,
0x5919: 0x0080, 0x591b: 0x0080, 0x591d: 0x0080,
0x591f: 0x0080, 0x5921: 0x0080, 0x5922: 0x0080,
0x5924: 0x0080, 0x5927: 0x0080, 0x5928: 0x0080, 0x5929: 0x0080,
0x592a: 0x0080, 0x592c: 0x0080, 0x592d: 0x0080, 0x592e: 0x0080, 0x592f: 0x0080,
0x5930: 0x0080, 0x5931: 0x0080, 0x5932: 0x0080, 0x5934: 0x0080, 0x5935: 0x0080,
0x5936: 0x0080, 0x5937: 0x0080, 0x5939: 0x0080, 0x593a: 0x0080, 0x593b: 0x0080,
0x593c: 0x0080, 0x593e: 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, 0x594b: 0x0080,
0x594c: 0x0080, 0x594d: 0x0080, 0x594e: 0x0080, 0x594f: 0x0080, 0x5950: 0x0080, 0x5951: 0x0080,
0x5952: 0x0080, 0x5953: 0x0080, 0x5954: 0x0080, 0x5955: 0x0080, 0x5956: 0x0080, 0x5957: 0x0080,
0x5958: 0x0080, 0x5959: 0x0080, 0x595a: 0x0080, 0x595b: 0x0080,
0x5961: 0x0080, 0x5962: 0x0080, 0x5963: 0x0080,
0x5965: 0x0080, 0x5966: 0x0080, 0x5967: 0x0080, 0x5968: 0x0080, 0x5969: 0x0080,
0x596b: 0x0080, 0x596c: 0x0080, 0x596d: 0x0080, 0x596e: 0x0080, 0x596f: 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,
// Block 0x166, offset 0x5980
0x59b0: 0x0080, 0x59b1: 0x0080,
// Block 0x167, offset 0x59c0
0x59c0: 0x0080, 0x59c1: 0x0080, 0x59c2: 0x0080, 0x59c3: 0x0080, 0x59c4: 0x0080, 0x59c5: 0x0080,
0x59c6: 0x0080, 0x59c7: 0x0080, 0x59c8: 0x0080, 0x59c9: 0x0080, 0x59ca: 0x0080, 0x59cb: 0x0080,
0x59cc: 0x0080, 0x59cd: 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, 0x59dc: 0x0080, 0x59dd: 0x0080,
0x59de: 0x0080, 0x59df: 0x0080, 0x59e0: 0x0080, 0x59e1: 0x0080, 0x59e2: 0x0080, 0x59e3: 0x0080,
0x59e4: 0x0080, 0x59e5: 0x0080, 0x59e6: 0x0080, 0x59e7: 0x0080, 0x59e8: 0x0080, 0x59e9: 0x0080,
0x59ea: 0x0080, 0x59eb: 0x0080,
0x59f0: 0x0080, 0x59f1: 0x0080, 0x59f2: 0x0080, 0x59f3: 0x0080, 0x59f4: 0x0080, 0x59f5: 0x0080,
0x59f6: 0x0080, 0x59f7: 0x0080, 0x59f8: 0x0080, 0x59f9: 0x0080, 0x59fa: 0x0080, 0x59fb: 0x0080,
0x59fc: 0x0080, 0x59fd: 0x0080, 0x59fe: 0x0080, 0x59ff: 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, 0x5a13: 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,
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
0x5a41: 0x0080, 0x5a42: 0x0080, 0x5a43: 0x0080, 0x5a44: 0x0080, 0x5a45: 0x0080,
0x5a46: 0x0080, 0x5a47: 0x0080, 0x5a48: 0x0080, 0x5a49: 0x0080, 0x5a4a: 0x0080, 0x5a4b: 0x0080,
0x5a4c: 0x0080, 0x5a4d: 0x0080, 0x5a4e: 0x0080, 0x5a4f: 0x0080, 0x5a51: 0x0080,
0x5a52: 0x0080, 0x5a53: 0x0080, 0x5a54: 0x0080, 0x5a55: 0x0080, 0x5a56: 0x0080, 0x5a57: 0x0080,
0x5a58: 0x0080, 0x5a59: 0x0080, 0x5a5a: 0x0080, 0x5a5b: 0x0080, 0x5a5c: 0x0080, 0x5a5d: 0x0080,
0x5a5e: 0x0080, 0x5a5f: 0x0080, 0x5a60: 0x0080, 0x5a61: 0x0080, 0x5a62: 0x0080, 0x5a63: 0x0080,
0x5a64: 0x0080, 0x5a65: 0x0080, 0x5a66: 0x0080, 0x5a67: 0x0080, 0x5a68: 0x0080, 0x5a69: 0x0080,
0x5a6a: 0x0080, 0x5a6b: 0x0080, 0x5a6c: 0x0080, 0x5a6d: 0x0080, 0x5a6e: 0x0080, 0x5a6f: 0x0080,
0x5a70: 0x0080, 0x5a71: 0x0080, 0x5a72: 0x0080, 0x5a73: 0x0080, 0x5a74: 0x0080, 0x5a75: 0x0080,
// Block 0x16a, offset 0x5a80
0x5aa6: 0x0080, 0x5aa7: 0x0080, 0x5aa8: 0x0080, 0x5aa9: 0x0080,
0x5aaa: 0x0080, 0x5aab: 0x0080, 0x5aac: 0x0080, 0x5aad: 0x0080, 0x5aae: 0x0080, 0x5aaf: 0x0080,
0x5ab0: 0x0080, 0x5ab1: 0x0080, 0x5ab2: 0x0080, 0x5ab3: 0x0080, 0x5ab4: 0x0080, 0x5ab5: 0x0080,
0x5ab6: 0x0080, 0x5ab7: 0x0080, 0x5ab8: 0x0080, 0x5ab9: 0x0080, 0x5aba: 0x0080, 0x5abb: 0x0080,
0x5abc: 0x0080, 0x5abd: 0x0080, 0x5abe: 0x0080, 0x5abf: 0x0080,
// Block 0x16b, offset 0x5ac0
0x5ac0: 0x008c, 0x5ac1: 0x0080, 0x5ac2: 0x0080,
0x5ad0: 0x0080, 0x5ad1: 0x0080,
0x5ad2: 0x0080, 0x5ad3: 0x0080, 0x5ad4: 0x0080, 0x5ad5: 0x0080, 0x5ad6: 0x0080, 0x5ad7: 0x0080,
0x5ad8: 0x0080, 0x5ad9: 0x0080, 0x5ada: 0x0080, 0x5adb: 0x0080, 0x5adc: 0x0080, 0x5add: 0x0080,
0x5ade: 0x0080, 0x5adf: 0x0080, 0x5ae0: 0x0080, 0x5ae1: 0x0080, 0x5ae2: 0x0080, 0x5ae3: 0x0080,
0x5ae4: 0x0080, 0x5ae5: 0x0080, 0x5ae6: 0x0080, 0x5ae7: 0x0080, 0x5ae8: 0x0080, 0x5ae9: 0x0080,
0x5aea: 0x0080, 0x5aeb: 0x0080, 0x5aec: 0x0080, 0x5aed: 0x0080, 0x5aee: 0x0080, 0x5aef: 0x0080,
0x5af0: 0x0080, 0x5af1: 0x0080, 0x5af2: 0x0080, 0x5af3: 0x0080, 0x5af4: 0x0080, 0x5af5: 0x0080,
0x5af6: 0x0080, 0x5af7: 0x0080, 0x5af8: 0x0080, 0x5af9: 0x0080, 0x5afa: 0x0080, 0x5afb: 0x0080,
// Block 0x16c, offset 0x5b00
0x5b00: 0x0080, 0x5b01: 0x0080, 0x5b02: 0x0080, 0x5b03: 0x0080, 0x5b04: 0x0080, 0x5b05: 0x0080,
0x5b06: 0x0080, 0x5b07: 0x0080, 0x5b08: 0x0080,
0x5b10: 0x0080, 0x5b11: 0x0080,
0x5b20: 0x0080, 0x5b21: 0x0080, 0x5b22: 0x0080, 0x5b23: 0x0080,
0x5b24: 0x0080, 0x5b25: 0x0080,
// Block 0x16d, offset 0x5b40
0x5b40: 0x0080, 0x5b41: 0x0080, 0x5b42: 0x0080, 0x5b43: 0x0080, 0x5b44: 0x0080, 0x5b45: 0x0080,
0x5b46: 0x0080, 0x5b47: 0x0080, 0x5b48: 0x0080, 0x5b49: 0x0080, 0x5b4a: 0x0080, 0x5b4b: 0x0080,
0x5b4c: 0x0080, 0x5b4d: 0x0080, 0x5b4e: 0x0080, 0x5b4f: 0x0080, 0x5b50: 0x0080, 0x5b51: 0x0080,
0x5b52: 0x0080, 0x5b53: 0x0080, 0x5b54: 0x0080, 0x5b55: 0x0080, 0x5b56: 0x0080, 0x5b57: 0x0080,
0x5b58: 0x0080, 0x5b5c: 0x0080, 0x5b5d: 0x0080,
0x5b5e: 0x0080, 0x5b5f: 0x0080, 0x5b60: 0x0080, 0x5b61: 0x0080, 0x5b62: 0x0080, 0x5b63: 0x0080,
0x5b64: 0x0080, 0x5b65: 0x0080, 0x5b66: 0x0080, 0x5b67: 0x0080, 0x5b68: 0x0080, 0x5b69: 0x0080,
0x5b6a: 0x0080, 0x5b6b: 0x0080, 0x5b6c: 0x0080,
0x5b70: 0x0080, 0x5b71: 0x0080, 0x5b72: 0x0080, 0x5b73: 0x0080, 0x5b74: 0x0080, 0x5b75: 0x0080,
0x5b76: 0x0080, 0x5b77: 0x0080, 0x5b78: 0x0080, 0x5b79: 0x0080, 0x5b7a: 0x0080, 0x5b7b: 0x0080,
0x5b7c: 0x0080,
// Block 0x16e, offset 0x5b80
0x5b80: 0x0080, 0x5b81: 0x0080, 0x5b82: 0x0080, 0x5b83: 0x0080, 0x5b84: 0x0080, 0x5b85: 0x0080,
0x5b86: 0x0080, 0x5b87: 0x0080, 0x5b88: 0x0080, 0x5b89: 0x0080, 0x5b8a: 0x0080, 0x5b8b: 0x0080,
0x5b8c: 0x0080, 0x5b8d: 0x0080, 0x5b8e: 0x0080, 0x5b8f: 0x0080, 0x5b90: 0x0080, 0x5b91: 0x0080,
0x5b92: 0x0080, 0x5b93: 0x0080, 0x5b94: 0x0080, 0x5b95: 0x0080, 0x5b96: 0x0080, 0x5b97: 0x0080,
0x5b98: 0x0080, 0x5b99: 0x0080,
0x5ba0: 0x0080, 0x5ba1: 0x0080, 0x5ba2: 0x0080, 0x5ba3: 0x0080,
0x5ba4: 0x0080, 0x5ba5: 0x0080, 0x5ba6: 0x0080, 0x5ba7: 0x0080, 0x5ba8: 0x0080, 0x5ba9: 0x0080,
0x5baa: 0x0080, 0x5bab: 0x0080,
0x5bb0: 0x0080,
// Block 0x16f, offset 0x5bc0
0x5bc0: 0x0080, 0x5bc1: 0x0080, 0x5bc2: 0x0080, 0x5bc3: 0x0080, 0x5bc4: 0x0080, 0x5bc5: 0x0080,
0x5bc6: 0x0080, 0x5bc7: 0x0080, 0x5bc8: 0x0080, 0x5bc9: 0x0080, 0x5bca: 0x0080, 0x5bcb: 0x0080,
0x5bd0: 0x0080, 0x5bd1: 0x0080,
0x5bd2: 0x0080, 0x5bd3: 0x0080, 0x5bd4: 0x0080, 0x5bd5: 0x0080, 0x5bd6: 0x0080, 0x5bd7: 0x0080,
0x5bd8: 0x0080, 0x5bd9: 0x0080, 0x5bda: 0x0080, 0x5bdb: 0x0080, 0x5bdc: 0x0080, 0x5bdd: 0x0080,
0x5bde: 0x0080, 0x5bdf: 0x0080, 0x5be0: 0x0080, 0x5be1: 0x0080, 0x5be2: 0x0080, 0x5be3: 0x0080,
0x5be4: 0x0080, 0x5be5: 0x0080, 0x5be6: 0x0080, 0x5be7: 0x0080, 0x5be8: 0x0080, 0x5be9: 0x0080,
0x5bea: 0x0080, 0x5beb: 0x0080, 0x5bec: 0x0080, 0x5bed: 0x0080, 0x5bee: 0x0080, 0x5bef: 0x0080,
0x5bf0: 0x0080, 0x5bf1: 0x0080, 0x5bf2: 0x0080, 0x5bf3: 0x0080, 0x5bf4: 0x0080, 0x5bf5: 0x0080,
0x5bf6: 0x0080, 0x5bf7: 0x0080, 0x5bf8: 0x0080, 0x5bf9: 0x0080, 0x5bfa: 0x0080, 0x5bfb: 0x0080,
0x5bfc: 0x0080, 0x5bfd: 0x0080, 0x5bfe: 0x0080, 0x5bff: 0x0080,
// Block 0x170, offset 0x5c00
0x5c00: 0x0080, 0x5c01: 0x0080, 0x5c02: 0x0080, 0x5c03: 0x0080, 0x5c04: 0x0080, 0x5c05: 0x0080,
0x5c06: 0x0080, 0x5c07: 0x0080,
0x5c10: 0x0080, 0x5c11: 0x0080,
0x5c12: 0x0080, 0x5c13: 0x0080, 0x5c14: 0x0080, 0x5c15: 0x0080, 0x5c16: 0x0080, 0x5c17: 0x0080,
0x5c18: 0x0080, 0x5c19: 0x0080,
0x5c20: 0x0080, 0x5c21: 0x0080, 0x5c22: 0x0080, 0x5c23: 0x0080,
0x5c24: 0x0080, 0x5c25: 0x0080, 0x5c26: 0x0080, 0x5c27: 0x0080, 0x5c28: 0x0080, 0x5c29: 0x0080,
0x5c2a: 0x0080, 0x5c2b: 0x0080, 0x5c2c: 0x0080, 0x5c2d: 0x0080, 0x5c2e: 0x0080, 0x5c2f: 0x0080,
0x5c30: 0x0080, 0x5c31: 0x0080, 0x5c32: 0x0080, 0x5c33: 0x0080, 0x5c34: 0x0080, 0x5c35: 0x0080,
0x5c36: 0x0080, 0x5c37: 0x0080, 0x5c38: 0x0080, 0x5c39: 0x0080, 0x5c3a: 0x0080, 0x5c3b: 0x0080,
0x5c3c: 0x0080, 0x5c3d: 0x0080, 0x5c3e: 0x0080, 0x5c3f: 0x0080,
// Block 0x171, offset 0x5c40
0x5c40: 0x0080, 0x5c41: 0x0080, 0x5c42: 0x0080, 0x5c43: 0x0080, 0x5c44: 0x0080, 0x5c45: 0x0080,
0x5c46: 0x0080, 0x5c47: 0x0080,
0x5c50: 0x0080, 0x5c51: 0x0080,
0x5c52: 0x0080, 0x5c53: 0x0080, 0x5c54: 0x0080, 0x5c55: 0x0080, 0x5c56: 0x0080, 0x5c57: 0x0080,
0x5c58: 0x0080, 0x5c59: 0x0080, 0x5c5a: 0x0080, 0x5c5b: 0x0080, 0x5c5c: 0x0080, 0x5c5d: 0x0080,
0x5c5e: 0x0080, 0x5c5f: 0x0080, 0x5c60: 0x0080, 0x5c61: 0x0080, 0x5c62: 0x0080, 0x5c63: 0x0080,
0x5c64: 0x0080, 0x5c65: 0x0080, 0x5c66: 0x0080, 0x5c67: 0x0080, 0x5c68: 0x0080, 0x5c69: 0x0080,
0x5c6a: 0x0080, 0x5c6b: 0x0080, 0x5c6c: 0x0080, 0x5c6d: 0x0080,
0x5c70: 0x0080, 0x5c71: 0x0080, 0x5c72: 0x0080, 0x5c73: 0x0080, 0x5c74: 0x0080, 0x5c75: 0x0080,
0x5c76: 0x0080, 0x5c77: 0x0080, 0x5c78: 0x0080, 0x5c79: 0x0080, 0x5c7a: 0x0080, 0x5c7b: 0x0080,
// Block 0x172, offset 0x5c80
0x5c80: 0x0080, 0x5c81: 0x0080,
0x5c90: 0x0080, 0x5c91: 0x0080,
0x5c92: 0x0080, 0x5c93: 0x0080, 0x5c94: 0x0080, 0x5c95: 0x0080, 0x5c96: 0x0080, 0x5c97: 0x0080,
0x5c98: 0x0080,
// Block 0x173, offset 0x5cc0
0x5cc0: 0x0080, 0x5cc1: 0x0080, 0x5cc2: 0x0080, 0x5cc3: 0x0080, 0x5cc4: 0x0080, 0x5cc5: 0x0080,
0x5cc6: 0x0080, 0x5cc7: 0x0080, 0x5cc8: 0x0080, 0x5cc9: 0x0080, 0x5cca: 0x0080, 0x5ccb: 0x0080,
0x5ccc: 0x0080, 0x5ccd: 0x0080, 0x5cce: 0x0080, 0x5ccf: 0x0080, 0x5cd0: 0x0080, 0x5cd1: 0x0080,
0x5cd2: 0x0080, 0x5cd3: 0x0080, 0x5cd4: 0x0080, 0x5cd5: 0x0080, 0x5cd6: 0x0080, 0x5cd7: 0x0080,
0x5ce0: 0x0080, 0x5ce1: 0x0080, 0x5ce2: 0x0080, 0x5ce3: 0x0080,
0x5ce4: 0x0080, 0x5ce5: 0x0080, 0x5ce6: 0x0080, 0x5ce7: 0x0080, 0x5ce8: 0x0080, 0x5ce9: 0x0080,
0x5cea: 0x0080, 0x5ceb: 0x0080, 0x5cec: 0x0080, 0x5ced: 0x0080,
0x5cf0: 0x0080, 0x5cf1: 0x0080, 0x5cf2: 0x0080, 0x5cf3: 0x0080, 0x5cf4: 0x0080, 0x5cf5: 0x0080,
0x5cf6: 0x0080, 0x5cf7: 0x0080, 0x5cf8: 0x0080, 0x5cf9: 0x0080, 0x5cfa: 0x0080, 0x5cfb: 0x0080,
0x5cfc: 0x0080,
// Block 0x174, offset 0x5d00
0x5d00: 0x0080, 0x5d01: 0x0080, 0x5d02: 0x0080, 0x5d03: 0x0080, 0x5d04: 0x0080, 0x5d05: 0x0080,
0x5d06: 0x0080, 0x5d07: 0x0080, 0x5d08: 0x0080, 0x5d09: 0x0080, 0x5d0a: 0x0080,
0x5d0e: 0x0080, 0x5d0f: 0x0080, 0x5d10: 0x0080, 0x5d11: 0x0080,
0x5d12: 0x0080, 0x5d13: 0x0080, 0x5d14: 0x0080, 0x5d15: 0x0080, 0x5d16: 0x0080, 0x5d17: 0x0080,
0x5d18: 0x0080, 0x5d19: 0x0080, 0x5d1a: 0x0080, 0x5d1b: 0x0080, 0x5d1c: 0x0080, 0x5d1d: 0x0080,
0x5d1e: 0x0080, 0x5d1f: 0x0080, 0x5d20: 0x0080, 0x5d21: 0x0080, 0x5d22: 0x0080, 0x5d23: 0x0080,
0x5d24: 0x0080, 0x5d25: 0x0080, 0x5d26: 0x0080, 0x5d27: 0x0080, 0x5d28: 0x0080, 0x5d29: 0x0080,
0x5d2a: 0x0080, 0x5d2b: 0x0080, 0x5d2c: 0x0080, 0x5d2d: 0x0080, 0x5d2e: 0x0080, 0x5d2f: 0x0080,
0x5d30: 0x0080, 0x5d31: 0x0080, 0x5d32: 0x0080, 0x5d33: 0x0080, 0x5d34: 0x0080, 0x5d35: 0x0080,
0x5d36: 0x0080, 0x5d37: 0x0080, 0x5d38: 0x0080, 0x5d39: 0x0080, 0x5d3a: 0x0080, 0x5d3b: 0x0080,
0x5d3c: 0x0080, 0x5d3d: 0x0080, 0x5d3e: 0x0080, 0x5d3f: 0x0080,
// Block 0x175, offset 0x5d40
0x5d40: 0x0080, 0x5d41: 0x0080, 0x5d42: 0x0080, 0x5d43: 0x0080, 0x5d44: 0x0080, 0x5d45: 0x0080,
0x5d46: 0x0080, 0x5d48: 0x0080,
0x5d4d: 0x0080, 0x5d4e: 0x0080, 0x5d4f: 0x0080, 0x5d50: 0x0080, 0x5d51: 0x0080,
0x5d52: 0x0080, 0x5d53: 0x0080, 0x5d54: 0x0080, 0x5d55: 0x0080, 0x5d56: 0x0080, 0x5d57: 0x0080,
0x5d58: 0x0080, 0x5d59: 0x0080, 0x5d5a: 0x0080, 0x5d5b: 0x0080, 0x5d5c: 0x0080,
0x5d5f: 0x0080, 0x5d60: 0x0080, 0x5d61: 0x0080, 0x5d62: 0x0080, 0x5d63: 0x0080,
0x5d64: 0x0080, 0x5d65: 0x0080, 0x5d66: 0x0080, 0x5d67: 0x0080, 0x5d68: 0x0080, 0x5d69: 0x0080,
0x5d6a: 0x0080, 0x5d6f: 0x0080,
0x5d70: 0x0080, 0x5d71: 0x0080, 0x5d72: 0x0080, 0x5d73: 0x0080, 0x5d74: 0x0080, 0x5d75: 0x0080,
0x5d76: 0x0080, 0x5d77: 0x0080, 0x5d78: 0x0080,
// Block 0x176, offset 0x5d80
0x5d80: 0x0080, 0x5d81: 0x0080, 0x5d82: 0x0080, 0x5d83: 0x0080, 0x5d84: 0x0080, 0x5d85: 0x0080,
0x5d86: 0x0080, 0x5d87: 0x0080, 0x5d88: 0x0080, 0x5d89: 0x0080, 0x5d8a: 0x0080, 0x5d8b: 0x0080,
0x5d8c: 0x0080, 0x5d8d: 0x0080, 0x5d8e: 0x0080, 0x5d8f: 0x0080, 0x5d90: 0x0080, 0x5d91: 0x0080,
0x5d92: 0x0080, 0x5d94: 0x0080, 0x5d95: 0x0080, 0x5d96: 0x0080, 0x5d97: 0x0080,
0x5d98: 0x0080, 0x5d99: 0x0080, 0x5d9a: 0x0080, 0x5d9b: 0x0080, 0x5d9c: 0x0080, 0x5d9d: 0x0080,
0x5d9e: 0x0080, 0x5d9f: 0x0080, 0x5da0: 0x0080, 0x5da1: 0x0080, 0x5da2: 0x0080, 0x5da3: 0x0080,
0x5da4: 0x0080, 0x5da5: 0x0080, 0x5da6: 0x0080, 0x5da7: 0x0080, 0x5da8: 0x0080, 0x5da9: 0x0080,
0x5daa: 0x0080, 0x5dab: 0x0080, 0x5dac: 0x0080, 0x5dad: 0x0080, 0x5dae: 0x0080, 0x5daf: 0x0080,
0x5db0: 0x0080, 0x5db1: 0x0080, 0x5db2: 0x0080, 0x5db3: 0x0080, 0x5db4: 0x0080, 0x5db5: 0x0080,
0x5db6: 0x0080, 0x5db7: 0x0080, 0x5db8: 0x0080, 0x5db9: 0x0080, 0x5dba: 0x0080, 0x5dbb: 0x0080,
0x5dbc: 0x0080, 0x5dbd: 0x0080, 0x5dbe: 0x0080, 0x5dbf: 0x0080,
// Block 0x177, offset 0x5dc0
0x5dc0: 0x0080, 0x5dc1: 0x0080, 0x5dc2: 0x0080, 0x5dc3: 0x0080, 0x5dc4: 0x0080, 0x5dc5: 0x0080,
0x5dc6: 0x0080, 0x5dc7: 0x0080, 0x5dc8: 0x0080, 0x5dc9: 0x0080, 0x5dca: 0x0080, 0x5dcb: 0x0080,
0x5dcc: 0x0080, 0x5dcd: 0x0080, 0x5dce: 0x0080, 0x5dcf: 0x0080, 0x5dd0: 0x0080, 0x5dd1: 0x0080,
0x5dd2: 0x0080, 0x5dd3: 0x0080, 0x5dd4: 0x0080, 0x5dd5: 0x0080, 0x5dd6: 0x0080, 0x5dd7: 0x0080,
0x5dd8: 0x0080, 0x5dd9: 0x0080, 0x5dda: 0x0080, 0x5ddb: 0x0080, 0x5ddc: 0x0080, 0x5ddd: 0x0080,
0x5dde: 0x0080, 0x5ddf: 0x0080, 0x5de0: 0x0080, 0x5de1: 0x0080, 0x5de2: 0x0080, 0x5de3: 0x0080,
0x5de4: 0x0080, 0x5de5: 0x0080, 0x5de6: 0x0080, 0x5de7: 0x0080, 0x5de8: 0x0080, 0x5de9: 0x0080,
0x5dea: 0x0080, 0x5deb: 0x0080, 0x5dec: 0x0080, 0x5ded: 0x0080, 0x5dee: 0x0080, 0x5def: 0x0080,
0x5df0: 0x0080, 0x5df1: 0x0080, 0x5df2: 0x0080, 0x5df3: 0x0080, 0x5df4: 0x0080, 0x5df5: 0x0080,
0x5df6: 0x0080, 0x5df7: 0x0080, 0x5df8: 0x0080, 0x5df9: 0x0080, 0x5dfa: 0x0080,
// Block 0x178, offset 0x5e00
0x5e00: 0x00cc, 0x5e01: 0x00cc, 0x5e02: 0x00cc, 0x5e03: 0x00cc, 0x5e04: 0x00cc, 0x5e05: 0x00cc,
0x5e06: 0x00cc, 0x5e07: 0x00cc, 0x5e08: 0x00cc, 0x5e09: 0x00cc, 0x5e0a: 0x00cc, 0x5e0b: 0x00cc,
0x5e0c: 0x00cc, 0x5e0d: 0x00cc, 0x5e0e: 0x00cc, 0x5e0f: 0x00cc, 0x5e10: 0x00cc, 0x5e11: 0x00cc,
0x5e12: 0x00cc, 0x5e13: 0x00cc, 0x5e14: 0x00cc, 0x5e15: 0x00cc, 0x5e16: 0x00cc, 0x5e17: 0x00cc,
0x5e18: 0x00cc, 0x5e19: 0x00cc, 0x5e1a: 0x00cc, 0x5e1b: 0x00cc, 0x5e1c: 0x00cc, 0x5e1d: 0x00cc,
0x5e1e: 0x00cc, 0x5e1f: 0x00cc,
// Block 0x179, offset 0x5e40
0x5e40: 0x00cc, 0x5e41: 0x00cc, 0x5e42: 0x00cc, 0x5e43: 0x00cc, 0x5e44: 0x00cc, 0x5e45: 0x00cc,
0x5e46: 0x00cc, 0x5e47: 0x00cc, 0x5e48: 0x00cc, 0x5e49: 0x00cc, 0x5e4a: 0x00cc, 0x5e4b: 0x00cc,
0x5e4c: 0x00cc, 0x5e4d: 0x00cc, 0x5e4e: 0x00cc, 0x5e4f: 0x00cc, 0x5e50: 0x00cc, 0x5e51: 0x00cc,
0x5e52: 0x00cc, 0x5e53: 0x00cc, 0x5e54: 0x00cc, 0x5e55: 0x00cc, 0x5e56: 0x00cc, 0x5e57: 0x00cc,
0x5e58: 0x00cc, 0x5e59: 0x00cc, 0x5e5a: 0x00cc, 0x5e5b: 0x00cc, 0x5e5c: 0x00cc, 0x5e5d: 0x00cc,
0x5e60: 0x00cc, 0x5e61: 0x00cc, 0x5e62: 0x00cc, 0x5e63: 0x00cc,
0x5e64: 0x00cc, 0x5e65: 0x00cc, 0x5e66: 0x00cc, 0x5e67: 0x00cc, 0x5e68: 0x00cc, 0x5e69: 0x00cc,
0x5e6a: 0x00cc, 0x5e6b: 0x00cc, 0x5e6c: 0x00cc, 0x5e6d: 0x00cc, 0x5e6e: 0x00cc, 0x5e6f: 0x00cc,
0x5e70: 0x00cc, 0x5e71: 0x00cc, 0x5e72: 0x00cc, 0x5e73: 0x00cc, 0x5e74: 0x00cc, 0x5e75: 0x00cc,
0x5e76: 0x00cc, 0x5e77: 0x00cc, 0x5e78: 0x00cc, 0x5e79: 0x00cc, 0x5e7a: 0x00cc, 0x5e7b: 0x00cc,
0x5e7c: 0x00cc, 0x5e7d: 0x00cc, 0x5e7e: 0x00cc, 0x5e7f: 0x00cc,
// Block 0x17a, offset 0x5e80
0x5e80: 0x00cc, 0x5e81: 0x00cc, 0x5e82: 0x00cc, 0x5e83: 0x00cc, 0x5e84: 0x00cc, 0x5e85: 0x00cc,
0x5e86: 0x00cc, 0x5e87: 0x00cc, 0x5e88: 0x00cc, 0x5e89: 0x00cc, 0x5e8a: 0x00cc, 0x5e8b: 0x00cc,
0x5e8c: 0x00cc, 0x5e8d: 0x00cc, 0x5e8e: 0x00cc, 0x5e8f: 0x00cc, 0x5e90: 0x00cc, 0x5e91: 0x00cc,
0x5e92: 0x00cc, 0x5e93: 0x00cc, 0x5e94: 0x00cc, 0x5e95: 0x00cc, 0x5e96: 0x00cc, 0x5e97: 0x00cc,
0x5e98: 0x00cc, 0x5e99: 0x00cc, 0x5e9a: 0x00cc, 0x5e9b: 0x00cc, 0x5e9c: 0x00cc, 0x5e9d: 0x00cc,
0x5e9e: 0x00cc, 0x5e9f: 0x00cc, 0x5ea0: 0x00cc, 0x5ea1: 0x00cc, 0x5ea2: 0x00cc, 0x5ea3: 0x00cc,
0x5ea4: 0x00cc, 0x5ea5: 0x00cc, 0x5ea6: 0x00cc, 0x5ea7: 0x00cc, 0x5ea8: 0x00cc, 0x5ea9: 0x00cc,
0x5eaa: 0x00cc, 0x5eab: 0x00cc, 0x5eac: 0x00cc, 0x5ead: 0x00cc,
0x5eb0: 0x00cc, 0x5eb1: 0x00cc, 0x5eb2: 0x00cc, 0x5eb3: 0x00cc, 0x5eb4: 0x00cc, 0x5eb5: 0x00cc,
0x5eb6: 0x00cc, 0x5eb7: 0x00cc, 0x5eb8: 0x00cc, 0x5eb9: 0x00cc, 0x5eba: 0x00cc, 0x5ebb: 0x00cc,
0x5ebc: 0x00cc, 0x5ebd: 0x00cc, 0x5ebe: 0x00cc, 0x5ebf: 0x00cc,
// Block 0x17b, offset 0x5ec0
0x5ec0: 0x00cc, 0x5ec1: 0x00cc, 0x5ec2: 0x00cc, 0x5ec3: 0x00cc, 0x5ec4: 0x00cc, 0x5ec5: 0x00cc,
0x5ec6: 0x00cc, 0x5ec7: 0x00cc, 0x5ec8: 0x00cc, 0x5ec9: 0x00cc, 0x5eca: 0x00cc, 0x5ecb: 0x00cc,
0x5ecc: 0x00cc, 0x5ecd: 0x00cc, 0x5ece: 0x00cc, 0x5ecf: 0x00cc, 0x5ed0: 0x00cc, 0x5ed1: 0x00cc,
0x5ed2: 0x00cc, 0x5ed3: 0x00cc, 0x5ed4: 0x00cc, 0x5ed5: 0x00cc, 0x5ed6: 0x00cc, 0x5ed7: 0x00cc,
0x5ed8: 0x00cc, 0x5ed9: 0x00cc, 0x5eda: 0x00cc, 0x5edb: 0x00cc, 0x5edc: 0x00cc, 0x5edd: 0x00cc,
0x5ede: 0x00cc, 0x5edf: 0x00cc, 0x5ee0: 0x00cc,
0x5ef0: 0x00cc, 0x5ef1: 0x00cc, 0x5ef2: 0x00cc, 0x5ef3: 0x00cc, 0x5ef4: 0x00cc, 0x5ef5: 0x00cc,
0x5ef6: 0x00cc, 0x5ef7: 0x00cc, 0x5ef8: 0x00cc, 0x5ef9: 0x00cc, 0x5efa: 0x00cc, 0x5efb: 0x00cc,
0x5efc: 0x00cc, 0x5efd: 0x00cc, 0x5efe: 0x00cc, 0x5eff: 0x00cc,
// Block 0x17c, offset 0x5f00
0x5f00: 0x00cc, 0x5f01: 0x00cc, 0x5f02: 0x00cc, 0x5f03: 0x00cc, 0x5f04: 0x00cc, 0x5f05: 0x00cc,
0x5f06: 0x00cc, 0x5f07: 0x00cc, 0x5f08: 0x00cc, 0x5f09: 0x00cc, 0x5f0a: 0x00cc, 0x5f0b: 0x00cc,
0x5f0c: 0x00cc, 0x5f0d: 0x00cc, 0x5f0e: 0x00cc, 0x5f0f: 0x00cc, 0x5f10: 0x00cc, 0x5f11: 0x00cc,
0x5f12: 0x00cc, 0x5f13: 0x00cc, 0x5f14: 0x00cc, 0x5f15: 0x00cc, 0x5f16: 0x00cc, 0x5f17: 0x00cc,
0x5f18: 0x00cc, 0x5f19: 0x00cc, 0x5f1a: 0x00cc, 0x5f1b: 0x00cc, 0x5f1c: 0x00cc, 0x5f1d: 0x00cc,
// Block 0x17d, offset 0x5f40
0x5f40: 0x008c, 0x5f41: 0x008c, 0x5f42: 0x008c, 0x5f43: 0x008c, 0x5f44: 0x008c, 0x5f45: 0x008c,
0x5f46: 0x008c, 0x5f47: 0x008c, 0x5f48: 0x008c, 0x5f49: 0x008c, 0x5f4a: 0x008c, 0x5f4b: 0x008c,
0x5f4c: 0x008c, 0x5f4d: 0x008c, 0x5f4e: 0x008c, 0x5f4f: 0x008c, 0x5f50: 0x008c, 0x5f51: 0x008c,
0x5f52: 0x008c, 0x5f53: 0x008c, 0x5f54: 0x008c, 0x5f55: 0x008c, 0x5f56: 0x008c, 0x5f57: 0x008c,
0x5f58: 0x008c, 0x5f59: 0x008c, 0x5f5a: 0x008c, 0x5f5b: 0x008c, 0x5f5c: 0x008c, 0x5f5d: 0x008c,
// Block 0x17e, offset 0x5f80
0x5f80: 0x00cc, 0x5f81: 0x00cc, 0x5f82: 0x00cc, 0x5f83: 0x00cc, 0x5f84: 0x00cc, 0x5f85: 0x00cc,
0x5f86: 0x00cc, 0x5f87: 0x00cc, 0x5f88: 0x00cc, 0x5f89: 0x00cc, 0x5f8a: 0x00cc,
0x5f90: 0x00cc, 0x5f91: 0x00cc,
0x5f92: 0x00cc, 0x5f93: 0x00cc, 0x5f94: 0x00cc, 0x5f95: 0x00cc, 0x5f96: 0x00cc, 0x5f97: 0x00cc,
0x5f98: 0x00cc, 0x5f99: 0x00cc, 0x5f9a: 0x00cc, 0x5f9b: 0x00cc, 0x5f9c: 0x00cc, 0x5f9d: 0x00cc,
0x5f9e: 0x00cc, 0x5f9f: 0x00cc, 0x5fa0: 0x00cc, 0x5fa1: 0x00cc, 0x5fa2: 0x00cc, 0x5fa3: 0x00cc,
0x5fa4: 0x00cc, 0x5fa5: 0x00cc, 0x5fa6: 0x00cc, 0x5fa7: 0x00cc, 0x5fa8: 0x00cc, 0x5fa9: 0x00cc,
0x5faa: 0x00cc, 0x5fab: 0x00cc, 0x5fac: 0x00cc, 0x5fad: 0x00cc, 0x5fae: 0x00cc, 0x5faf: 0x00cc,
0x5fb0: 0x00cc, 0x5fb1: 0x00cc, 0x5fb2: 0x00cc, 0x5fb3: 0x00cc, 0x5fb4: 0x00cc, 0x5fb5: 0x00cc,
0x5fb6: 0x00cc, 0x5fb7: 0x00cc, 0x5fb8: 0x00cc, 0x5fb9: 0x00cc, 0x5fba: 0x00cc, 0x5fbb: 0x00cc,
0x5fbc: 0x00cc, 0x5fbd: 0x00cc, 0x5fbe: 0x00cc, 0x5fbf: 0x00cc,
// Block 0x17f, offset 0x5fc0
0x5fc0: 0x00cc, 0x5fc1: 0x00cc, 0x5fc2: 0x00cc, 0x5fc3: 0x00cc, 0x5fc4: 0x00cc, 0x5fc5: 0x00cc,
0x5fc6: 0x00cc, 0x5fc7: 0x00cc, 0x5fc8: 0x00cc, 0x5fc9: 0x00cc, 0x5fca: 0x00cc, 0x5fcb: 0x00cc,
0x5fcc: 0x00cc, 0x5fcd: 0x00cc, 0x5fce: 0x00cc, 0x5fcf: 0x00cc, 0x5fd0: 0x00cc, 0x5fd1: 0x00cc,
0x5fd2: 0x00cc, 0x5fd3: 0x00cc, 0x5fd4: 0x00cc, 0x5fd5: 0x00cc, 0x5fd6: 0x00cc, 0x5fd7: 0x00cc,
0x5fd8: 0x00cc, 0x5fd9: 0x00cc, 0x5fda: 0x00cc, 0x5fdb: 0x00cc, 0x5fdc: 0x00cc, 0x5fdd: 0x00cc,
0x5fde: 0x00cc, 0x5fdf: 0x00cc, 0x5fe0: 0x00cc, 0x5fe1: 0x00cc, 0x5fe2: 0x00cc, 0x5fe3: 0x00cc,
0x5fe4: 0x00cc, 0x5fe5: 0x00cc, 0x5fe6: 0x00cc, 0x5fe7: 0x00cc, 0x5fe8: 0x00cc, 0x5fe9: 0x00cc,
0x5fea: 0x00cc, 0x5feb: 0x00cc, 0x5fec: 0x00cc, 0x5fed: 0x00cc, 0x5fee: 0x00cc, 0x5fef: 0x00cc,
0x5ff0: 0x00cc, 0x5ff1: 0x00cc, 0x5ff2: 0x00cc, 0x5ff3: 0x00cc, 0x5ff4: 0x00cc, 0x5ff5: 0x00cc,
0x5ff6: 0x00cc, 0x5ff7: 0x00cc, 0x5ff8: 0x00cc, 0x5ff9: 0x00cc,
// Block 0x180, offset 0x6000
0x6001: 0x0040,
0x6020: 0x0040, 0x6021: 0x0040, 0x6022: 0x0040, 0x6023: 0x0040,
0x6024: 0x0040, 0x6025: 0x0040, 0x6026: 0x0040, 0x6027: 0x0040, 0x6028: 0x0040, 0x6029: 0x0040,
0x602a: 0x0040, 0x602b: 0x0040, 0x602c: 0x0040, 0x602d: 0x0040, 0x602e: 0x0040, 0x602f: 0x0040,
0x6030: 0x0040, 0x6031: 0x0040, 0x6032: 0x0040, 0x6033: 0x0040, 0x6034: 0x0040, 0x6035: 0x0040,
0x6036: 0x0040, 0x6037: 0x0040, 0x6038: 0x0040, 0x6039: 0x0040, 0x603a: 0x0040, 0x603b: 0x0040,
0x603c: 0x0040, 0x603d: 0x0040, 0x603e: 0x0040, 0x603f: 0x0040,
// Block 0x181, offset 0x6040
0x6040: 0x0040, 0x6041: 0x0040, 0x6042: 0x0040, 0x6043: 0x0040, 0x6044: 0x0040, 0x6045: 0x0040,
0x6046: 0x0040, 0x6047: 0x0040, 0x6048: 0x0040, 0x6049: 0x0040, 0x604a: 0x0040, 0x604b: 0x0040,
0x604c: 0x0040, 0x604d: 0x0040, 0x604e: 0x0040, 0x604f: 0x0040, 0x6050: 0x0040, 0x6051: 0x0040,
0x6052: 0x0040, 0x6053: 0x0040, 0x6054: 0x0040, 0x6055: 0x0040, 0x6056: 0x0040, 0x6057: 0x0040,
0x6058: 0x0040, 0x6059: 0x0040, 0x605a: 0x0040, 0x605b: 0x0040, 0x605c: 0x0040, 0x605d: 0x0040,
0x605e: 0x0040, 0x605f: 0x0040, 0x6060: 0x0040, 0x6061: 0x0040, 0x6062: 0x0040, 0x6063: 0x0040,
0x6064: 0x0040, 0x6065: 0x0040, 0x6066: 0x0040, 0x6067: 0x0040, 0x6068: 0x0040, 0x6069: 0x0040,
0x606a: 0x0040, 0x606b: 0x0040, 0x606c: 0x0040, 0x606d: 0x0040, 0x606e: 0x0040, 0x606f: 0x0040,
// Block 0x182, offset 0x6080
0x6080: 0x0040, 0x6081: 0x0040, 0x6082: 0x0040, 0x6083: 0x0040, 0x6084: 0x0040, 0x6085: 0x0040,
0x6086: 0x0040, 0x6087: 0x0040, 0x6088: 0x0040, 0x6089: 0x0040, 0x608a: 0x0040, 0x608b: 0x0040,
0x608c: 0x0040, 0x608d: 0x0040, 0x608e: 0x0040, 0x608f: 0x0040, 0x6090: 0x0040, 0x6091: 0x0040,
0x6092: 0x0040, 0x6093: 0x0040, 0x6094: 0x0040, 0x6095: 0x0040, 0x6096: 0x0040, 0x6097: 0x0040,
0x6098: 0x0040, 0x6099: 0x0040, 0x609a: 0x0040, 0x609b: 0x0040, 0x609c: 0x0040, 0x609d: 0x0040,
0x609e: 0x0040, 0x609f: 0x0040, 0x60a0: 0x0040, 0x60a1: 0x0040, 0x60a2: 0x0040, 0x60a3: 0x0040,
0x60a4: 0x0040, 0x60a5: 0x0040, 0x60a6: 0x0040, 0x60a7: 0x0040, 0x60a8: 0x0040, 0x60a9: 0x0040,
0x60aa: 0x0040, 0x60ab: 0x0040, 0x60ac: 0x0040, 0x60ad: 0x0040, 0x60ae: 0x0040, 0x60af: 0x0040,
0x60b0: 0x0040, 0x60b1: 0x0040, 0x60b2: 0x0040, 0x60b3: 0x0040, 0x60b4: 0x0040, 0x60b5: 0x0040,
0x60b6: 0x0040, 0x60b7: 0x0040, 0x60b8: 0x0040, 0x60b9: 0x0040, 0x60ba: 0x0040, 0x60bb: 0x0040,
0x60bc: 0x0040, 0x60bd: 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: 0x71, 0x1af: 0x71,
0x1b0: 0x05, 0x1b1: 0x75, 0x1b2: 0x05, 0x1b3: 0x76, 0x1b4: 0x77, 0x1b5: 0x78, 0x1b6: 0x79, 0x1b7: 0x7a,
0x1b8: 0x7b, 0x1b9: 0x7c, 0x1ba: 0x7d, 0x1bb: 0x7e, 0x1bc: 0x7f, 0x1bd: 0x7f, 0x1be: 0x7f, 0x1bf: 0x80,
// Block 0x7, offset 0x1c0
0x1c0: 0x81, 0x1c1: 0x82, 0x1c2: 0x83, 0x1c3: 0x84, 0x1c4: 0x85, 0x1c5: 0x86, 0x1c6: 0x87, 0x1c7: 0x88,
0x1c8: 0x89, 0x1c9: 0x71, 0x1ca: 0x71, 0x1cb: 0x8a, 0x1cc: 0x7f, 0x1cd: 0x8b, 0x1ce: 0x71, 0x1cf: 0x71,
0x1d0: 0x8c, 0x1d1: 0x8c, 0x1d2: 0x8c, 0x1d3: 0x8c, 0x1d4: 0x8c, 0x1d5: 0x8c, 0x1d6: 0x8c, 0x1d7: 0x8c,
0x1d8: 0x8c, 0x1d9: 0x8c, 0x1da: 0x8c, 0x1db: 0x8c, 0x1dc: 0x8c, 0x1dd: 0x8c, 0x1de: 0x8c, 0x1df: 0x8c,
0x1e0: 0x8c, 0x1e1: 0x8c, 0x1e2: 0x8c, 0x1e3: 0x8c, 0x1e4: 0x8c, 0x1e5: 0x8c, 0x1e6: 0x8c, 0x1e7: 0x8c,
0x1e8: 0x8c, 0x1e9: 0x8c, 0x1ea: 0x8c, 0x1eb: 0x8c, 0x1ec: 0x8c, 0x1ed: 0x8c, 0x1ee: 0x8c, 0x1ef: 0x8c,
0x1f0: 0x8c, 0x1f1: 0x8c, 0x1f2: 0x8c, 0x1f3: 0x8c, 0x1f4: 0x8c, 0x1f5: 0x8c, 0x1f6: 0x8c, 0x1f7: 0x8c,
0x1f8: 0x8c, 0x1f9: 0x8c, 0x1fa: 0x8c, 0x1fb: 0x8c, 0x1fc: 0x8c, 0x1fd: 0x8c, 0x1fe: 0x8c, 0x1ff: 0x8c,
// Block 0x8, offset 0x200
0x200: 0x8c, 0x201: 0x8c, 0x202: 0x8c, 0x203: 0x8c, 0x204: 0x8c, 0x205: 0x8c, 0x206: 0x8c, 0x207: 0x8c,
0x208: 0x8c, 0x209: 0x8c, 0x20a: 0x8c, 0x20b: 0x8c, 0x20c: 0x8c, 0x20d: 0x8c, 0x20e: 0x8c, 0x20f: 0x8c,
0x210: 0x8c, 0x211: 0x8c, 0x212: 0x8c, 0x213: 0x8c, 0x214: 0x8c, 0x215: 0x8c, 0x216: 0x8c, 0x217: 0x8c,
0x218: 0x8c, 0x219: 0x8c, 0x21a: 0x8c, 0x21b: 0x8c, 0x21c: 0x8c, 0x21d: 0x8c, 0x21e: 0x8c, 0x21f: 0x8c,
0x220: 0x8c, 0x221: 0x8c, 0x222: 0x8c, 0x223: 0x8c, 0x224: 0x8c, 0x225: 0x8c, 0x226: 0x8c, 0x227: 0x8c,
0x228: 0x8c, 0x229: 0x8c, 0x22a: 0x8c, 0x22b: 0x8c, 0x22c: 0x8c, 0x22d: 0x8c, 0x22e: 0x8c, 0x22f: 0x8c,
0x230: 0x8c, 0x231: 0x8c, 0x232: 0x8c, 0x233: 0x8c, 0x234: 0x8c, 0x235: 0x8c, 0x236: 0x8c, 0x237: 0x71,
0x238: 0x8c, 0x239: 0x8c, 0x23a: 0x8c, 0x23b: 0x8c, 0x23c: 0x8c, 0x23d: 0x8c, 0x23e: 0x8c, 0x23f: 0x8c,
// Block 0x9, offset 0x240
0x240: 0x8c, 0x241: 0x8c, 0x242: 0x8c, 0x243: 0x8c, 0x244: 0x8c, 0x245: 0x8c, 0x246: 0x8c, 0x247: 0x8c,
0x248: 0x8c, 0x249: 0x8c, 0x24a: 0x8c, 0x24b: 0x8c, 0x24c: 0x8c, 0x24d: 0x8c, 0x24e: 0x8c, 0x24f: 0x8c,
0x250: 0x8c, 0x251: 0x8c, 0x252: 0x8c, 0x253: 0x8c, 0x254: 0x8c, 0x255: 0x8c, 0x256: 0x8c, 0x257: 0x8c,
0x258: 0x8c, 0x259: 0x8c, 0x25a: 0x8c, 0x25b: 0x8c, 0x25c: 0x8c, 0x25d: 0x8c, 0x25e: 0x8c, 0x25f: 0x8c,
0x260: 0x8c, 0x261: 0x8c, 0x262: 0x8c, 0x263: 0x8c, 0x264: 0x8c, 0x265: 0x8c, 0x266: 0x8c, 0x267: 0x8c,
0x268: 0x8c, 0x269: 0x8c, 0x26a: 0x8c, 0x26b: 0x8c, 0x26c: 0x8c, 0x26d: 0x8c, 0x26e: 0x8c, 0x26f: 0x8c,
0x270: 0x8c, 0x271: 0x8c, 0x272: 0x8c, 0x273: 0x8c, 0x274: 0x8c, 0x275: 0x8c, 0x276: 0x8c, 0x277: 0x8c,
0x278: 0x8c, 0x279: 0x8c, 0x27a: 0x8c, 0x27b: 0x8c, 0x27c: 0x8c, 0x27d: 0x8c, 0x27e: 0x8c, 0x27f: 0x8c,
// 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: 0x8d, 0x293: 0x8e, 0x294: 0x05, 0x295: 0x05, 0x296: 0x05, 0x297: 0x05,
0x298: 0x8f, 0x299: 0x90, 0x29a: 0x91, 0x29b: 0x92, 0x29c: 0x93, 0x29d: 0x94, 0x29e: 0x95, 0x29f: 0x96,
0x2a0: 0x97, 0x2a1: 0x98, 0x2a2: 0x05, 0x2a3: 0x99, 0x2a4: 0x9a, 0x2a5: 0x9b, 0x2a6: 0x9c, 0x2a7: 0x9d,
0x2a8: 0x9e, 0x2a9: 0x9f, 0x2aa: 0xa0, 0x2ab: 0xa1, 0x2ac: 0xa2, 0x2ad: 0xa3, 0x2ae: 0x05, 0x2af: 0xa4,
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: 0xa5, 0x31f: 0xa6,
// 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: 0x7f, 0x3a5: 0x7f, 0x3a6: 0x7f, 0x3a7: 0x7f,
0x3a8: 0xa7, 0x3a9: 0xa8, 0x3aa: 0x7f, 0x3ab: 0xa9, 0x3ac: 0xaa, 0x3ad: 0xab, 0x3ae: 0x71, 0x3af: 0x71,
0x3b0: 0x71, 0x3b1: 0x71, 0x3b2: 0x71, 0x3b3: 0x71, 0x3b4: 0x71, 0x3b5: 0x71, 0x3b6: 0x71, 0x3b7: 0xac,
0x3b8: 0xad, 0x3b9: 0xae, 0x3ba: 0x71, 0x3bb: 0xaf, 0x3bc: 0xb0, 0x3bd: 0xb1, 0x3be: 0xb2, 0x3bf: 0xb3,
// Block 0xf, offset 0x3c0
0x3c0: 0xb4, 0x3c1: 0xb5, 0x3c2: 0x05, 0x3c3: 0xb6, 0x3c4: 0xb7, 0x3c5: 0xb8, 0x3c6: 0xb9, 0x3c7: 0xba,
0x3ca: 0xbb, 0x3cb: 0xbc, 0x3cc: 0xbd, 0x3cd: 0xbe, 0x3ce: 0xbf, 0x3cf: 0xc0,
0x3d0: 0x05, 0x3d1: 0x05, 0x3d2: 0xc1, 0x3d3: 0xc2, 0x3d4: 0xc3, 0x3d5: 0xc4, 0x3d6: 0xc5, 0x3d7: 0xc6,
0x3d8: 0x05, 0x3d9: 0x05, 0x3da: 0x05, 0x3db: 0x05, 0x3dc: 0xc7, 0x3dd: 0xc8, 0x3de: 0xc9,
0x3e0: 0xca, 0x3e1: 0xcb, 0x3e2: 0xcc, 0x3e3: 0xcd, 0x3e4: 0xce, 0x3e5: 0xcf, 0x3e6: 0xd0, 0x3e7: 0xd1,
0x3e8: 0xd2, 0x3e9: 0xd3, 0x3ea: 0xd4, 0x3eb: 0xd5, 0x3ec: 0xd6, 0x3ed: 0xd7, 0x3ee: 0xd8,
0x3f0: 0x05, 0x3f1: 0xd9, 0x3f2: 0xda, 0x3f3: 0xdb, 0x3f4: 0xdc, 0x3f5: 0xdd, 0x3f6: 0xde,
0x3f9: 0xdf, 0x3fa: 0xe0, 0x3fb: 0xe1, 0x3fc: 0xe2, 0x3fd: 0xe3, 0x3fe: 0xe4, 0x3ff: 0xe5,
// Block 0x10, offset 0x400
0x400: 0xe6, 0x401: 0xe7, 0x402: 0xe8, 0x403: 0xe9, 0x404: 0xea, 0x405: 0xeb, 0x406: 0xec, 0x407: 0xed,
0x408: 0xee, 0x409: 0xef, 0x40a: 0xf0, 0x40b: 0xf1, 0x40c: 0xf2, 0x40d: 0xf3, 0x40e: 0xf4, 0x40f: 0xf5,
0x410: 0xf6, 0x411: 0xf7, 0x412: 0xf8, 0x413: 0xf9, 0x416: 0xfa, 0x417: 0xfb,
0x418: 0xfc, 0x419: 0xfd, 0x41a: 0xfe, 0x41b: 0xff, 0x41c: 0x100, 0x41d: 0x101,
0x420: 0x102, 0x422: 0x103, 0x423: 0x104, 0x424: 0x105, 0x425: 0x106, 0x426: 0x107, 0x427: 0x108,
0x428: 0x109, 0x429: 0x10a, 0x42a: 0x10b, 0x42b: 0x10c, 0x42c: 0x10d, 0x42d: 0x10e, 0x42f: 0x10f,
0x430: 0x110, 0x431: 0x111, 0x432: 0x112, 0x434: 0x113, 0x435: 0x114, 0x436: 0x115, 0x437: 0x116,
0x43b: 0x117, 0x43c: 0x118, 0x43d: 0x119, 0x43e: 0x11a, 0x43f: 0x11b,
// 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: 0xcf,
0x450: 0x71, 0x451: 0x11c, 0x452: 0x05, 0x453: 0x05, 0x454: 0x05, 0x455: 0x11d,
0x47e: 0x11e, 0x47f: 0x11f,
// 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: 0x120, 0x491: 0x121, 0x492: 0x05, 0x493: 0x05, 0x494: 0x05, 0x495: 0x05, 0x496: 0x05, 0x497: 0x05,
0x498: 0x05, 0x499: 0x05, 0x49a: 0x05, 0x49b: 0x05, 0x49c: 0x05, 0x49d: 0x05, 0x49e: 0x05, 0x49f: 0x05,
0x4a0: 0x05, 0x4a1: 0x05, 0x4a2: 0x05, 0x4a3: 0x05, 0x4a4: 0x05, 0x4a5: 0x05, 0x4a6: 0x05, 0x4a7: 0x05,
0x4a8: 0x05, 0x4a9: 0x05, 0x4aa: 0x05, 0x4ab: 0x05, 0x4ac: 0x05, 0x4ad: 0x05, 0x4ae: 0x05, 0x4af: 0x05,
0x4b0: 0x05, 0x4b1: 0x05, 0x4b2: 0x05, 0x4b3: 0x05, 0x4b4: 0x05, 0x4b5: 0x05, 0x4b6: 0x05, 0x4b7: 0x05,
0x4b8: 0x05, 0x4b9: 0x05, 0x4ba: 0x05, 0x4bb: 0x05, 0x4bc: 0x05, 0x4bd: 0x05, 0x4be: 0x05, 0x4bf: 0x05,
// Block 0x13, offset 0x4c0
0x4c0: 0x05, 0x4c1: 0x05, 0x4c2: 0x05, 0x4c3: 0x05, 0x4c4: 0x05, 0x4c5: 0x05, 0x4c6: 0x05, 0x4c7: 0x05,
0x4c8: 0x05, 0x4c9: 0x05, 0x4ca: 0x05, 0x4cb: 0x05, 0x4cc: 0x05, 0x4cd: 0x05, 0x4ce: 0x05, 0x4cf: 0xb6,
0x4d0: 0x05, 0x4d1: 0x05, 0x4d2: 0x05, 0x4d3: 0x05, 0x4d4: 0x05, 0x4d5: 0x05, 0x4d6: 0x05, 0x4d7: 0x05,
0x4d8: 0x05, 0x4d9: 0x101,
// Block 0x14, offset 0x500
0x504: 0x122,
0x520: 0x05, 0x521: 0x05, 0x522: 0x05, 0x523: 0x05, 0x524: 0x05, 0x525: 0x05, 0x526: 0x05, 0x527: 0x05,
0x528: 0x10c, 0x529: 0x123, 0x52a: 0x124, 0x52b: 0x125, 0x52c: 0x126, 0x52d: 0x127, 0x52e: 0x128,
0x535: 0x129,
0x539: 0x05, 0x53a: 0x12a, 0x53b: 0x12b, 0x53c: 0x05, 0x53d: 0x12c, 0x53e: 0x12d, 0x53f: 0x12e,
// 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: 0x05,
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: 0x12f, 0x574: 0x130, 0x576: 0x05, 0x577: 0xda,
// Block 0x16, offset 0x580
0x5bf: 0x131,
// Block 0x17, offset 0x5c0
0x5c0: 0x8c, 0x5c1: 0x8c, 0x5c2: 0x8c, 0x5c3: 0x8c, 0x5c4: 0x132, 0x5c5: 0x133, 0x5c6: 0x05, 0x5c7: 0x05,
0x5c8: 0x05, 0x5c9: 0x05, 0x5ca: 0x05, 0x5cb: 0x134,
0x5f0: 0x05, 0x5f1: 0x135, 0x5f2: 0x136,
// Block 0x18, offset 0x600
0x630: 0x71, 0x631: 0x71, 0x632: 0x71, 0x633: 0x137, 0x634: 0x71, 0x635: 0x71, 0x636: 0x71, 0x637: 0x71,
0x638: 0x71, 0x639: 0x71, 0x63a: 0x138, 0x63b: 0x139, 0x63c: 0x13a, 0x63d: 0x13b, 0x63e: 0x71, 0x63f: 0x13c,
// Block 0x19, offset 0x640
0x640: 0x71, 0x641: 0x71, 0x642: 0x71, 0x643: 0x13d, 0x644: 0x13e, 0x645: 0x13f, 0x646: 0x140, 0x647: 0x141,
0x648: 0xb8, 0x649: 0x142, 0x64b: 0x143, 0x64c: 0x71, 0x64d: 0x144,
0x650: 0x71, 0x651: 0x145, 0x652: 0x146, 0x653: 0x147, 0x654: 0x148, 0x655: 0x149, 0x656: 0x71, 0x657: 0x71,
0x658: 0x71, 0x659: 0x71, 0x65a: 0x14a, 0x65b: 0x71, 0x65c: 0x71, 0x65d: 0x71, 0x65e: 0x71, 0x65f: 0x14b,
0x660: 0x71, 0x661: 0x71, 0x662: 0x71, 0x663: 0x71, 0x664: 0x71, 0x665: 0x71, 0x666: 0x71, 0x667: 0x71,
0x668: 0x14c, 0x669: 0x14d, 0x66a: 0x14e,
0x67c: 0x14f,
// Block 0x1a, offset 0x680
0x680: 0x150, 0x681: 0x151, 0x682: 0x152, 0x684: 0x153, 0x685: 0x154,
0x68a: 0x155, 0x68b: 0x156,
0x693: 0x157, 0x697: 0x158,
0x69b: 0x159, 0x69f: 0x15a,
0x6a0: 0x05, 0x6a1: 0x05, 0x6a2: 0x05, 0x6a3: 0x15b, 0x6a4: 0x15c, 0x6a5: 0x15d,
0x6b1: 0x15e, 0x6b2: 0x15f, 0x6b4: 0x160,
0x6b8: 0x161, 0x6b9: 0x162, 0x6ba: 0x163, 0x6bb: 0x164,
// Block 0x1b, offset 0x6c0
0x6c0: 0x165, 0x6c1: 0x71, 0x6c2: 0x166, 0x6c3: 0x167, 0x6c4: 0x71, 0x6c5: 0x71, 0x6c6: 0x151, 0x6c7: 0x168,
0x6c8: 0x169, 0x6c9: 0x16a, 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: 0x16b, 0x6dc: 0x71, 0x6dd: 0x71, 0x6de: 0x71, 0x6df: 0x16c,
0x6e0: 0x16d, 0x6e1: 0x16e, 0x6e2: 0x16f, 0x6e3: 0x170, 0x6e4: 0x71, 0x6e5: 0x71, 0x6e6: 0x71, 0x6e7: 0x71,
0x6e8: 0x71, 0x6e9: 0x171, 0x6ea: 0x172, 0x6eb: 0x173, 0x6ec: 0x71, 0x6ed: 0x71, 0x6ee: 0x174, 0x6ef: 0x175,
// Block 0x1c, offset 0x700
0x700: 0x8c, 0x701: 0x8c, 0x702: 0x8c, 0x703: 0x8c, 0x704: 0x8c, 0x705: 0x8c, 0x706: 0x8c, 0x707: 0x8c,
0x708: 0x8c, 0x709: 0x8c, 0x70a: 0x8c, 0x70b: 0x8c, 0x70c: 0x8c, 0x70d: 0x8c, 0x70e: 0x8c, 0x70f: 0x8c,
0x710: 0x8c, 0x711: 0x8c, 0x712: 0x8c, 0x713: 0x8c, 0x714: 0x8c, 0x715: 0x8c, 0x716: 0x8c, 0x717: 0x8c,
0x718: 0x8c, 0x719: 0x8c, 0x71a: 0x8c, 0x71b: 0x176, 0x71c: 0x8c, 0x71d: 0x8c, 0x71e: 0x8c, 0x71f: 0x8c,
0x720: 0x8c, 0x721: 0x8c, 0x722: 0x8c, 0x723: 0x8c, 0x724: 0x8c, 0x725: 0x8c, 0x726: 0x8c, 0x727: 0x8c,
0x728: 0x8c, 0x729: 0x8c, 0x72a: 0x8c, 0x72b: 0x8c, 0x72c: 0x8c, 0x72d: 0x8c, 0x72e: 0x8c, 0x72f: 0x8c,
0x730: 0x8c, 0x731: 0x8c, 0x732: 0x8c, 0x733: 0x8c, 0x734: 0x8c, 0x735: 0x8c, 0x736: 0x8c, 0x737: 0x8c,
0x738: 0x8c, 0x739: 0x8c, 0x73a: 0x8c, 0x73b: 0x8c, 0x73c: 0x8c, 0x73d: 0x8c, 0x73e: 0x8c, 0x73f: 0x8c,
// Block 0x1d, offset 0x740
0x740: 0x8c, 0x741: 0x8c, 0x742: 0x8c, 0x743: 0x8c, 0x744: 0x8c, 0x745: 0x8c, 0x746: 0x8c, 0x747: 0x8c,
0x748: 0x8c, 0x749: 0x8c, 0x74a: 0x8c, 0x74b: 0x8c, 0x74c: 0x8c, 0x74d: 0x8c, 0x74e: 0x8c, 0x74f: 0x8c,
0x750: 0x8c, 0x751: 0x8c, 0x752: 0x8c, 0x753: 0x8c, 0x754: 0x8c, 0x755: 0x8c, 0x756: 0x8c, 0x757: 0x8c,
0x758: 0x8c, 0x759: 0x8c, 0x75a: 0x8c, 0x75b: 0x8c, 0x75c: 0x8c, 0x75d: 0x8c, 0x75e: 0x8c, 0x75f: 0x8c,
0x760: 0x177, 0x761: 0x8c, 0x762: 0x8c, 0x763: 0x8c, 0x764: 0x8c, 0x765: 0x8c, 0x766: 0x8c, 0x767: 0x8c,
0x768: 0x8c, 0x769: 0x8c, 0x76a: 0x8c, 0x76b: 0x8c, 0x76c: 0x8c, 0x76d: 0x8c, 0x76e: 0x8c, 0x76f: 0x8c,
0x770: 0x8c, 0x771: 0x8c, 0x772: 0x8c, 0x773: 0x8c, 0x774: 0x8c, 0x775: 0x8c, 0x776: 0x8c, 0x777: 0x8c,
0x778: 0x8c, 0x779: 0x8c, 0x77a: 0x8c, 0x77b: 0x8c, 0x77c: 0x8c, 0x77d: 0x8c, 0x77e: 0x8c, 0x77f: 0x8c,
// Block 0x1e, offset 0x780
0x780: 0x8c, 0x781: 0x8c, 0x782: 0x8c, 0x783: 0x8c, 0x784: 0x8c, 0x785: 0x8c, 0x786: 0x8c, 0x787: 0x8c,
0x788: 0x8c, 0x789: 0x8c, 0x78a: 0x8c, 0x78b: 0x8c, 0x78c: 0x8c, 0x78d: 0x8c, 0x78e: 0x8c, 0x78f: 0x8c,
0x790: 0x8c, 0x791: 0x8c, 0x792: 0x8c, 0x793: 0x8c, 0x794: 0x8c, 0x795: 0x8c, 0x796: 0x8c, 0x797: 0x8c,
0x798: 0x8c, 0x799: 0x8c, 0x79a: 0x8c, 0x79b: 0x8c, 0x79c: 0x8c, 0x79d: 0x8c, 0x79e: 0x8c, 0x79f: 0x8c,
0x7a0: 0x8c, 0x7a1: 0x8c, 0x7a2: 0x8c, 0x7a3: 0x8c, 0x7a4: 0x8c, 0x7a5: 0x8c, 0x7a6: 0x8c, 0x7a7: 0x8c,
0x7a8: 0x8c, 0x7a9: 0x8c, 0x7aa: 0x8c, 0x7ab: 0x8c, 0x7ac: 0x8c, 0x7ad: 0x8c, 0x7ae: 0x8c, 0x7af: 0x8c,
0x7b0: 0x8c, 0x7b1: 0x8c, 0x7b2: 0x8c, 0x7b3: 0x8c, 0x7b4: 0x8c, 0x7b5: 0x8c, 0x7b6: 0x8c, 0x7b7: 0x8c,
0x7b8: 0x8c, 0x7b9: 0x8c, 0x7ba: 0x178, 0x7bb: 0x8c, 0x7bc: 0x8c, 0x7bd: 0x8c, 0x7be: 0x8c, 0x7bf: 0x8c,
// Block 0x1f, offset 0x7c0
0x7c0: 0x8c, 0x7c1: 0x8c, 0x7c2: 0x8c, 0x7c3: 0x8c, 0x7c4: 0x8c, 0x7c5: 0x8c, 0x7c6: 0x8c, 0x7c7: 0x8c,
0x7c8: 0x8c, 0x7c9: 0x8c, 0x7ca: 0x8c, 0x7cb: 0x8c, 0x7cc: 0x8c, 0x7cd: 0x8c, 0x7ce: 0x8c, 0x7cf: 0x8c,
0x7d0: 0x8c, 0x7d1: 0x8c, 0x7d2: 0x8c, 0x7d3: 0x8c, 0x7d4: 0x8c, 0x7d5: 0x8c, 0x7d6: 0x8c, 0x7d7: 0x8c,
0x7d8: 0x8c, 0x7d9: 0x8c, 0x7da: 0x8c, 0x7db: 0x8c, 0x7dc: 0x8c, 0x7dd: 0x8c, 0x7de: 0x8c, 0x7df: 0x8c,
0x7e0: 0x8c, 0x7e1: 0x8c, 0x7e2: 0x8c, 0x7e3: 0x8c, 0x7e4: 0x8c, 0x7e5: 0x8c, 0x7e6: 0x8c, 0x7e7: 0x8c,
0x7e8: 0x8c, 0x7e9: 0x8c, 0x7ea: 0x8c, 0x7eb: 0x8c, 0x7ec: 0x8c, 0x7ed: 0x8c, 0x7ee: 0x8c, 0x7ef: 0x179,
0x7f0: 0x8c, 0x7f1: 0x8c, 0x7f2: 0x8c, 0x7f3: 0x8c, 0x7f4: 0x8c, 0x7f5: 0x8c, 0x7f6: 0x8c, 0x7f7: 0x8c,
0x7f8: 0x8c, 0x7f9: 0x17a,
// Block 0x20, offset 0x800
0x820: 0x7f, 0x821: 0x7f, 0x822: 0x7f, 0x823: 0x7f, 0x824: 0x7f, 0x825: 0x7f, 0x826: 0x7f, 0x827: 0x7f,
0x828: 0x17b,
// Block 0x21, offset 0x840
0x840: 0x8c, 0x841: 0x8c, 0x842: 0x8c, 0x843: 0x8c, 0x844: 0x8c, 0x845: 0x8c, 0x846: 0x8c, 0x847: 0x8c,
0x848: 0x8c, 0x849: 0x8c, 0x84a: 0x8c, 0x84b: 0x8c, 0x84c: 0x8c, 0x84d: 0x17c, 0x84e: 0x8c, 0x84f: 0x8c,
0x850: 0x8c, 0x851: 0x8c, 0x852: 0x8c, 0x853: 0x8c, 0x854: 0x8c, 0x855: 0x8c, 0x856: 0x8c, 0x857: 0x8c,
0x858: 0x8c, 0x859: 0x8c, 0x85a: 0x8c, 0x85b: 0x8c, 0x85c: 0x8c, 0x85d: 0x8c, 0x85e: 0x8c, 0x85f: 0x8c,
0x860: 0x8c, 0x861: 0x8c, 0x862: 0x8c, 0x863: 0x8c, 0x864: 0x8c, 0x865: 0x8c, 0x866: 0x8c, 0x867: 0x8c,
0x868: 0x8c, 0x869: 0x8c, 0x86a: 0x8c, 0x86b: 0x8c, 0x86c: 0x8c, 0x86d: 0x8c, 0x86e: 0x8c, 0x86f: 0x8c,
0x870: 0x8c, 0x871: 0x8c, 0x872: 0x8c, 0x873: 0x8c, 0x874: 0x8c, 0x875: 0x8c, 0x876: 0x8c, 0x877: 0x8c,
0x878: 0x8c, 0x879: 0x8c, 0x87a: 0x8c, 0x87b: 0x8c, 0x87c: 0x8c, 0x87d: 0x8c, 0x87e: 0x8c, 0x87f: 0x8c,
// Block 0x22, offset 0x880
0x880: 0x8c, 0x881: 0x8c, 0x882: 0x8c, 0x883: 0x8c, 0x884: 0x8c, 0x885: 0x8c, 0x886: 0x8c, 0x887: 0x8c,
0x888: 0x8c, 0x889: 0x8c, 0x88a: 0x8c, 0x88b: 0x8c, 0x88c: 0x8c, 0x88d: 0x8c, 0x88e: 0x8c, 0x88f: 0x8c,
0x890: 0x8c, 0x891: 0x17d,
// 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: 0x07, 0x8f3: 0x20,
// Block 0x24, offset 0x900
0x900: 0x17e, 0x901: 0x3e, 0x904: 0x3e, 0x905: 0x3e, 0x906: 0x3e, 0x907: 0x17f,
// 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: 0x180,
// 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 29888 bytes (29KiB); 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.27
package bidi
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "17.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: 20608 bytes (20.12 KiB). Checksum: 291cd0103a32a537.
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: 270 blocks, 17280 entries, 17280 bytes
// The third block is the zero block.
var bidiValues = [17280]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: 0x000d, 0x610: 0x0005, 0x611: 0x0005,
0x612: 0x0001, 0x613: 0x0001, 0x614: 0x0001, 0x615: 0x0001, 0x616: 0x0001, 0x617: 0x000c,
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, 0x11cf: 0x000c, 0x11d0: 0x000c, 0x11d1: 0x000c,
0x11d2: 0x000c, 0x11d3: 0x000c, 0x11d4: 0x000c, 0x11d5: 0x000c, 0x11d6: 0x000c, 0x11d7: 0x000c,
0x11d8: 0x000c, 0x11d9: 0x000c, 0x11da: 0x000c, 0x11db: 0x000c, 0x11dc: 0x000c, 0x11dd: 0x000c,
0x11e0: 0x000c, 0x11e1: 0x000c, 0x11e2: 0x000c, 0x11e3: 0x000c,
0x11e4: 0x000c, 0x11e5: 0x000c, 0x11e6: 0x000c, 0x11e7: 0x000c, 0x11e8: 0x000c, 0x11e9: 0x000c,
0x11ea: 0x000c, 0x11eb: 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, 0x1727: 0x000a, 0x1728: 0x000a, 0x1729: 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
0x19a5: 0x000a, 0x19a6: 0x000a, 0x19a7: 0x000a, 0x19a8: 0x000a, 0x19a9: 0x000a,
0x19aa: 0x000a, 0x19af: 0x000c,
0x19b0: 0x000c, 0x19b1: 0x000c,
0x19b9: 0x000a, 0x19ba: 0x000a, 0x19bb: 0x000a,
0x19bc: 0x000a, 0x19bd: 0x000a, 0x19be: 0x000a, 0x19bf: 0x000a,
// Block 0x67, offset 0x19c0
0x19ff: 0x000c,
// Block 0x68, offset 0x1a00
0x1a20: 0x000c, 0x1a21: 0x000c, 0x1a22: 0x000c, 0x1a23: 0x000c,
0x1a24: 0x000c, 0x1a25: 0x000c, 0x1a26: 0x000c, 0x1a27: 0x000c, 0x1a28: 0x000c, 0x1a29: 0x000c,
0x1a2a: 0x000c, 0x1a2b: 0x000c, 0x1a2c: 0x000c, 0x1a2d: 0x000c, 0x1a2e: 0x000c, 0x1a2f: 0x000c,
0x1a30: 0x000c, 0x1a31: 0x000c, 0x1a32: 0x000c, 0x1a33: 0x000c, 0x1a34: 0x000c, 0x1a35: 0x000c,
0x1a36: 0x000c, 0x1a37: 0x000c, 0x1a38: 0x000c, 0x1a39: 0x000c, 0x1a3a: 0x000c, 0x1a3b: 0x000c,
0x1a3c: 0x000c, 0x1a3d: 0x000c, 0x1a3e: 0x000c, 0x1a3f: 0x000c,
// Block 0x69, offset 0x1a40
0x1a40: 0x000a, 0x1a41: 0x000a, 0x1a42: 0x000a, 0x1a43: 0x000a, 0x1a44: 0x000a, 0x1a45: 0x000a,
0x1a46: 0x000a, 0x1a47: 0x000a, 0x1a48: 0x000a, 0x1a49: 0x000a, 0x1a4a: 0x000a, 0x1a4b: 0x000a,
0x1a4c: 0x000a, 0x1a4d: 0x000a, 0x1a4e: 0x000a, 0x1a4f: 0x000a, 0x1a50: 0x000a, 0x1a51: 0x000a,
0x1a52: 0x000a, 0x1a53: 0x000a, 0x1a54: 0x000a, 0x1a55: 0x000a, 0x1a56: 0x000a, 0x1a57: 0x000a,
0x1a58: 0x000a, 0x1a59: 0x000a, 0x1a5a: 0x000a, 0x1a5b: 0x000a, 0x1a5c: 0x000a, 0x1a5d: 0x000a,
0x1a5e: 0x000a, 0x1a5f: 0x000a, 0x1a60: 0x000a, 0x1a61: 0x000a, 0x1a62: 0x003a, 0x1a63: 0x002a,
0x1a64: 0x003a, 0x1a65: 0x002a, 0x1a66: 0x003a, 0x1a67: 0x002a, 0x1a68: 0x003a, 0x1a69: 0x002a,
0x1a6a: 0x000a, 0x1a6b: 0x000a, 0x1a6c: 0x000a, 0x1a6d: 0x000a, 0x1a6e: 0x000a, 0x1a6f: 0x000a,
0x1a70: 0x000a, 0x1a71: 0x000a, 0x1a72: 0x000a, 0x1a73: 0x000a, 0x1a74: 0x000a, 0x1a75: 0x000a,
0x1a76: 0x000a, 0x1a77: 0x000a, 0x1a78: 0x000a, 0x1a79: 0x000a, 0x1a7a: 0x000a, 0x1a7b: 0x000a,
0x1a7c: 0x000a, 0x1a7d: 0x000a, 0x1a7e: 0x000a, 0x1a7f: 0x000a,
// 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: 0x009a, 0x1a96: 0x008a, 0x1a97: 0x00ba,
0x1a98: 0x00aa, 0x1a99: 0x009a, 0x1a9a: 0x008a, 0x1a9b: 0x007a, 0x1a9c: 0x006a, 0x1a9d: 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: 0x000a, 0x1ad6: 0x000a, 0x1ad7: 0x000a,
0x1ad8: 0x000a, 0x1ad9: 0x000a, 0x1adb: 0x000a, 0x1adc: 0x000a, 0x1add: 0x000a,
0x1ade: 0x000a, 0x1adf: 0x000a, 0x1ae0: 0x000a, 0x1ae1: 0x000a, 0x1ae2: 0x000a, 0x1ae3: 0x000a,
0x1ae4: 0x000a, 0x1ae5: 0x000a, 0x1ae6: 0x000a, 0x1ae7: 0x000a, 0x1ae8: 0x000a, 0x1ae9: 0x000a,
0x1aea: 0x000a, 0x1aeb: 0x000a, 0x1aec: 0x000a, 0x1aed: 0x000a, 0x1aee: 0x000a, 0x1aef: 0x000a,
0x1af0: 0x000a, 0x1af1: 0x000a, 0x1af2: 0x000a, 0x1af3: 0x000a, 0x1af4: 0x000a, 0x1af5: 0x000a,
0x1af6: 0x000a, 0x1af7: 0x000a, 0x1af8: 0x000a, 0x1af9: 0x000a, 0x1afa: 0x000a, 0x1afb: 0x000a,
0x1afc: 0x000a, 0x1afd: 0x000a, 0x1afe: 0x000a, 0x1aff: 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, 0x1b1a: 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,
// 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,
0x1b70: 0x000a, 0x1b71: 0x000a, 0x1b72: 0x000a, 0x1b73: 0x000a, 0x1b74: 0x000a, 0x1b75: 0x000a,
0x1b76: 0x000a, 0x1b77: 0x000a, 0x1b78: 0x000a, 0x1b79: 0x000a, 0x1b7a: 0x000a, 0x1b7b: 0x000a,
0x1b7c: 0x000a, 0x1b7d: 0x000a, 0x1b7e: 0x000a, 0x1b7f: 0x000a,
// Block 0x6e, offset 0x1b80
0x1b80: 0x0009, 0x1b81: 0x000a, 0x1b82: 0x000a, 0x1b83: 0x000a, 0x1b84: 0x000a,
0x1b88: 0x003a, 0x1b89: 0x002a, 0x1b8a: 0x003a, 0x1b8b: 0x002a,
0x1b8c: 0x003a, 0x1b8d: 0x002a, 0x1b8e: 0x003a, 0x1b8f: 0x002a, 0x1b90: 0x003a, 0x1b91: 0x002a,
0x1b92: 0x000a, 0x1b93: 0x000a, 0x1b94: 0x003a, 0x1b95: 0x002a, 0x1b96: 0x003a, 0x1b97: 0x002a,
0x1b98: 0x003a, 0x1b99: 0x002a, 0x1b9a: 0x003a, 0x1b9b: 0x002a, 0x1b9c: 0x000a, 0x1b9d: 0x000a,
0x1b9e: 0x000a, 0x1b9f: 0x000a, 0x1ba0: 0x000a,
0x1baa: 0x000c, 0x1bab: 0x000c, 0x1bac: 0x000c, 0x1bad: 0x000c,
0x1bb0: 0x000a,
0x1bb6: 0x000a, 0x1bb7: 0x000a,
0x1bbd: 0x000a, 0x1bbe: 0x000a, 0x1bbf: 0x000a,
// Block 0x6f, offset 0x1bc0
0x1bd9: 0x000c, 0x1bda: 0x000c, 0x1bdb: 0x000a, 0x1bdc: 0x000a,
0x1be0: 0x000a,
// Block 0x70, offset 0x1c00
0x1c3b: 0x000a,
// Block 0x71, offset 0x1c40
0x1c40: 0x000a, 0x1c41: 0x000a, 0x1c42: 0x000a, 0x1c43: 0x000a, 0x1c44: 0x000a, 0x1c45: 0x000a,
0x1c46: 0x000a, 0x1c47: 0x000a, 0x1c48: 0x000a, 0x1c49: 0x000a, 0x1c4a: 0x000a, 0x1c4b: 0x000a,
0x1c4c: 0x000a, 0x1c4d: 0x000a, 0x1c4e: 0x000a, 0x1c4f: 0x000a, 0x1c50: 0x000a, 0x1c51: 0x000a,
0x1c52: 0x000a, 0x1c53: 0x000a, 0x1c54: 0x000a, 0x1c55: 0x000a, 0x1c56: 0x000a, 0x1c57: 0x000a,
0x1c58: 0x000a, 0x1c59: 0x000a, 0x1c5a: 0x000a, 0x1c5b: 0x000a, 0x1c5c: 0x000a, 0x1c5d: 0x000a,
0x1c5e: 0x000a, 0x1c5f: 0x000a, 0x1c60: 0x000a, 0x1c61: 0x000a, 0x1c62: 0x000a, 0x1c63: 0x000a,
0x1c64: 0x000a, 0x1c65: 0x000a,
0x1c6f: 0x000a,
// Block 0x72, offset 0x1c80
0x1c9d: 0x000a,
0x1c9e: 0x000a,
// Block 0x73, offset 0x1cc0
0x1cd0: 0x000a, 0x1cd1: 0x000a,
0x1cd2: 0x000a, 0x1cd3: 0x000a, 0x1cd4: 0x000a, 0x1cd5: 0x000a, 0x1cd6: 0x000a, 0x1cd7: 0x000a,
0x1cd8: 0x000a, 0x1cd9: 0x000a, 0x1cda: 0x000a, 0x1cdb: 0x000a, 0x1cdc: 0x000a, 0x1cdd: 0x000a,
0x1cde: 0x000a, 0x1cdf: 0x000a,
0x1cfc: 0x000a, 0x1cfd: 0x000a, 0x1cfe: 0x000a,
// Block 0x74, offset 0x1d00
0x1d31: 0x000a, 0x1d32: 0x000a, 0x1d33: 0x000a, 0x1d34: 0x000a, 0x1d35: 0x000a,
0x1d36: 0x000a, 0x1d37: 0x000a, 0x1d38: 0x000a, 0x1d39: 0x000a, 0x1d3a: 0x000a, 0x1d3b: 0x000a,
0x1d3c: 0x000a, 0x1d3d: 0x000a, 0x1d3e: 0x000a, 0x1d3f: 0x000a,
// Block 0x75, offset 0x1d40
0x1d4c: 0x000a, 0x1d4d: 0x000a, 0x1d4e: 0x000a, 0x1d4f: 0x000a,
// Block 0x76, offset 0x1d80
0x1db7: 0x000a, 0x1db8: 0x000a, 0x1db9: 0x000a, 0x1dba: 0x000a,
// Block 0x77, offset 0x1dc0
0x1dde: 0x000a, 0x1ddf: 0x000a,
0x1dff: 0x000a,
// Block 0x78, offset 0x1e00
0x1e10: 0x000a, 0x1e11: 0x000a,
0x1e12: 0x000a, 0x1e13: 0x000a, 0x1e14: 0x000a, 0x1e15: 0x000a, 0x1e16: 0x000a, 0x1e17: 0x000a,
0x1e18: 0x000a, 0x1e19: 0x000a, 0x1e1a: 0x000a, 0x1e1b: 0x000a, 0x1e1c: 0x000a, 0x1e1d: 0x000a,
0x1e1e: 0x000a, 0x1e1f: 0x000a, 0x1e20: 0x000a, 0x1e21: 0x000a, 0x1e22: 0x000a, 0x1e23: 0x000a,
0x1e24: 0x000a, 0x1e25: 0x000a, 0x1e26: 0x000a, 0x1e27: 0x000a, 0x1e28: 0x000a, 0x1e29: 0x000a,
0x1e2a: 0x000a, 0x1e2b: 0x000a, 0x1e2c: 0x000a, 0x1e2d: 0x000a, 0x1e2e: 0x000a, 0x1e2f: 0x000a,
0x1e30: 0x000a, 0x1e31: 0x000a, 0x1e32: 0x000a, 0x1e33: 0x000a, 0x1e34: 0x000a, 0x1e35: 0x000a,
0x1e36: 0x000a, 0x1e37: 0x000a, 0x1e38: 0x000a, 0x1e39: 0x000a, 0x1e3a: 0x000a, 0x1e3b: 0x000a,
0x1e3c: 0x000a, 0x1e3d: 0x000a, 0x1e3e: 0x000a, 0x1e3f: 0x000a,
// Block 0x79, offset 0x1e40
0x1e40: 0x000a, 0x1e41: 0x000a, 0x1e42: 0x000a, 0x1e43: 0x000a, 0x1e44: 0x000a, 0x1e45: 0x000a,
0x1e46: 0x000a,
// Block 0x7a, offset 0x1e80
0x1e8d: 0x000a, 0x1e8e: 0x000a, 0x1e8f: 0x000a,
// Block 0x7b, offset 0x1ec0
0x1eef: 0x000c,
0x1ef0: 0x000c, 0x1ef1: 0x000c, 0x1ef2: 0x000c, 0x1ef3: 0x000a, 0x1ef4: 0x000c, 0x1ef5: 0x000c,
0x1ef6: 0x000c, 0x1ef7: 0x000c, 0x1ef8: 0x000c, 0x1ef9: 0x000c, 0x1efa: 0x000c, 0x1efb: 0x000c,
0x1efc: 0x000c, 0x1efd: 0x000c, 0x1efe: 0x000a, 0x1eff: 0x000a,
// Block 0x7c, offset 0x1f00
0x1f1e: 0x000c, 0x1f1f: 0x000c,
// Block 0x7d, offset 0x1f40
0x1f70: 0x000c, 0x1f71: 0x000c,
// Block 0x7e, offset 0x1f80
0x1f80: 0x000a, 0x1f81: 0x000a, 0x1f82: 0x000a, 0x1f83: 0x000a, 0x1f84: 0x000a, 0x1f85: 0x000a,
0x1f86: 0x000a, 0x1f87: 0x000a, 0x1f88: 0x000a, 0x1f89: 0x000a, 0x1f8a: 0x000a, 0x1f8b: 0x000a,
0x1f8c: 0x000a, 0x1f8d: 0x000a, 0x1f8e: 0x000a, 0x1f8f: 0x000a, 0x1f90: 0x000a, 0x1f91: 0x000a,
0x1f92: 0x000a, 0x1f93: 0x000a, 0x1f94: 0x000a, 0x1f95: 0x000a, 0x1f96: 0x000a, 0x1f97: 0x000a,
0x1f98: 0x000a, 0x1f99: 0x000a, 0x1f9a: 0x000a, 0x1f9b: 0x000a, 0x1f9c: 0x000a, 0x1f9d: 0x000a,
0x1f9e: 0x000a, 0x1f9f: 0x000a, 0x1fa0: 0x000a, 0x1fa1: 0x000a,
// Block 0x7f, offset 0x1fc0
0x1fc8: 0x000a,
// Block 0x80, offset 0x2000
0x2002: 0x000c,
0x2006: 0x000c, 0x200b: 0x000c,
0x2025: 0x000c, 0x2026: 0x000c, 0x2028: 0x000a, 0x2029: 0x000a,
0x202a: 0x000a, 0x202b: 0x000a, 0x202c: 0x000c,
0x2038: 0x0004, 0x2039: 0x0004,
// Block 0x81, offset 0x2040
0x2074: 0x000a, 0x2075: 0x000a,
0x2076: 0x000a, 0x2077: 0x000a,
// Block 0x82, offset 0x2080
0x2084: 0x000c, 0x2085: 0x000c,
0x20a0: 0x000c, 0x20a1: 0x000c, 0x20a2: 0x000c, 0x20a3: 0x000c,
0x20a4: 0x000c, 0x20a5: 0x000c, 0x20a6: 0x000c, 0x20a7: 0x000c, 0x20a8: 0x000c, 0x20a9: 0x000c,
0x20aa: 0x000c, 0x20ab: 0x000c, 0x20ac: 0x000c, 0x20ad: 0x000c, 0x20ae: 0x000c, 0x20af: 0x000c,
0x20b0: 0x000c, 0x20b1: 0x000c,
0x20bf: 0x000c,
// Block 0x83, offset 0x20c0
0x20e6: 0x000c, 0x20e7: 0x000c, 0x20e8: 0x000c, 0x20e9: 0x000c,
0x20ea: 0x000c, 0x20eb: 0x000c, 0x20ec: 0x000c, 0x20ed: 0x000c,
// Block 0x84, offset 0x2100
0x2107: 0x000c, 0x2108: 0x000c, 0x2109: 0x000c, 0x210a: 0x000c, 0x210b: 0x000c,
0x210c: 0x000c, 0x210d: 0x000c, 0x210e: 0x000c, 0x210f: 0x000c, 0x2110: 0x000c, 0x2111: 0x000c,
// Block 0x85, offset 0x2140
0x2140: 0x000c, 0x2141: 0x000c, 0x2142: 0x000c,
0x2173: 0x000c,
0x2176: 0x000c, 0x2177: 0x000c, 0x2178: 0x000c, 0x2179: 0x000c,
0x217c: 0x000c, 0x217d: 0x000c,
// Block 0x86, offset 0x2180
0x21a5: 0x000c,
// Block 0x87, offset 0x21c0
0x21e9: 0x000c,
0x21ea: 0x000c, 0x21eb: 0x000c, 0x21ec: 0x000c, 0x21ed: 0x000c, 0x21ee: 0x000c,
0x21f1: 0x000c, 0x21f2: 0x000c, 0x21f5: 0x000c,
0x21f6: 0x000c,
// Block 0x88, offset 0x2200
0x2203: 0x000c,
0x220c: 0x000c,
0x223c: 0x000c,
// Block 0x89, offset 0x2240
0x2270: 0x000c, 0x2272: 0x000c, 0x2273: 0x000c, 0x2274: 0x000c,
0x2277: 0x000c, 0x2278: 0x000c,
0x227e: 0x000c, 0x227f: 0x000c,
// Block 0x8a, offset 0x2280
0x2281: 0x000c,
0x22ac: 0x000c, 0x22ad: 0x000c,
0x22b6: 0x000c,
// Block 0x8b, offset 0x22c0
0x22ea: 0x000a, 0x22eb: 0x000a,
// Block 0x8c, offset 0x2300
0x2325: 0x000c, 0x2328: 0x000c,
0x232d: 0x000c,
// Block 0x8d, offset 0x2340
0x235d: 0x0001,
0x235e: 0x000c, 0x235f: 0x0001, 0x2360: 0x0001, 0x2361: 0x0001, 0x2362: 0x0001, 0x2363: 0x0001,
0x2364: 0x0001, 0x2365: 0x0001, 0x2366: 0x0001, 0x2367: 0x0001, 0x2368: 0x0001, 0x2369: 0x0003,
0x236a: 0x0001, 0x236b: 0x0001, 0x236c: 0x0001, 0x236d: 0x0001, 0x236e: 0x0001, 0x236f: 0x0001,
0x2370: 0x0001, 0x2371: 0x0001, 0x2372: 0x0001, 0x2373: 0x0001, 0x2374: 0x0001, 0x2375: 0x0001,
0x2376: 0x0001, 0x2377: 0x0001, 0x2378: 0x0001, 0x2379: 0x0001, 0x237a: 0x0001, 0x237b: 0x0001,
0x237c: 0x0001, 0x237d: 0x0001, 0x237e: 0x0001, 0x237f: 0x0001,
// Block 0x8e, offset 0x2380
0x2380: 0x0001, 0x2381: 0x0001, 0x2382: 0x0001, 0x2383: 0x0001, 0x2384: 0x0001, 0x2385: 0x0001,
0x2386: 0x0001, 0x2387: 0x0001, 0x2388: 0x0001, 0x2389: 0x0001, 0x238a: 0x0001, 0x238b: 0x0001,
0x238c: 0x0001, 0x238d: 0x0001, 0x238e: 0x0001, 0x238f: 0x0001, 0x2390: 0x000d, 0x2391: 0x000d,
0x2392: 0x000d, 0x2393: 0x000d, 0x2394: 0x000d, 0x2395: 0x000d, 0x2396: 0x000d, 0x2397: 0x000d,
0x2398: 0x000d, 0x2399: 0x000d, 0x239a: 0x000d, 0x239b: 0x000d, 0x239c: 0x000d, 0x239d: 0x000d,
0x239e: 0x000d, 0x239f: 0x000d, 0x23a0: 0x000d, 0x23a1: 0x000d, 0x23a2: 0x000d, 0x23a3: 0x000d,
0x23a4: 0x000d, 0x23a5: 0x000d, 0x23a6: 0x000d, 0x23a7: 0x000d, 0x23a8: 0x000d, 0x23a9: 0x000d,
0x23aa: 0x000d, 0x23ab: 0x000d, 0x23ac: 0x000d, 0x23ad: 0x000d, 0x23ae: 0x000d, 0x23af: 0x000d,
0x23b0: 0x000d, 0x23b1: 0x000d, 0x23b2: 0x000d, 0x23b3: 0x000d, 0x23b4: 0x000d, 0x23b5: 0x000d,
0x23b6: 0x000d, 0x23b7: 0x000d, 0x23b8: 0x000d, 0x23b9: 0x000d, 0x23ba: 0x000d, 0x23bb: 0x000d,
0x23bc: 0x000d, 0x23bd: 0x000d, 0x23be: 0x000d, 0x23bf: 0x000d,
// Block 0x8f, offset 0x23c0
0x23c0: 0x000d, 0x23c1: 0x000d, 0x23c2: 0x000d, 0x23c3: 0x000a, 0x23c4: 0x000a, 0x23c5: 0x000a,
0x23c6: 0x000a, 0x23c7: 0x000a, 0x23c8: 0x000a, 0x23c9: 0x000a, 0x23ca: 0x000a, 0x23cb: 0x000a,
0x23cc: 0x000a, 0x23cd: 0x000a, 0x23ce: 0x000a, 0x23cf: 0x000a, 0x23d0: 0x000a, 0x23d1: 0x000a,
0x23d2: 0x000a, 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: 0x000d, 0x2490: 0x000a, 0x2491: 0x000a,
0x2492: 0x000d, 0x2493: 0x000d, 0x2494: 0x000d, 0x2495: 0x000d, 0x2496: 0x000d, 0x2497: 0x000d,
0x2498: 0x000d, 0x2499: 0x000d, 0x249a: 0x000d, 0x249b: 0x000d, 0x249c: 0x000d, 0x249d: 0x000d,
0x249e: 0x000d, 0x249f: 0x000d, 0x24a0: 0x000d, 0x24a1: 0x000d, 0x24a2: 0x000d, 0x24a3: 0x000d,
0x24a4: 0x000d, 0x24a5: 0x000d, 0x24a6: 0x000d, 0x24a7: 0x000d, 0x24a8: 0x000d, 0x24a9: 0x000d,
0x24aa: 0x000d, 0x24ab: 0x000d, 0x24ac: 0x000d, 0x24ad: 0x000d, 0x24ae: 0x000d, 0x24af: 0x000d,
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: 0x000d, 0x24be: 0x000d, 0x24bf: 0x000d,
// Block 0x93, offset 0x24c0
0x24c0: 0x000d, 0x24c1: 0x000d, 0x24c2: 0x000d, 0x24c3: 0x000d, 0x24c4: 0x000d, 0x24c5: 0x000d,
0x24c6: 0x000d, 0x24c7: 0x000d, 0x24c8: 0x000a, 0x24c9: 0x000a, 0x24ca: 0x000a, 0x24cb: 0x000a,
0x24cc: 0x000a, 0x24cd: 0x000a, 0x24ce: 0x000a, 0x24cf: 0x000a, 0x24d0: 0x000b, 0x24d1: 0x000b,
0x24d2: 0x000b, 0x24d3: 0x000b, 0x24d4: 0x000b, 0x24d5: 0x000b, 0x24d6: 0x000b, 0x24d7: 0x000b,
0x24d8: 0x000b, 0x24d9: 0x000b, 0x24da: 0x000b, 0x24db: 0x000b, 0x24dc: 0x000b, 0x24dd: 0x000b,
0x24de: 0x000b, 0x24df: 0x000b, 0x24e0: 0x000b, 0x24e1: 0x000b, 0x24e2: 0x000b, 0x24e3: 0x000b,
0x24e4: 0x000b, 0x24e5: 0x000b, 0x24e6: 0x000b, 0x24e7: 0x000b, 0x24e8: 0x000b, 0x24e9: 0x000b,
0x24ea: 0x000b, 0x24eb: 0x000b, 0x24ec: 0x000b, 0x24ed: 0x000b, 0x24ee: 0x000b, 0x24ef: 0x000b,
0x24f0: 0x000d, 0x24f1: 0x000d, 0x24f2: 0x000d, 0x24f3: 0x000d, 0x24f4: 0x000d, 0x24f5: 0x000d,
0x24f6: 0x000d, 0x24f7: 0x000d, 0x24f8: 0x000d, 0x24f9: 0x000d, 0x24fa: 0x000d, 0x24fb: 0x000d,
0x24fc: 0x000d, 0x24fd: 0x000a, 0x24fe: 0x000a, 0x24ff: 0x000a,
// Block 0x94, offset 0x2500
0x2500: 0x000c, 0x2501: 0x000c, 0x2502: 0x000c, 0x2503: 0x000c, 0x2504: 0x000c, 0x2505: 0x000c,
0x2506: 0x000c, 0x2507: 0x000c, 0x2508: 0x000c, 0x2509: 0x000c, 0x250a: 0x000c, 0x250b: 0x000c,
0x250c: 0x000c, 0x250d: 0x000c, 0x250e: 0x000c, 0x250f: 0x000c, 0x2510: 0x000a, 0x2511: 0x000a,
0x2512: 0x000a, 0x2513: 0x000a, 0x2514: 0x000a, 0x2515: 0x000a, 0x2516: 0x000a, 0x2517: 0x000a,
0x2518: 0x000a, 0x2519: 0x000a,
0x2520: 0x000c, 0x2521: 0x000c, 0x2522: 0x000c, 0x2523: 0x000c,
0x2524: 0x000c, 0x2525: 0x000c, 0x2526: 0x000c, 0x2527: 0x000c, 0x2528: 0x000c, 0x2529: 0x000c,
0x252a: 0x000c, 0x252b: 0x000c, 0x252c: 0x000c, 0x252d: 0x000c, 0x252e: 0x000c, 0x252f: 0x000c,
0x2530: 0x000a, 0x2531: 0x000a, 0x2532: 0x000a, 0x2533: 0x000a, 0x2534: 0x000a, 0x2535: 0x000a,
0x2536: 0x000a, 0x2537: 0x000a, 0x2538: 0x000a, 0x2539: 0x000a, 0x253a: 0x000a, 0x253b: 0x000a,
0x253c: 0x000a, 0x253d: 0x000a, 0x253e: 0x000a, 0x253f: 0x000a,
// Block 0x95, offset 0x2540
0x2540: 0x000a, 0x2541: 0x000a, 0x2542: 0x000a, 0x2543: 0x000a, 0x2544: 0x000a, 0x2545: 0x000a,
0x2546: 0x000a, 0x2547: 0x000a, 0x2548: 0x000a, 0x2549: 0x000a, 0x254a: 0x000a, 0x254b: 0x000a,
0x254c: 0x000a, 0x254d: 0x000a, 0x254e: 0x000a, 0x254f: 0x000a, 0x2550: 0x0006, 0x2551: 0x000a,
0x2552: 0x0006, 0x2554: 0x000a, 0x2555: 0x0006, 0x2556: 0x000a, 0x2557: 0x000a,
0x2558: 0x000a, 0x2559: 0x009a, 0x255a: 0x008a, 0x255b: 0x007a, 0x255c: 0x006a, 0x255d: 0x009a,
0x255e: 0x008a, 0x255f: 0x0004, 0x2560: 0x000a, 0x2561: 0x000a, 0x2562: 0x0003, 0x2563: 0x0003,
0x2564: 0x000a, 0x2565: 0x000a, 0x2566: 0x000a, 0x2568: 0x000a, 0x2569: 0x0004,
0x256a: 0x0004, 0x256b: 0x000a,
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: 0x000d,
// Block 0x96, offset 0x2580
0x2580: 0x000d, 0x2581: 0x000d, 0x2582: 0x000d, 0x2583: 0x000d, 0x2584: 0x000d, 0x2585: 0x000d,
0x2586: 0x000d, 0x2587: 0x000d, 0x2588: 0x000d, 0x2589: 0x000d, 0x258a: 0x000d, 0x258b: 0x000d,
0x258c: 0x000d, 0x258d: 0x000d, 0x258e: 0x000d, 0x258f: 0x000d, 0x2590: 0x000d, 0x2591: 0x000d,
0x2592: 0x000d, 0x2593: 0x000d, 0x2594: 0x000d, 0x2595: 0x000d, 0x2596: 0x000d, 0x2597: 0x000d,
0x2598: 0x000d, 0x2599: 0x000d, 0x259a: 0x000d, 0x259b: 0x000d, 0x259c: 0x000d, 0x259d: 0x000d,
0x259e: 0x000d, 0x259f: 0x000d, 0x25a0: 0x000d, 0x25a1: 0x000d, 0x25a2: 0x000d, 0x25a3: 0x000d,
0x25a4: 0x000d, 0x25a5: 0x000d, 0x25a6: 0x000d, 0x25a7: 0x000d, 0x25a8: 0x000d, 0x25a9: 0x000d,
0x25aa: 0x000d, 0x25ab: 0x000d, 0x25ac: 0x000d, 0x25ad: 0x000d, 0x25ae: 0x000d, 0x25af: 0x000d,
0x25b0: 0x000d, 0x25b1: 0x000d, 0x25b2: 0x000d, 0x25b3: 0x000d, 0x25b4: 0x000d, 0x25b5: 0x000d,
0x25b6: 0x000d, 0x25b7: 0x000d, 0x25b8: 0x000d, 0x25b9: 0x000d, 0x25ba: 0x000d, 0x25bb: 0x000d,
0x25bc: 0x000d, 0x25bd: 0x000d, 0x25be: 0x000d, 0x25bf: 0x000b,
// Block 0x97, offset 0x25c0
0x25c1: 0x000a, 0x25c2: 0x000a, 0x25c3: 0x0004, 0x25c4: 0x0004, 0x25c5: 0x0004,
0x25c6: 0x000a, 0x25c7: 0x000a, 0x25c8: 0x003a, 0x25c9: 0x002a, 0x25ca: 0x000a, 0x25cb: 0x0003,
0x25cc: 0x0006, 0x25cd: 0x0003, 0x25ce: 0x0006, 0x25cf: 0x0006, 0x25d0: 0x0002, 0x25d1: 0x0002,
0x25d2: 0x0002, 0x25d3: 0x0002, 0x25d4: 0x0002, 0x25d5: 0x0002, 0x25d6: 0x0002, 0x25d7: 0x0002,
0x25d8: 0x0002, 0x25d9: 0x0002, 0x25da: 0x0006, 0x25db: 0x000a, 0x25dc: 0x000a, 0x25dd: 0x000a,
0x25de: 0x000a, 0x25df: 0x000a, 0x25e0: 0x000a,
0x25fb: 0x005a,
0x25fc: 0x000a, 0x25fd: 0x004a, 0x25fe: 0x000a, 0x25ff: 0x000a,
// Block 0x98, offset 0x2600
0x2600: 0x000a,
0x261b: 0x005a, 0x261c: 0x000a, 0x261d: 0x004a,
0x261e: 0x000a, 0x261f: 0x00fa, 0x2620: 0x00ea, 0x2621: 0x000a, 0x2622: 0x003a, 0x2623: 0x002a,
0x2624: 0x000a, 0x2625: 0x000a,
// Block 0x99, offset 0x2640
0x2660: 0x0004, 0x2661: 0x0004, 0x2662: 0x000a, 0x2663: 0x000a,
0x2664: 0x000a, 0x2665: 0x0004, 0x2666: 0x0004, 0x2668: 0x000a, 0x2669: 0x000a,
0x266a: 0x000a, 0x266b: 0x000a, 0x266c: 0x000a, 0x266d: 0x000a, 0x266e: 0x000a,
0x2670: 0x000b, 0x2671: 0x000b, 0x2672: 0x000b, 0x2673: 0x000b, 0x2674: 0x000b, 0x2675: 0x000b,
0x2676: 0x000b, 0x2677: 0x000b, 0x2678: 0x000b, 0x2679: 0x000a, 0x267a: 0x000a, 0x267b: 0x000a,
0x267c: 0x000a, 0x267d: 0x000a, 0x267e: 0x000b, 0x267f: 0x000b,
// Block 0x9a, offset 0x2680
0x2681: 0x000a,
// Block 0x9b, offset 0x26c0
0x26c0: 0x000a, 0x26c1: 0x000a, 0x26c2: 0x000a, 0x26c3: 0x000a, 0x26c4: 0x000a, 0x26c5: 0x000a,
0x26c6: 0x000a, 0x26c7: 0x000a, 0x26c8: 0x000a, 0x26c9: 0x000a, 0x26ca: 0x000a, 0x26cb: 0x000a,
0x26cc: 0x000a, 0x26d0: 0x000a, 0x26d1: 0x000a,
0x26d2: 0x000a, 0x26d3: 0x000a, 0x26d4: 0x000a, 0x26d5: 0x000a, 0x26d6: 0x000a, 0x26d7: 0x000a,
0x26d8: 0x000a, 0x26d9: 0x000a, 0x26da: 0x000a, 0x26db: 0x000a, 0x26dc: 0x000a,
0x26e0: 0x000a,
// Block 0x9c, offset 0x2700
0x273d: 0x000c,
// Block 0x9d, offset 0x2740
0x2760: 0x000c, 0x2761: 0x0002, 0x2762: 0x0002, 0x2763: 0x0002,
0x2764: 0x0002, 0x2765: 0x0002, 0x2766: 0x0002, 0x2767: 0x0002, 0x2768: 0x0002, 0x2769: 0x0002,
0x276a: 0x0002, 0x276b: 0x0002, 0x276c: 0x0002, 0x276d: 0x0002, 0x276e: 0x0002, 0x276f: 0x0002,
0x2770: 0x0002, 0x2771: 0x0002, 0x2772: 0x0002, 0x2773: 0x0002, 0x2774: 0x0002, 0x2775: 0x0002,
0x2776: 0x0002, 0x2777: 0x0002, 0x2778: 0x0002, 0x2779: 0x0002, 0x277a: 0x0002, 0x277b: 0x0002,
// Block 0x9e, offset 0x2780
0x27b6: 0x000c, 0x27b7: 0x000c, 0x27b8: 0x000c, 0x27b9: 0x000c, 0x27ba: 0x000c,
// 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: 0x0001, 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: 0x0001, 0x2802: 0x0001, 0x2803: 0x0001, 0x2804: 0x0001, 0x2805: 0x0001,
0x2806: 0x0001, 0x2807: 0x0001, 0x2808: 0x0001, 0x2809: 0x0001, 0x280a: 0x0001, 0x280b: 0x0001,
0x280c: 0x0001, 0x280d: 0x0001, 0x280e: 0x0001, 0x280f: 0x0001, 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: 0x000a, 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: 0x0001, 0x2839: 0x0001, 0x283a: 0x0001, 0x283b: 0x0001,
0x283c: 0x0001, 0x283d: 0x0001, 0x283e: 0x0001, 0x283f: 0x0001,
// Block 0xa1, offset 0x2840
0x2840: 0x0001, 0x2841: 0x000c, 0x2842: 0x000c, 0x2843: 0x000c, 0x2844: 0x0001, 0x2845: 0x000c,
0x2846: 0x000c, 0x2847: 0x0001, 0x2848: 0x0001, 0x2849: 0x0001, 0x284a: 0x0001, 0x284b: 0x0001,
0x284c: 0x000c, 0x284d: 0x000c, 0x284e: 0x000c, 0x284f: 0x000c, 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: 0x0001, 0x2866: 0x0001, 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: 0x000c, 0x2879: 0x000c, 0x287a: 0x000c, 0x287b: 0x0001,
0x287c: 0x0001, 0x287d: 0x0001, 0x287e: 0x0001, 0x287f: 0x000c,
// 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: 0x000c, 0x28a6: 0x000c, 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: 0x0001, 0x28ba: 0x0001, 0x28bb: 0x0001,
0x28bc: 0x0001, 0x28bd: 0x0001, 0x28be: 0x0001, 0x28bf: 0x0001,
// Block 0xa3, offset 0x28c0
0x28c0: 0x0001, 0x28c1: 0x0001, 0x28c2: 0x0001, 0x28c3: 0x0001, 0x28c4: 0x0001, 0x28c5: 0x0001,
0x28c6: 0x0001, 0x28c7: 0x0001, 0x28c8: 0x0001, 0x28c9: 0x0001, 0x28ca: 0x0001, 0x28cb: 0x0001,
0x28cc: 0x0001, 0x28cd: 0x0001, 0x28ce: 0x0001, 0x28cf: 0x0001, 0x28d0: 0x0001, 0x28d1: 0x0001,
0x28d2: 0x0001, 0x28d3: 0x0001, 0x28d4: 0x0001, 0x28d5: 0x0001, 0x28d6: 0x0001, 0x28d7: 0x0001,
0x28d8: 0x0001, 0x28d9: 0x0001, 0x28da: 0x0001, 0x28db: 0x0001, 0x28dc: 0x0001, 0x28dd: 0x0001,
0x28de: 0x0001, 0x28df: 0x0001, 0x28e0: 0x0001, 0x28e1: 0x0001, 0x28e2: 0x0001, 0x28e3: 0x0001,
0x28e4: 0x0001, 0x28e5: 0x0001, 0x28e6: 0x0001, 0x28e7: 0x0001, 0x28e8: 0x0001, 0x28e9: 0x0001,
0x28ea: 0x0001, 0x28eb: 0x0001, 0x28ec: 0x0001, 0x28ed: 0x0001, 0x28ee: 0x0001, 0x28ef: 0x0001,
0x28f0: 0x0001, 0x28f1: 0x0001, 0x28f2: 0x0001, 0x28f3: 0x0001, 0x28f4: 0x0001, 0x28f5: 0x0001,
0x28f6: 0x0001, 0x28f7: 0x0001, 0x28f8: 0x0001, 0x28f9: 0x000a, 0x28fa: 0x000a, 0x28fb: 0x000a,
0x28fc: 0x000a, 0x28fd: 0x000a, 0x28fe: 0x000a, 0x28ff: 0x000a,
// Block 0xa4, offset 0x2900
0x2900: 0x000d, 0x2901: 0x000d, 0x2902: 0x000d, 0x2903: 0x000d, 0x2904: 0x000d, 0x2905: 0x000d,
0x2906: 0x000d, 0x2907: 0x000d, 0x2908: 0x000d, 0x2909: 0x000d, 0x290a: 0x000d, 0x290b: 0x000d,
0x290c: 0x000d, 0x290d: 0x000d, 0x290e: 0x000d, 0x290f: 0x000d, 0x2910: 0x000d, 0x2911: 0x000d,
0x2912: 0x000d, 0x2913: 0x000d, 0x2914: 0x000d, 0x2915: 0x000d, 0x2916: 0x000d, 0x2917: 0x000d,
0x2918: 0x000d, 0x2919: 0x000d, 0x291a: 0x000d, 0x291b: 0x000d, 0x291c: 0x000d, 0x291d: 0x000d,
0x291e: 0x000d, 0x291f: 0x000d, 0x2920: 0x000d, 0x2921: 0x000d, 0x2922: 0x000d, 0x2923: 0x000d,
0x2924: 0x000c, 0x2925: 0x000c, 0x2926: 0x000c, 0x2927: 0x000c, 0x2928: 0x0001, 0x2929: 0x0001,
0x292a: 0x0001, 0x292b: 0x0001, 0x292c: 0x0001, 0x292d: 0x0001, 0x292e: 0x0001, 0x292f: 0x0001,
0x2930: 0x0005, 0x2931: 0x0005, 0x2932: 0x0005, 0x2933: 0x0005, 0x2934: 0x0005, 0x2935: 0x0005,
0x2936: 0x0005, 0x2937: 0x0005, 0x2938: 0x0005, 0x2939: 0x0005, 0x293a: 0x0001, 0x293b: 0x0001,
0x293c: 0x0001, 0x293d: 0x0001, 0x293e: 0x0001, 0x293f: 0x0001,
// Block 0xa5, offset 0x2940
0x2940: 0x0005, 0x2941: 0x0005, 0x2942: 0x0005, 0x2943: 0x0005, 0x2944: 0x0005, 0x2945: 0x0005,
0x2946: 0x0005, 0x2947: 0x0005, 0x2948: 0x0005, 0x2949: 0x0005, 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: 0x000c,
0x296a: 0x000c, 0x296b: 0x000c, 0x296c: 0x000c, 0x296d: 0x000c, 0x296e: 0x000a, 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: 0x0005, 0x29a1: 0x0005, 0x29a2: 0x0005, 0x29a3: 0x0005,
0x29a4: 0x0005, 0x29a5: 0x0005, 0x29a6: 0x0005, 0x29a7: 0x0005, 0x29a8: 0x0005, 0x29a9: 0x0005,
0x29aa: 0x0005, 0x29ab: 0x0005, 0x29ac: 0x0005, 0x29ad: 0x0005, 0x29ae: 0x0005, 0x29af: 0x0005,
0x29b0: 0x0005, 0x29b1: 0x0005, 0x29b2: 0x0005, 0x29b3: 0x0005, 0x29b4: 0x0005, 0x29b5: 0x0005,
0x29b6: 0x0005, 0x29b7: 0x0005, 0x29b8: 0x0005, 0x29b9: 0x0005, 0x29ba: 0x0005, 0x29bb: 0x0005,
0x29bc: 0x0005, 0x29bd: 0x0005, 0x29be: 0x0005, 0x29bf: 0x0001,
// 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: 0x000c, 0x29ec: 0x000c, 0x29ed: 0x0001, 0x29ee: 0x0001, 0x29ef: 0x0001,
0x29f0: 0x0001, 0x29f1: 0x0001, 0x29f2: 0x0001, 0x29f3: 0x0001, 0x29f4: 0x0001, 0x29f5: 0x0001,
0x29f6: 0x0001, 0x29f7: 0x0001, 0x29f8: 0x0001, 0x29f9: 0x0001, 0x29fa: 0x0001, 0x29fb: 0x0001,
0x29fc: 0x0001, 0x29fd: 0x0001, 0x29fe: 0x0001, 0x29ff: 0x0001,
// Block 0xa8, offset 0x2a00
0x2a00: 0x0001, 0x2a01: 0x0001, 0x2a02: 0x000d, 0x2a03: 0x000d, 0x2a04: 0x000d, 0x2a05: 0x000d,
0x2a06: 0x000d, 0x2a07: 0x000d, 0x2a08: 0x0001, 0x2a09: 0x0001, 0x2a0a: 0x0001, 0x2a0b: 0x0001,
0x2a0c: 0x0001, 0x2a0d: 0x0001, 0x2a0e: 0x0001, 0x2a0f: 0x0001, 0x2a10: 0x000a, 0x2a11: 0x000a,
0x2a12: 0x000a, 0x2a13: 0x000a, 0x2a14: 0x000a, 0x2a15: 0x000a, 0x2a16: 0x000a, 0x2a17: 0x000a,
0x2a18: 0x000a, 0x2a19: 0x0001, 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: 0x000c, 0x2a3b: 0x000c,
0x2a3c: 0x000c, 0x2a3d: 0x000c, 0x2a3e: 0x000c, 0x2a3f: 0x000c,
// Block 0xa9, offset 0x2a40
0x2a40: 0x0001, 0x2a41: 0x0001, 0x2a42: 0x0001, 0x2a43: 0x0001, 0x2a44: 0x0001, 0x2a45: 0x0001,
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: 0x000d, 0x2a71: 0x000d, 0x2a72: 0x000d, 0x2a73: 0x000d, 0x2a74: 0x000d, 0x2a75: 0x000d,
0x2a76: 0x000d, 0x2a77: 0x000d, 0x2a78: 0x000d, 0x2a79: 0x000d, 0x2a7a: 0x000d, 0x2a7b: 0x000d,
0x2a7c: 0x000d, 0x2a7d: 0x000d, 0x2a7e: 0x000d, 0x2a7f: 0x000d,
// Block 0xaa, offset 0x2a80
0x2a80: 0x000d, 0x2a81: 0x000d, 0x2a82: 0x000d, 0x2a83: 0x000d, 0x2a84: 0x000d, 0x2a85: 0x000d,
0x2a86: 0x000c, 0x2a87: 0x000c, 0x2a88: 0x000c, 0x2a89: 0x000c, 0x2a8a: 0x000c, 0x2a8b: 0x000c,
0x2a8c: 0x000c, 0x2a8d: 0x000c, 0x2a8e: 0x000c, 0x2a8f: 0x000c, 0x2a90: 0x000c, 0x2a91: 0x000d,
0x2a92: 0x000d, 0x2a93: 0x000d, 0x2a94: 0x000d, 0x2a95: 0x000d, 0x2a96: 0x000d, 0x2a97: 0x000d,
0x2a98: 0x000d, 0x2a99: 0x000d, 0x2a9a: 0x0001, 0x2a9b: 0x0001, 0x2a9c: 0x0001, 0x2a9d: 0x0001,
0x2a9e: 0x0001, 0x2a9f: 0x0001, 0x2aa0: 0x0001, 0x2aa1: 0x0001, 0x2aa2: 0x0001, 0x2aa3: 0x0001,
0x2aa4: 0x0001, 0x2aa5: 0x0001, 0x2aa6: 0x0001, 0x2aa7: 0x0001, 0x2aa8: 0x0001, 0x2aa9: 0x0001,
0x2aaa: 0x0001, 0x2aab: 0x0001, 0x2aac: 0x0001, 0x2aad: 0x0001, 0x2aae: 0x0001, 0x2aaf: 0x0001,
0x2ab0: 0x0001, 0x2ab1: 0x0001, 0x2ab2: 0x0001, 0x2ab3: 0x0001, 0x2ab4: 0x0001, 0x2ab5: 0x0001,
0x2ab6: 0x0001, 0x2ab7: 0x0001, 0x2ab8: 0x0001, 0x2ab9: 0x0001, 0x2aba: 0x0001, 0x2abb: 0x0001,
0x2abc: 0x0001, 0x2abd: 0x0001, 0x2abe: 0x0001, 0x2abf: 0x0001,
// Block 0xab, offset 0x2ac0
0x2ac0: 0x0001, 0x2ac1: 0x0001, 0x2ac2: 0x000c, 0x2ac3: 0x000c, 0x2ac4: 0x000c, 0x2ac5: 0x000c,
0x2ac6: 0x0001, 0x2ac7: 0x0001, 0x2ac8: 0x0001, 0x2ac9: 0x0001, 0x2aca: 0x0001, 0x2acb: 0x0001,
0x2acc: 0x0001, 0x2acd: 0x0001, 0x2ace: 0x0001, 0x2acf: 0x0001, 0x2ad0: 0x0001, 0x2ad1: 0x0001,
0x2ad2: 0x0001, 0x2ad3: 0x0001, 0x2ad4: 0x0001, 0x2ad5: 0x0001, 0x2ad6: 0x0001, 0x2ad7: 0x0001,
0x2ad8: 0x0001, 0x2ad9: 0x0001, 0x2ada: 0x0001, 0x2adb: 0x0001, 0x2adc: 0x0001, 0x2add: 0x0001,
0x2ade: 0x0001, 0x2adf: 0x0001, 0x2ae0: 0x0001, 0x2ae1: 0x0001, 0x2ae2: 0x0001, 0x2ae3: 0x0001,
0x2ae4: 0x0001, 0x2ae5: 0x0001, 0x2ae6: 0x0001, 0x2ae7: 0x0001, 0x2ae8: 0x0001, 0x2ae9: 0x0001,
0x2aea: 0x0001, 0x2aeb: 0x0001, 0x2aec: 0x0001, 0x2aed: 0x0001, 0x2aee: 0x0001, 0x2aef: 0x0001,
0x2af0: 0x0001, 0x2af1: 0x0001, 0x2af2: 0x0001, 0x2af3: 0x0001, 0x2af4: 0x0001, 0x2af5: 0x0001,
0x2af6: 0x0001, 0x2af7: 0x0001, 0x2af8: 0x0001, 0x2af9: 0x0001, 0x2afa: 0x0001, 0x2afb: 0x0001,
0x2afc: 0x0001, 0x2afd: 0x0001, 0x2afe: 0x0001, 0x2aff: 0x0001,
// Block 0xac, offset 0x2b00
0x2b01: 0x000c,
0x2b38: 0x000c, 0x2b39: 0x000c, 0x2b3a: 0x000c, 0x2b3b: 0x000c,
0x2b3c: 0x000c, 0x2b3d: 0x000c, 0x2b3e: 0x000c, 0x2b3f: 0x000c,
// Block 0xad, offset 0x2b40
0x2b40: 0x000c, 0x2b41: 0x000c, 0x2b42: 0x000c, 0x2b43: 0x000c, 0x2b44: 0x000c, 0x2b45: 0x000c,
0x2b46: 0x000c,
0x2b52: 0x000a, 0x2b53: 0x000a, 0x2b54: 0x000a, 0x2b55: 0x000a, 0x2b56: 0x000a, 0x2b57: 0x000a,
0x2b58: 0x000a, 0x2b59: 0x000a, 0x2b5a: 0x000a, 0x2b5b: 0x000a, 0x2b5c: 0x000a, 0x2b5d: 0x000a,
0x2b5e: 0x000a, 0x2b5f: 0x000a, 0x2b60: 0x000a, 0x2b61: 0x000a, 0x2b62: 0x000a, 0x2b63: 0x000a,
0x2b64: 0x000a, 0x2b65: 0x000a,
0x2b70: 0x000c, 0x2b73: 0x000c, 0x2b74: 0x000c,
0x2b7f: 0x000c,
// Block 0xae, offset 0x2b80
0x2b80: 0x000c, 0x2b81: 0x000c,
0x2bb3: 0x000c, 0x2bb4: 0x000c, 0x2bb5: 0x000c,
0x2bb6: 0x000c, 0x2bb9: 0x000c, 0x2bba: 0x000c,
// Block 0xaf, offset 0x2bc0
0x2bc0: 0x000c, 0x2bc1: 0x000c, 0x2bc2: 0x000c,
0x2be7: 0x000c, 0x2be8: 0x000c, 0x2be9: 0x000c,
0x2bea: 0x000c, 0x2beb: 0x000c, 0x2bed: 0x000c, 0x2bee: 0x000c, 0x2bef: 0x000c,
0x2bf0: 0x000c, 0x2bf1: 0x000c, 0x2bf2: 0x000c, 0x2bf3: 0x000c, 0x2bf4: 0x000c,
// Block 0xb0, offset 0x2c00
0x2c33: 0x000c,
// Block 0xb1, offset 0x2c40
0x2c40: 0x000c, 0x2c41: 0x000c,
0x2c76: 0x000c, 0x2c77: 0x000c, 0x2c78: 0x000c, 0x2c79: 0x000c, 0x2c7a: 0x000c, 0x2c7b: 0x000c,
0x2c7c: 0x000c, 0x2c7d: 0x000c, 0x2c7e: 0x000c,
// Block 0xb2, offset 0x2c80
0x2c89: 0x000c, 0x2c8a: 0x000c, 0x2c8b: 0x000c,
0x2c8c: 0x000c, 0x2c8f: 0x000c,
// Block 0xb3, offset 0x2cc0
0x2cef: 0x000c,
0x2cf0: 0x000c, 0x2cf1: 0x000c, 0x2cf4: 0x000c,
0x2cf6: 0x000c, 0x2cf7: 0x000c,
0x2cfe: 0x000c,
// Block 0xb4, offset 0x2d00
0x2d1f: 0x000c, 0x2d23: 0x000c,
0x2d24: 0x000c, 0x2d25: 0x000c, 0x2d26: 0x000c, 0x2d27: 0x000c, 0x2d28: 0x000c, 0x2d29: 0x000c,
0x2d2a: 0x000c,
// Block 0xb5, offset 0x2d40
0x2d40: 0x000c,
0x2d66: 0x000c, 0x2d67: 0x000c, 0x2d68: 0x000c, 0x2d69: 0x000c,
0x2d6a: 0x000c, 0x2d6b: 0x000c, 0x2d6c: 0x000c,
0x2d70: 0x000c, 0x2d71: 0x000c, 0x2d72: 0x000c, 0x2d73: 0x000c, 0x2d74: 0x000c,
// Block 0xb6, offset 0x2d80
0x2dbb: 0x000c,
0x2dbc: 0x000c, 0x2dbd: 0x000c, 0x2dbe: 0x000c, 0x2dbf: 0x000c,
// Block 0xb7, offset 0x2dc0
0x2dc0: 0x000c,
0x2dce: 0x000c, 0x2dd0: 0x000c,
0x2dd2: 0x000c,
0x2de1: 0x000c, 0x2de2: 0x000c,
// Block 0xb8, offset 0x2e00
0x2e38: 0x000c, 0x2e39: 0x000c, 0x2e3a: 0x000c, 0x2e3b: 0x000c,
0x2e3c: 0x000c, 0x2e3d: 0x000c, 0x2e3e: 0x000c, 0x2e3f: 0x000c,
// Block 0xb9, offset 0x2e40
0x2e42: 0x000c, 0x2e43: 0x000c, 0x2e44: 0x000c,
0x2e46: 0x000c,
0x2e5e: 0x000c,
// Block 0xba, offset 0x2e80
0x2eb3: 0x000c, 0x2eb4: 0x000c, 0x2eb5: 0x000c,
0x2eb6: 0x000c, 0x2eb7: 0x000c, 0x2eb8: 0x000c, 0x2eba: 0x000c,
0x2ebf: 0x000c,
// Block 0xbb, offset 0x2ec0
0x2ec0: 0x000c, 0x2ec2: 0x000c, 0x2ec3: 0x000c,
// Block 0xbc, offset 0x2f00
0x2f32: 0x000c, 0x2f33: 0x000c, 0x2f34: 0x000c, 0x2f35: 0x000c,
0x2f3c: 0x000c, 0x2f3d: 0x000c, 0x2f3f: 0x000c,
// Block 0xbd, offset 0x2f40
0x2f40: 0x000c,
0x2f5c: 0x000c, 0x2f5d: 0x000c,
// Block 0xbe, offset 0x2f80
0x2fb3: 0x000c, 0x2fb4: 0x000c, 0x2fb5: 0x000c,
0x2fb6: 0x000c, 0x2fb7: 0x000c, 0x2fb8: 0x000c, 0x2fb9: 0x000c, 0x2fba: 0x000c,
0x2fbd: 0x000c, 0x2fbf: 0x000c,
// Block 0xbf, offset 0x2fc0
0x2fc0: 0x000c,
0x2fe0: 0x000a, 0x2fe1: 0x000a, 0x2fe2: 0x000a, 0x2fe3: 0x000a,
0x2fe4: 0x000a, 0x2fe5: 0x000a, 0x2fe6: 0x000a, 0x2fe7: 0x000a, 0x2fe8: 0x000a, 0x2fe9: 0x000a,
0x2fea: 0x000a, 0x2feb: 0x000a, 0x2fec: 0x000a,
// Block 0xc0, offset 0x3000
0x302b: 0x000c, 0x302d: 0x000c,
0x3030: 0x000c, 0x3031: 0x000c, 0x3032: 0x000c, 0x3033: 0x000c, 0x3034: 0x000c, 0x3035: 0x000c,
0x3037: 0x000c,
// Block 0xc1, offset 0x3040
0x305d: 0x000c,
0x305f: 0x000c, 0x3062: 0x000c, 0x3063: 0x000c,
0x3064: 0x000c, 0x3065: 0x000c, 0x3067: 0x000c, 0x3068: 0x000c, 0x3069: 0x000c,
0x306a: 0x000c, 0x306b: 0x000c,
// Block 0xc2, offset 0x3080
0x30af: 0x000c,
0x30b0: 0x000c, 0x30b1: 0x000c, 0x30b2: 0x000c, 0x30b3: 0x000c, 0x30b4: 0x000c, 0x30b5: 0x000c,
0x30b6: 0x000c, 0x30b7: 0x000c, 0x30b9: 0x000c, 0x30ba: 0x000c,
// Block 0xc3, offset 0x30c0
0x30fb: 0x000c,
0x30fc: 0x000c, 0x30fe: 0x000c,
// Block 0xc4, offset 0x3100
0x3103: 0x000c,
// Block 0xc5, offset 0x3140
0x3154: 0x000c, 0x3155: 0x000c, 0x3156: 0x000c, 0x3157: 0x000c,
0x315a: 0x000c, 0x315b: 0x000c,
0x3160: 0x000c,
// Block 0xc6, offset 0x3180
0x3181: 0x000c, 0x3182: 0x000c, 0x3183: 0x000c, 0x3184: 0x000c, 0x3185: 0x000c,
0x3186: 0x000c, 0x3189: 0x000c, 0x318a: 0x000c,
0x31b3: 0x000c, 0x31b4: 0x000c, 0x31b5: 0x000c,
0x31b6: 0x000c, 0x31b7: 0x000c, 0x31b8: 0x000c, 0x31bb: 0x000c,
0x31bc: 0x000c, 0x31bd: 0x000c, 0x31be: 0x000c,
// Block 0xc7, offset 0x31c0
0x31c7: 0x000c,
0x31d1: 0x000c,
0x31d2: 0x000c, 0x31d3: 0x000c, 0x31d4: 0x000c, 0x31d5: 0x000c, 0x31d6: 0x000c,
0x31d9: 0x000c, 0x31da: 0x000c, 0x31db: 0x000c,
// Block 0xc8, offset 0x3200
0x320a: 0x000c, 0x320b: 0x000c,
0x320c: 0x000c, 0x320d: 0x000c, 0x320e: 0x000c, 0x320f: 0x000c, 0x3210: 0x000c, 0x3211: 0x000c,
0x3212: 0x000c, 0x3213: 0x000c, 0x3214: 0x000c, 0x3215: 0x000c, 0x3216: 0x000c,
0x3218: 0x000c, 0x3219: 0x000c,
// Block 0xc9, offset 0x3240
0x3260: 0x000c, 0x3262: 0x000c, 0x3263: 0x000c,
0x3264: 0x000c, 0x3266: 0x000c,
// Block 0xca, offset 0x3280
0x32b0: 0x000c, 0x32b1: 0x000c, 0x32b2: 0x000c, 0x32b3: 0x000c, 0x32b4: 0x000c, 0x32b5: 0x000c,
0x32b6: 0x000c, 0x32b8: 0x000c, 0x32b9: 0x000c, 0x32ba: 0x000c, 0x32bb: 0x000c,
0x32bc: 0x000c, 0x32bd: 0x000c,
// Block 0xcb, offset 0x32c0
0x32d2: 0x000c, 0x32d3: 0x000c, 0x32d4: 0x000c, 0x32d5: 0x000c, 0x32d6: 0x000c, 0x32d7: 0x000c,
0x32d8: 0x000c, 0x32d9: 0x000c, 0x32da: 0x000c, 0x32db: 0x000c, 0x32dc: 0x000c, 0x32dd: 0x000c,
0x32de: 0x000c, 0x32df: 0x000c, 0x32e0: 0x000c, 0x32e1: 0x000c, 0x32e2: 0x000c, 0x32e3: 0x000c,
0x32e4: 0x000c, 0x32e5: 0x000c, 0x32e6: 0x000c, 0x32e7: 0x000c,
0x32ea: 0x000c, 0x32eb: 0x000c, 0x32ec: 0x000c, 0x32ed: 0x000c, 0x32ee: 0x000c, 0x32ef: 0x000c,
0x32f0: 0x000c, 0x32f2: 0x000c, 0x32f3: 0x000c, 0x32f5: 0x000c,
0x32f6: 0x000c,
// Block 0xcc, offset 0x3300
0x3331: 0x000c, 0x3332: 0x000c, 0x3333: 0x000c, 0x3334: 0x000c, 0x3335: 0x000c,
0x3336: 0x000c, 0x333a: 0x000c,
0x333c: 0x000c, 0x333d: 0x000c, 0x333f: 0x000c,
// Block 0xcd, offset 0x3340
0x3340: 0x000c, 0x3341: 0x000c, 0x3342: 0x000c, 0x3343: 0x000c, 0x3344: 0x000c, 0x3345: 0x000c,
0x3347: 0x000c,
// Block 0xce, offset 0x3380
0x3390: 0x000c, 0x3391: 0x000c,
0x3395: 0x000c, 0x3397: 0x000c,
// Block 0xcf, offset 0x33c0
0x33f3: 0x000c, 0x33f4: 0x000c,
// Block 0xd0, offset 0x3400
0x3400: 0x000c, 0x3401: 0x000c,
0x3436: 0x000c, 0x3437: 0x000c, 0x3438: 0x000c, 0x3439: 0x000c, 0x343a: 0x000c,
// Block 0xd1, offset 0x3440
0x3440: 0x000c, 0x3442: 0x000c,
0x345a: 0x000c,
// Block 0xd2, offset 0x3480
0x3495: 0x000a, 0x3496: 0x000a, 0x3497: 0x000a,
0x3498: 0x000a, 0x3499: 0x000a, 0x349a: 0x000a, 0x349b: 0x000a, 0x349c: 0x000a, 0x349d: 0x0004,
0x349e: 0x0004, 0x349f: 0x0004, 0x34a0: 0x0004, 0x34a1: 0x000a, 0x34a2: 0x000a, 0x34a3: 0x000a,
0x34a4: 0x000a, 0x34a5: 0x000a, 0x34a6: 0x000a, 0x34a7: 0x000a, 0x34a8: 0x000a, 0x34a9: 0x000a,
0x34aa: 0x000a, 0x34ab: 0x000a, 0x34ac: 0x000a, 0x34ad: 0x000a, 0x34ae: 0x000a, 0x34af: 0x000a,
0x34b0: 0x000a, 0x34b1: 0x000a,
// Block 0xd3, offset 0x34c0
0x34c0: 0x000c,
0x34c7: 0x000c, 0x34c8: 0x000c, 0x34c9: 0x000c, 0x34ca: 0x000c, 0x34cb: 0x000c,
0x34cc: 0x000c, 0x34cd: 0x000c, 0x34ce: 0x000c, 0x34cf: 0x000c, 0x34d0: 0x000c, 0x34d1: 0x000c,
0x34d2: 0x000c, 0x34d3: 0x000c, 0x34d4: 0x000c, 0x34d5: 0x000c,
// Block 0xd4, offset 0x3500
0x351e: 0x000c, 0x351f: 0x000c, 0x3520: 0x000c, 0x3521: 0x000c, 0x3522: 0x000c, 0x3523: 0x000c,
0x3524: 0x000c, 0x3525: 0x000c, 0x3526: 0x000c, 0x3527: 0x000c, 0x3528: 0x000c, 0x3529: 0x000c,
0x352d: 0x000c, 0x352e: 0x000c, 0x352f: 0x000c,
// Block 0xd5, offset 0x3540
0x3570: 0x000c, 0x3571: 0x000c, 0x3572: 0x000c, 0x3573: 0x000c, 0x3574: 0x000c,
// Block 0xd6, offset 0x3580
0x35b0: 0x000c, 0x35b1: 0x000c, 0x35b2: 0x000c, 0x35b3: 0x000c, 0x35b4: 0x000c, 0x35b5: 0x000c,
0x35b6: 0x000c,
// Block 0xd7, offset 0x35c0
0x35cf: 0x000c,
// Block 0xd8, offset 0x3600
0x360f: 0x000c, 0x3610: 0x000c, 0x3611: 0x000c,
0x3612: 0x000c,
// Block 0xd9, offset 0x3640
0x3662: 0x000a,
0x3664: 0x000c,
// Block 0xda, offset 0x3680
0x369d: 0x000c,
0x369e: 0x000c, 0x36a0: 0x000b, 0x36a1: 0x000b, 0x36a2: 0x000b, 0x36a3: 0x000b,
// 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,
0x36f0: 0x0002, 0x36f1: 0x0002, 0x36f2: 0x0002, 0x36f3: 0x0002, 0x36f4: 0x0002, 0x36f5: 0x0002,
0x36f6: 0x0002, 0x36f7: 0x0002, 0x36f8: 0x0002, 0x36f9: 0x0002, 0x36fa: 0x000a, 0x36fb: 0x000a,
0x36fc: 0x000a,
// Block 0xdc, offset 0x3700
0x3700: 0x000a, 0x3701: 0x000a, 0x3702: 0x000a, 0x3703: 0x000a, 0x3704: 0x000a, 0x3705: 0x000a,
0x3706: 0x000a, 0x3707: 0x000a, 0x3708: 0x000a, 0x3709: 0x000a, 0x370a: 0x000a, 0x370b: 0x000a,
0x370c: 0x000a, 0x370d: 0x000a, 0x370e: 0x000a, 0x370f: 0x000a, 0x3710: 0x000a, 0x3711: 0x000a,
0x3712: 0x000a, 0x3713: 0x000a, 0x3714: 0x000a, 0x3715: 0x000a, 0x3716: 0x000a, 0x3717: 0x000a,
0x3718: 0x000a, 0x3719: 0x000a, 0x371a: 0x000a, 0x371b: 0x000a, 0x371c: 0x000a, 0x371d: 0x000a,
0x371e: 0x000a, 0x371f: 0x000a, 0x3720: 0x000a, 0x3721: 0x000a, 0x3722: 0x000a, 0x3723: 0x000a,
0x3724: 0x000a, 0x3725: 0x000a, 0x3726: 0x000a, 0x3727: 0x000a, 0x3728: 0x000a, 0x3729: 0x000a,
0x372a: 0x000a, 0x372b: 0x000a, 0x372c: 0x000a, 0x372d: 0x000a, 0x372e: 0x000a, 0x372f: 0x000a,
0x3730: 0x000a, 0x3731: 0x000a, 0x3732: 0x000a, 0x3733: 0x000a,
0x373a: 0x000a, 0x373b: 0x000a,
0x373c: 0x000a, 0x373d: 0x000a, 0x373e: 0x000a, 0x373f: 0x000a,
// Block 0xdd, offset 0x3740
0x3740: 0x000a, 0x3741: 0x000a, 0x3742: 0x000a, 0x3743: 0x000a, 0x3744: 0x000a, 0x3745: 0x000a,
0x3746: 0x000a, 0x3747: 0x000a, 0x3748: 0x000a, 0x3749: 0x000a, 0x374a: 0x000a, 0x374b: 0x000a,
0x374c: 0x000a, 0x374d: 0x000a, 0x374e: 0x000a, 0x374f: 0x000a, 0x3750: 0x000a,
0x3760: 0x000a, 0x3761: 0x000a, 0x3762: 0x000a, 0x3763: 0x000a,
0x3764: 0x000a, 0x3765: 0x000a, 0x3766: 0x000a, 0x3767: 0x000a, 0x3768: 0x000a, 0x3769: 0x000a,
0x376a: 0x000a, 0x376b: 0x000a, 0x376c: 0x000a, 0x376d: 0x000a, 0x376e: 0x000a, 0x376f: 0x000a,
0x3770: 0x000a,
// Block 0xde, offset 0x3780
0x3780: 0x000c, 0x3781: 0x000c, 0x3782: 0x000c, 0x3783: 0x000c, 0x3784: 0x000c, 0x3785: 0x000c,
0x3786: 0x000c, 0x3787: 0x000c, 0x3788: 0x000c, 0x3789: 0x000c, 0x378a: 0x000c, 0x378b: 0x000c,
0x378c: 0x000c, 0x378d: 0x000c, 0x378e: 0x000c, 0x378f: 0x000c, 0x3790: 0x000c, 0x3791: 0x000c,
0x3792: 0x000c, 0x3793: 0x000c, 0x3794: 0x000c, 0x3795: 0x000c, 0x3796: 0x000c, 0x3797: 0x000c,
0x3798: 0x000c, 0x3799: 0x000c, 0x379a: 0x000c, 0x379b: 0x000c, 0x379c: 0x000c, 0x379d: 0x000c,
0x379e: 0x000c, 0x379f: 0x000c, 0x37a0: 0x000c, 0x37a1: 0x000c, 0x37a2: 0x000c, 0x37a3: 0x000c,
0x37a4: 0x000c, 0x37a5: 0x000c, 0x37a6: 0x000c, 0x37a7: 0x000c, 0x37a8: 0x000c, 0x37a9: 0x000c,
0x37aa: 0x000c, 0x37ab: 0x000c, 0x37ac: 0x000c, 0x37ad: 0x000c,
0x37b0: 0x000c, 0x37b1: 0x000c, 0x37b2: 0x000c, 0x37b3: 0x000c, 0x37b4: 0x000c, 0x37b5: 0x000c,
0x37b6: 0x000c, 0x37b7: 0x000c, 0x37b8: 0x000c, 0x37b9: 0x000c, 0x37ba: 0x000c, 0x37bb: 0x000c,
0x37bc: 0x000c, 0x37bd: 0x000c, 0x37be: 0x000c, 0x37bf: 0x000c,
// Block 0xdf, offset 0x37c0
0x37c0: 0x000c, 0x37c1: 0x000c, 0x37c2: 0x000c, 0x37c3: 0x000c, 0x37c4: 0x000c, 0x37c5: 0x000c,
0x37c6: 0x000c,
// Block 0xe0, offset 0x3800
0x3827: 0x000c, 0x3828: 0x000c, 0x3829: 0x000c,
0x3833: 0x000b, 0x3834: 0x000b, 0x3835: 0x000b,
0x3836: 0x000b, 0x3837: 0x000b, 0x3838: 0x000b, 0x3839: 0x000b, 0x383a: 0x000b, 0x383b: 0x000c,
0x383c: 0x000c, 0x383d: 0x000c, 0x383e: 0x000c, 0x383f: 0x000c,
// Block 0xe1, offset 0x3840
0x3840: 0x000c, 0x3841: 0x000c, 0x3842: 0x000c, 0x3845: 0x000c,
0x3846: 0x000c, 0x3847: 0x000c, 0x3848: 0x000c, 0x3849: 0x000c, 0x384a: 0x000c, 0x384b: 0x000c,
0x386a: 0x000c, 0x386b: 0x000c, 0x386c: 0x000c, 0x386d: 0x000c,
// Block 0xe2, offset 0x3880
0x38a9: 0x000a,
0x38aa: 0x000a,
// Block 0xe3, offset 0x38c0
0x38c0: 0x000a, 0x38c1: 0x000a, 0x38c2: 0x000c, 0x38c3: 0x000c, 0x38c4: 0x000c, 0x38c5: 0x000a,
// Block 0xe4, offset 0x3900
0x3900: 0x000a, 0x3901: 0x000a, 0x3902: 0x000a, 0x3903: 0x000a, 0x3904: 0x000a, 0x3905: 0x000a,
0x3906: 0x000a, 0x3907: 0x000a, 0x3908: 0x000a, 0x3909: 0x000a, 0x390a: 0x000a, 0x390b: 0x000a,
0x390c: 0x000a, 0x390d: 0x000a, 0x390e: 0x000a, 0x390f: 0x000a, 0x3910: 0x000a, 0x3911: 0x000a,
0x3912: 0x000a, 0x3913: 0x000a, 0x3914: 0x000a, 0x3915: 0x000a, 0x3916: 0x000a,
// Block 0xe5, offset 0x3940
0x3941: 0x000a,
0x395b: 0x000a,
0x397b: 0x000a,
// Block 0xe6, offset 0x3980
0x3995: 0x000a,
0x39b5: 0x000a,
// Block 0xe7, offset 0x39c0
0x39cf: 0x000a,
0x39ef: 0x000a,
// Block 0xe8, offset 0x3a00
0x3a09: 0x000a,
0x3a29: 0x000a,
// Block 0xe9, offset 0x3a40
0x3a43: 0x000a,
0x3a4e: 0x0002, 0x3a4f: 0x0002, 0x3a50: 0x0002, 0x3a51: 0x0002,
0x3a52: 0x0002, 0x3a53: 0x0002, 0x3a54: 0x0002, 0x3a55: 0x0002, 0x3a56: 0x0002, 0x3a57: 0x0002,
0x3a58: 0x0002, 0x3a59: 0x0002, 0x3a5a: 0x0002, 0x3a5b: 0x0002, 0x3a5c: 0x0002, 0x3a5d: 0x0002,
0x3a5e: 0x0002, 0x3a5f: 0x0002, 0x3a60: 0x0002, 0x3a61: 0x0002, 0x3a62: 0x0002, 0x3a63: 0x0002,
0x3a64: 0x0002, 0x3a65: 0x0002, 0x3a66: 0x0002, 0x3a67: 0x0002, 0x3a68: 0x0002, 0x3a69: 0x0002,
0x3a6a: 0x0002, 0x3a6b: 0x0002, 0x3a6c: 0x0002, 0x3a6d: 0x0002, 0x3a6e: 0x0002, 0x3a6f: 0x0002,
0x3a70: 0x0002, 0x3a71: 0x0002, 0x3a72: 0x0002, 0x3a73: 0x0002, 0x3a74: 0x0002, 0x3a75: 0x0002,
0x3a76: 0x0002, 0x3a77: 0x0002, 0x3a78: 0x0002, 0x3a79: 0x0002, 0x3a7a: 0x0002, 0x3a7b: 0x0002,
0x3a7c: 0x0002, 0x3a7d: 0x0002, 0x3a7e: 0x0002, 0x3a7f: 0x0002,
// Block 0xea, offset 0x3a80
0x3a80: 0x000c, 0x3a81: 0x000c, 0x3a82: 0x000c, 0x3a83: 0x000c, 0x3a84: 0x000c, 0x3a85: 0x000c,
0x3a86: 0x000c, 0x3a87: 0x000c, 0x3a88: 0x000c, 0x3a89: 0x000c, 0x3a8a: 0x000c, 0x3a8b: 0x000c,
0x3a8c: 0x000c, 0x3a8d: 0x000c, 0x3a8e: 0x000c, 0x3a8f: 0x000c, 0x3a90: 0x000c, 0x3a91: 0x000c,
0x3a92: 0x000c, 0x3a93: 0x000c, 0x3a94: 0x000c, 0x3a95: 0x000c, 0x3a96: 0x000c, 0x3a97: 0x000c,
0x3a98: 0x000c, 0x3a99: 0x000c, 0x3a9a: 0x000c, 0x3a9b: 0x000c, 0x3a9c: 0x000c, 0x3a9d: 0x000c,
0x3a9e: 0x000c, 0x3a9f: 0x000c, 0x3aa0: 0x000c, 0x3aa1: 0x000c, 0x3aa2: 0x000c, 0x3aa3: 0x000c,
0x3aa4: 0x000c, 0x3aa5: 0x000c, 0x3aa6: 0x000c, 0x3aa7: 0x000c, 0x3aa8: 0x000c, 0x3aa9: 0x000c,
0x3aaa: 0x000c, 0x3aab: 0x000c, 0x3aac: 0x000c, 0x3aad: 0x000c, 0x3aae: 0x000c, 0x3aaf: 0x000c,
0x3ab0: 0x000c, 0x3ab1: 0x000c, 0x3ab2: 0x000c, 0x3ab3: 0x000c, 0x3ab4: 0x000c, 0x3ab5: 0x000c,
0x3ab6: 0x000c, 0x3abb: 0x000c,
0x3abc: 0x000c, 0x3abd: 0x000c, 0x3abe: 0x000c, 0x3abf: 0x000c,
// Block 0xeb, offset 0x3ac0
0x3ac0: 0x000c, 0x3ac1: 0x000c, 0x3ac2: 0x000c, 0x3ac3: 0x000c, 0x3ac4: 0x000c, 0x3ac5: 0x000c,
0x3ac6: 0x000c, 0x3ac7: 0x000c, 0x3ac8: 0x000c, 0x3ac9: 0x000c, 0x3aca: 0x000c, 0x3acb: 0x000c,
0x3acc: 0x000c, 0x3acd: 0x000c, 0x3ace: 0x000c, 0x3acf: 0x000c, 0x3ad0: 0x000c, 0x3ad1: 0x000c,
0x3ad2: 0x000c, 0x3ad3: 0x000c, 0x3ad4: 0x000c, 0x3ad5: 0x000c, 0x3ad6: 0x000c, 0x3ad7: 0x000c,
0x3ad8: 0x000c, 0x3ad9: 0x000c, 0x3ada: 0x000c, 0x3adb: 0x000c, 0x3adc: 0x000c, 0x3add: 0x000c,
0x3ade: 0x000c, 0x3adf: 0x000c, 0x3ae0: 0x000c, 0x3ae1: 0x000c, 0x3ae2: 0x000c, 0x3ae3: 0x000c,
0x3ae4: 0x000c, 0x3ae5: 0x000c, 0x3ae6: 0x000c, 0x3ae7: 0x000c, 0x3ae8: 0x000c, 0x3ae9: 0x000c,
0x3aea: 0x000c, 0x3aeb: 0x000c, 0x3aec: 0x000c,
0x3af5: 0x000c,
// Block 0xec, offset 0x3b00
0x3b04: 0x000c,
0x3b1b: 0x000c, 0x3b1c: 0x000c, 0x3b1d: 0x000c,
0x3b1e: 0x000c, 0x3b1f: 0x000c, 0x3b21: 0x000c, 0x3b22: 0x000c, 0x3b23: 0x000c,
0x3b24: 0x000c, 0x3b25: 0x000c, 0x3b26: 0x000c, 0x3b27: 0x000c, 0x3b28: 0x000c, 0x3b29: 0x000c,
0x3b2a: 0x000c, 0x3b2b: 0x000c, 0x3b2c: 0x000c, 0x3b2d: 0x000c, 0x3b2e: 0x000c, 0x3b2f: 0x000c,
// Block 0xed, offset 0x3b40
0x3b40: 0x000c, 0x3b41: 0x000c, 0x3b42: 0x000c, 0x3b43: 0x000c, 0x3b44: 0x000c, 0x3b45: 0x000c,
0x3b46: 0x000c, 0x3b48: 0x000c, 0x3b49: 0x000c, 0x3b4a: 0x000c, 0x3b4b: 0x000c,
0x3b4c: 0x000c, 0x3b4d: 0x000c, 0x3b4e: 0x000c, 0x3b4f: 0x000c, 0x3b50: 0x000c, 0x3b51: 0x000c,
0x3b52: 0x000c, 0x3b53: 0x000c, 0x3b54: 0x000c, 0x3b55: 0x000c, 0x3b56: 0x000c, 0x3b57: 0x000c,
0x3b58: 0x000c, 0x3b5b: 0x000c, 0x3b5c: 0x000c, 0x3b5d: 0x000c,
0x3b5e: 0x000c, 0x3b5f: 0x000c, 0x3b60: 0x000c, 0x3b61: 0x000c, 0x3b63: 0x000c,
0x3b64: 0x000c, 0x3b66: 0x000c, 0x3b67: 0x000c, 0x3b68: 0x000c, 0x3b69: 0x000c,
0x3b6a: 0x000c,
// Block 0xee, offset 0x3b80
0x3bae: 0x000c,
// Block 0xef, offset 0x3bc0
0x3bec: 0x000c, 0x3bed: 0x000c, 0x3bee: 0x000c, 0x3bef: 0x000c,
0x3bff: 0x0004,
// Block 0xf0, offset 0x3c00
0x3c2c: 0x000c, 0x3c2d: 0x000c, 0x3c2e: 0x000c, 0x3c2f: 0x000c,
// Block 0xf1, offset 0x3c40
0x3c6e: 0x000c, 0x3c6f: 0x000c,
// Block 0xf2, offset 0x3c80
0x3ca3: 0x000c,
0x3ca6: 0x000c,
0x3cae: 0x000c, 0x3caf: 0x000c,
0x3cb5: 0x000c,
// Block 0xf3, offset 0x3cc0
0x3cc0: 0x0001, 0x3cc1: 0x0001, 0x3cc2: 0x0001, 0x3cc3: 0x0001, 0x3cc4: 0x0001, 0x3cc5: 0x0001,
0x3cc6: 0x0001, 0x3cc7: 0x0001, 0x3cc8: 0x0001, 0x3cc9: 0x0001, 0x3cca: 0x0001, 0x3ccb: 0x0001,
0x3ccc: 0x0001, 0x3ccd: 0x0001, 0x3cce: 0x0001, 0x3ccf: 0x0001, 0x3cd0: 0x000c, 0x3cd1: 0x000c,
0x3cd2: 0x000c, 0x3cd3: 0x000c, 0x3cd4: 0x000c, 0x3cd5: 0x000c, 0x3cd6: 0x000c, 0x3cd7: 0x0001,
0x3cd8: 0x0001, 0x3cd9: 0x0001, 0x3cda: 0x0001, 0x3cdb: 0x0001, 0x3cdc: 0x0001, 0x3cdd: 0x0001,
0x3cde: 0x0001, 0x3cdf: 0x0001, 0x3ce0: 0x0001, 0x3ce1: 0x0001, 0x3ce2: 0x0001, 0x3ce3: 0x0001,
0x3ce4: 0x0001, 0x3ce5: 0x0001, 0x3ce6: 0x0001, 0x3ce7: 0x0001, 0x3ce8: 0x0001, 0x3ce9: 0x0001,
0x3cea: 0x0001, 0x3ceb: 0x0001, 0x3cec: 0x0001, 0x3ced: 0x0001, 0x3cee: 0x0001, 0x3cef: 0x0001,
0x3cf0: 0x0001, 0x3cf1: 0x0001, 0x3cf2: 0x0001, 0x3cf3: 0x0001, 0x3cf4: 0x0001, 0x3cf5: 0x0001,
0x3cf6: 0x0001, 0x3cf7: 0x0001, 0x3cf8: 0x0001, 0x3cf9: 0x0001, 0x3cfa: 0x0001, 0x3cfb: 0x0001,
0x3cfc: 0x0001, 0x3cfd: 0x0001, 0x3cfe: 0x0001, 0x3cff: 0x0001,
// Block 0xf4, offset 0x3d00
0x3d00: 0x0001, 0x3d01: 0x0001, 0x3d02: 0x0001, 0x3d03: 0x0001, 0x3d04: 0x000c, 0x3d05: 0x000c,
0x3d06: 0x000c, 0x3d07: 0x000c, 0x3d08: 0x000c, 0x3d09: 0x000c, 0x3d0a: 0x000c, 0x3d0b: 0x0001,
0x3d0c: 0x0001, 0x3d0d: 0x0001, 0x3d0e: 0x0001, 0x3d0f: 0x0001, 0x3d10: 0x0001, 0x3d11: 0x0001,
0x3d12: 0x0001, 0x3d13: 0x0001, 0x3d14: 0x0001, 0x3d15: 0x0001, 0x3d16: 0x0001, 0x3d17: 0x0001,
0x3d18: 0x0001, 0x3d19: 0x0001, 0x3d1a: 0x0001, 0x3d1b: 0x0001, 0x3d1c: 0x0001, 0x3d1d: 0x0001,
0x3d1e: 0x0001, 0x3d1f: 0x0001, 0x3d20: 0x0001, 0x3d21: 0x0001, 0x3d22: 0x0001, 0x3d23: 0x0001,
0x3d24: 0x0001, 0x3d25: 0x0001, 0x3d26: 0x0001, 0x3d27: 0x0001, 0x3d28: 0x0001, 0x3d29: 0x0001,
0x3d2a: 0x0001, 0x3d2b: 0x0001, 0x3d2c: 0x0001, 0x3d2d: 0x0001, 0x3d2e: 0x0001, 0x3d2f: 0x0001,
0x3d30: 0x0001, 0x3d31: 0x0001, 0x3d32: 0x0001, 0x3d33: 0x0001, 0x3d34: 0x0001, 0x3d35: 0x0001,
0x3d36: 0x0001, 0x3d37: 0x0001, 0x3d38: 0x0001, 0x3d39: 0x0001, 0x3d3a: 0x0001, 0x3d3b: 0x0001,
0x3d3c: 0x0001, 0x3d3d: 0x0001, 0x3d3e: 0x0001, 0x3d3f: 0x0001,
// Block 0xf5, offset 0x3d40
0x3d40: 0x0001, 0x3d41: 0x0001, 0x3d42: 0x0001, 0x3d43: 0x0001, 0x3d44: 0x0001, 0x3d45: 0x0001,
0x3d46: 0x0001, 0x3d47: 0x0001, 0x3d48: 0x0001, 0x3d49: 0x0001, 0x3d4a: 0x0001, 0x3d4b: 0x0001,
0x3d4c: 0x0001, 0x3d4d: 0x0001, 0x3d4e: 0x0001, 0x3d4f: 0x0001, 0x3d50: 0x0001, 0x3d51: 0x0001,
0x3d52: 0x0001, 0x3d53: 0x0001, 0x3d54: 0x0001, 0x3d55: 0x0001, 0x3d56: 0x0001, 0x3d57: 0x0001,
0x3d58: 0x0001, 0x3d59: 0x0001, 0x3d5a: 0x0001, 0x3d5b: 0x0001, 0x3d5c: 0x0001, 0x3d5d: 0x0001,
0x3d5e: 0x0001, 0x3d5f: 0x0001, 0x3d60: 0x0001, 0x3d61: 0x0001, 0x3d62: 0x0001, 0x3d63: 0x0001,
0x3d64: 0x0001, 0x3d65: 0x0001, 0x3d66: 0x0001, 0x3d67: 0x0001, 0x3d68: 0x0001, 0x3d69: 0x0001,
0x3d6a: 0x0001, 0x3d6b: 0x0001, 0x3d6c: 0x0001, 0x3d6d: 0x0001, 0x3d6e: 0x0001, 0x3d6f: 0x0001,
0x3d70: 0x0001, 0x3d71: 0x000d, 0x3d72: 0x000d, 0x3d73: 0x000d, 0x3d74: 0x000d, 0x3d75: 0x000d,
0x3d76: 0x000d, 0x3d77: 0x000d, 0x3d78: 0x000d, 0x3d79: 0x000d, 0x3d7a: 0x000d, 0x3d7b: 0x000d,
0x3d7c: 0x000d, 0x3d7d: 0x000d, 0x3d7e: 0x000d, 0x3d7f: 0x000d,
// Block 0xf6, offset 0x3d80
0x3d80: 0x000d, 0x3d81: 0x000d, 0x3d82: 0x000d, 0x3d83: 0x000d, 0x3d84: 0x000d, 0x3d85: 0x000d,
0x3d86: 0x000d, 0x3d87: 0x000d, 0x3d88: 0x000d, 0x3d89: 0x000d, 0x3d8a: 0x000d, 0x3d8b: 0x000d,
0x3d8c: 0x000d, 0x3d8d: 0x000d, 0x3d8e: 0x000d, 0x3d8f: 0x000d, 0x3d90: 0x000d, 0x3d91: 0x000d,
0x3d92: 0x000d, 0x3d93: 0x000d, 0x3d94: 0x000d, 0x3d95: 0x000d, 0x3d96: 0x000d, 0x3d97: 0x000d,
0x3d98: 0x000d, 0x3d99: 0x000d, 0x3d9a: 0x000d, 0x3d9b: 0x000d, 0x3d9c: 0x000d, 0x3d9d: 0x000d,
0x3d9e: 0x000d, 0x3d9f: 0x000d, 0x3da0: 0x000d, 0x3da1: 0x000d, 0x3da2: 0x000d, 0x3da3: 0x000d,
0x3da4: 0x000d, 0x3da5: 0x000d, 0x3da6: 0x000d, 0x3da7: 0x000d, 0x3da8: 0x000d, 0x3da9: 0x000d,
0x3daa: 0x000d, 0x3dab: 0x000d, 0x3dac: 0x000d, 0x3dad: 0x000d, 0x3dae: 0x000d, 0x3daf: 0x000d,
0x3db0: 0x000d, 0x3db1: 0x000d, 0x3db2: 0x000d, 0x3db3: 0x000d, 0x3db4: 0x000d, 0x3db5: 0x0001,
0x3db6: 0x0001, 0x3db7: 0x0001, 0x3db8: 0x0001, 0x3db9: 0x0001, 0x3dba: 0x0001, 0x3dbb: 0x0001,
0x3dbc: 0x0001, 0x3dbd: 0x0001, 0x3dbe: 0x0001, 0x3dbf: 0x0001,
// Block 0xf7, offset 0x3dc0
0x3dc0: 0x0001, 0x3dc1: 0x000d, 0x3dc2: 0x000d, 0x3dc3: 0x000d, 0x3dc4: 0x000d, 0x3dc5: 0x000d,
0x3dc6: 0x000d, 0x3dc7: 0x000d, 0x3dc8: 0x000d, 0x3dc9: 0x000d, 0x3dca: 0x000d, 0x3dcb: 0x000d,
0x3dcc: 0x000d, 0x3dcd: 0x000d, 0x3dce: 0x000d, 0x3dcf: 0x000d, 0x3dd0: 0x000d, 0x3dd1: 0x000d,
0x3dd2: 0x000d, 0x3dd3: 0x000d, 0x3dd4: 0x000d, 0x3dd5: 0x000d, 0x3dd6: 0x000d, 0x3dd7: 0x000d,
0x3dd8: 0x000d, 0x3dd9: 0x000d, 0x3dda: 0x000d, 0x3ddb: 0x000d, 0x3ddc: 0x000d, 0x3ddd: 0x000d,
0x3dde: 0x000d, 0x3ddf: 0x000d, 0x3de0: 0x000d, 0x3de1: 0x000d, 0x3de2: 0x000d, 0x3de3: 0x000d,
0x3de4: 0x000d, 0x3de5: 0x000d, 0x3de6: 0x000d, 0x3de7: 0x000d, 0x3de8: 0x000d, 0x3de9: 0x000d,
0x3dea: 0x000d, 0x3deb: 0x000d, 0x3dec: 0x000d, 0x3ded: 0x000d, 0x3dee: 0x000d, 0x3def: 0x000d,
0x3df0: 0x000d, 0x3df1: 0x000d, 0x3df2: 0x000d, 0x3df3: 0x000d, 0x3df4: 0x000d, 0x3df5: 0x000d,
0x3df6: 0x000d, 0x3df7: 0x000d, 0x3df8: 0x000d, 0x3df9: 0x000d, 0x3dfa: 0x000d, 0x3dfb: 0x000d,
0x3dfc: 0x000d, 0x3dfd: 0x000d, 0x3dfe: 0x0001, 0x3dff: 0x0001,
// Block 0xf8, offset 0x3e00
0x3e00: 0x000d, 0x3e01: 0x000d, 0x3e02: 0x000d, 0x3e03: 0x000d, 0x3e04: 0x000d, 0x3e05: 0x000d,
0x3e06: 0x000d, 0x3e07: 0x000d, 0x3e08: 0x000d, 0x3e09: 0x000d, 0x3e0a: 0x000d, 0x3e0b: 0x000d,
0x3e0c: 0x000d, 0x3e0d: 0x000d, 0x3e0e: 0x000d, 0x3e0f: 0x000d, 0x3e10: 0x000d, 0x3e11: 0x000d,
0x3e12: 0x000d, 0x3e13: 0x000d, 0x3e14: 0x000d, 0x3e15: 0x000d, 0x3e16: 0x000d, 0x3e17: 0x000d,
0x3e18: 0x000d, 0x3e19: 0x000d, 0x3e1a: 0x000d, 0x3e1b: 0x000d, 0x3e1c: 0x000d, 0x3e1d: 0x000d,
0x3e1e: 0x000d, 0x3e1f: 0x000d, 0x3e20: 0x000d, 0x3e21: 0x000d, 0x3e22: 0x000d, 0x3e23: 0x000d,
0x3e24: 0x000d, 0x3e25: 0x000d, 0x3e26: 0x000d, 0x3e27: 0x000d, 0x3e28: 0x000d, 0x3e29: 0x000d,
0x3e2a: 0x000d, 0x3e2b: 0x000d, 0x3e2c: 0x000d, 0x3e2d: 0x000d, 0x3e2e: 0x000d, 0x3e2f: 0x000d,
0x3e30: 0x000a, 0x3e31: 0x000a, 0x3e32: 0x000d, 0x3e33: 0x000d, 0x3e34: 0x000d, 0x3e35: 0x000d,
0x3e36: 0x000d, 0x3e37: 0x000d, 0x3e38: 0x000d, 0x3e39: 0x000d, 0x3e3a: 0x000d, 0x3e3b: 0x000d,
0x3e3c: 0x000d, 0x3e3d: 0x000d, 0x3e3e: 0x000d, 0x3e3f: 0x000d,
// Block 0xf9, offset 0x3e40
0x3e40: 0x000a, 0x3e41: 0x000a, 0x3e42: 0x000a, 0x3e43: 0x000a, 0x3e44: 0x000a, 0x3e45: 0x000a,
0x3e46: 0x000a, 0x3e47: 0x000a, 0x3e48: 0x000a, 0x3e49: 0x000a, 0x3e4a: 0x000a, 0x3e4b: 0x000a,
0x3e4c: 0x000a, 0x3e4d: 0x000a, 0x3e4e: 0x000a, 0x3e4f: 0x000a, 0x3e50: 0x000a, 0x3e51: 0x000a,
0x3e52: 0x000a, 0x3e53: 0x000a, 0x3e54: 0x000a, 0x3e55: 0x000a, 0x3e56: 0x000a, 0x3e57: 0x000a,
0x3e58: 0x000a, 0x3e59: 0x000a, 0x3e5a: 0x000a, 0x3e5b: 0x000a, 0x3e5c: 0x000a, 0x3e5d: 0x000a,
0x3e5e: 0x000a, 0x3e5f: 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,
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, 0x3e88: 0x000a, 0x3e89: 0x000a, 0x3e8a: 0x000a, 0x3e8b: 0x000a,
0x3e8c: 0x000a, 0x3e8d: 0x000a, 0x3e8e: 0x000a, 0x3e8f: 0x000a, 0x3e90: 0x000a, 0x3e91: 0x000a,
0x3e92: 0x000a, 0x3e93: 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, 0x3eae: 0x000a,
0x3eb1: 0x000a, 0x3eb2: 0x000a, 0x3eb3: 0x000a, 0x3eb4: 0x000a, 0x3eb5: 0x000a,
0x3eb6: 0x000a, 0x3eb7: 0x000a, 0x3eb8: 0x000a, 0x3eb9: 0x000a, 0x3eba: 0x000a, 0x3ebb: 0x000a,
0x3ebc: 0x000a, 0x3ebd: 0x000a, 0x3ebe: 0x000a, 0x3ebf: 0x000a,
// Block 0xfb, offset 0x3ec0
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, 0x3ed1: 0x000a,
0x3ed2: 0x000a, 0x3ed3: 0x000a, 0x3ed4: 0x000a, 0x3ed5: 0x000a, 0x3ed6: 0x000a, 0x3ed7: 0x000a,
0x3ed8: 0x000a, 0x3ed9: 0x000a, 0x3eda: 0x000a, 0x3edb: 0x000a, 0x3edc: 0x000a, 0x3edd: 0x000a,
0x3ede: 0x000a, 0x3edf: 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, 0x3eee: 0x000a, 0x3eef: 0x000a,
0x3ef0: 0x000a, 0x3ef1: 0x000a, 0x3ef2: 0x000a, 0x3ef3: 0x000a, 0x3ef4: 0x000a, 0x3ef5: 0x000a,
// Block 0xfc, offset 0x3f00
0x3f00: 0x0002, 0x3f01: 0x0002, 0x3f02: 0x0002, 0x3f03: 0x0002, 0x3f04: 0x0002, 0x3f05: 0x0002,
0x3f06: 0x0002, 0x3f07: 0x0002, 0x3f08: 0x0002, 0x3f09: 0x0002, 0x3f0a: 0x0002, 0x3f0b: 0x000a,
0x3f0c: 0x000a, 0x3f0d: 0x000a, 0x3f0e: 0x000a, 0x3f0f: 0x000a,
0x3f2f: 0x000a,
// Block 0xfd, offset 0x3f40
0x3f6a: 0x000a, 0x3f6b: 0x000a, 0x3f6c: 0x000a, 0x3f6d: 0x000a, 0x3f6e: 0x000a, 0x3f6f: 0x000a,
// Block 0xfe, offset 0x3f80
0x3fad: 0x000a,
// Block 0xff, offset 0x3fc0
0x3fe0: 0x000a, 0x3fe1: 0x000a, 0x3fe2: 0x000a, 0x3fe3: 0x000a,
0x3fe4: 0x000a, 0x3fe5: 0x000a,
// Block 0x100, offset 0x4000
0x4000: 0x000a, 0x4001: 0x000a, 0x4002: 0x000a, 0x4003: 0x000a, 0x4004: 0x000a, 0x4005: 0x000a,
0x4006: 0x000a, 0x4007: 0x000a, 0x4008: 0x000a, 0x4009: 0x000a, 0x400a: 0x000a, 0x400b: 0x000a,
0x400c: 0x000a, 0x400d: 0x000a, 0x400e: 0x000a, 0x400f: 0x000a, 0x4010: 0x000a, 0x4011: 0x000a,
0x4012: 0x000a, 0x4013: 0x000a, 0x4014: 0x000a, 0x4015: 0x000a, 0x4016: 0x000a, 0x4017: 0x000a,
0x4018: 0x000a, 0x401c: 0x000a, 0x401d: 0x000a,
0x401e: 0x000a, 0x401f: 0x000a, 0x4020: 0x000a, 0x4021: 0x000a, 0x4022: 0x000a, 0x4023: 0x000a,
0x4024: 0x000a, 0x4025: 0x000a, 0x4026: 0x000a, 0x4027: 0x000a, 0x4028: 0x000a, 0x4029: 0x000a,
0x402a: 0x000a, 0x402b: 0x000a, 0x402c: 0x000a,
0x4030: 0x000a, 0x4031: 0x000a, 0x4032: 0x000a, 0x4033: 0x000a, 0x4034: 0x000a, 0x4035: 0x000a,
0x4036: 0x000a, 0x4037: 0x000a, 0x4038: 0x000a, 0x4039: 0x000a, 0x403a: 0x000a, 0x403b: 0x000a,
0x403c: 0x000a,
// Block 0x101, offset 0x4040
0x4040: 0x000a, 0x4041: 0x000a, 0x4042: 0x000a, 0x4043: 0x000a, 0x4044: 0x000a, 0x4045: 0x000a,
0x4046: 0x000a, 0x4047: 0x000a, 0x4048: 0x000a, 0x4049: 0x000a, 0x404a: 0x000a, 0x404b: 0x000a,
0x404c: 0x000a, 0x404d: 0x000a, 0x404e: 0x000a, 0x404f: 0x000a, 0x4050: 0x000a, 0x4051: 0x000a,
0x4052: 0x000a, 0x4053: 0x000a, 0x4054: 0x000a, 0x4055: 0x000a, 0x4056: 0x000a, 0x4057: 0x000a,
0x4058: 0x000a, 0x4059: 0x000a,
0x4060: 0x000a, 0x4061: 0x000a, 0x4062: 0x000a, 0x4063: 0x000a,
0x4064: 0x000a, 0x4065: 0x000a, 0x4066: 0x000a, 0x4067: 0x000a, 0x4068: 0x000a, 0x4069: 0x000a,
0x406a: 0x000a, 0x406b: 0x000a,
0x4070: 0x000a,
// Block 0x102, offset 0x4080
0x4080: 0x000a, 0x4081: 0x000a, 0x4082: 0x000a, 0x4083: 0x000a, 0x4084: 0x000a, 0x4085: 0x000a,
0x4086: 0x000a, 0x4087: 0x000a, 0x4088: 0x000a, 0x4089: 0x000a, 0x408a: 0x000a, 0x408b: 0x000a,
0x4090: 0x000a, 0x4091: 0x000a,
0x4092: 0x000a, 0x4093: 0x000a, 0x4094: 0x000a, 0x4095: 0x000a, 0x4096: 0x000a, 0x4097: 0x000a,
0x4098: 0x000a, 0x4099: 0x000a, 0x409a: 0x000a, 0x409b: 0x000a, 0x409c: 0x000a, 0x409d: 0x000a,
0x409e: 0x000a, 0x409f: 0x000a, 0x40a0: 0x000a, 0x40a1: 0x000a, 0x40a2: 0x000a, 0x40a3: 0x000a,
0x40a4: 0x000a, 0x40a5: 0x000a, 0x40a6: 0x000a, 0x40a7: 0x000a, 0x40a8: 0x000a, 0x40a9: 0x000a,
0x40aa: 0x000a, 0x40ab: 0x000a, 0x40ac: 0x000a, 0x40ad: 0x000a, 0x40ae: 0x000a, 0x40af: 0x000a,
0x40b0: 0x000a, 0x40b1: 0x000a, 0x40b2: 0x000a, 0x40b3: 0x000a, 0x40b4: 0x000a, 0x40b5: 0x000a,
0x40b6: 0x000a, 0x40b7: 0x000a, 0x40b8: 0x000a, 0x40b9: 0x000a, 0x40ba: 0x000a, 0x40bb: 0x000a,
0x40bc: 0x000a, 0x40bd: 0x000a, 0x40be: 0x000a, 0x40bf: 0x000a,
// Block 0x103, offset 0x40c0
0x40c0: 0x000a, 0x40c1: 0x000a, 0x40c2: 0x000a, 0x40c3: 0x000a, 0x40c4: 0x000a, 0x40c5: 0x000a,
0x40c6: 0x000a, 0x40c7: 0x000a,
0x40d0: 0x000a, 0x40d1: 0x000a,
0x40d2: 0x000a, 0x40d3: 0x000a, 0x40d4: 0x000a, 0x40d5: 0x000a, 0x40d6: 0x000a, 0x40d7: 0x000a,
0x40d8: 0x000a, 0x40d9: 0x000a,
0x40e0: 0x000a, 0x40e1: 0x000a, 0x40e2: 0x000a, 0x40e3: 0x000a,
0x40e4: 0x000a, 0x40e5: 0x000a, 0x40e6: 0x000a, 0x40e7: 0x000a, 0x40e8: 0x000a, 0x40e9: 0x000a,
0x40ea: 0x000a, 0x40eb: 0x000a, 0x40ec: 0x000a, 0x40ed: 0x000a, 0x40ee: 0x000a, 0x40ef: 0x000a,
0x40f0: 0x000a, 0x40f1: 0x000a, 0x40f2: 0x000a, 0x40f3: 0x000a, 0x40f4: 0x000a, 0x40f5: 0x000a,
0x40f6: 0x000a, 0x40f7: 0x000a, 0x40f8: 0x000a, 0x40f9: 0x000a, 0x40fa: 0x000a, 0x40fb: 0x000a,
0x40fc: 0x000a, 0x40fd: 0x000a, 0x40fe: 0x000a, 0x40ff: 0x000a,
// Block 0x104, offset 0x4100
0x4100: 0x000a, 0x4101: 0x000a, 0x4102: 0x000a, 0x4103: 0x000a, 0x4104: 0x000a, 0x4105: 0x000a,
0x4106: 0x000a, 0x4107: 0x000a,
0x4110: 0x000a, 0x4111: 0x000a,
0x4112: 0x000a, 0x4113: 0x000a, 0x4114: 0x000a, 0x4115: 0x000a, 0x4116: 0x000a, 0x4117: 0x000a,
0x4118: 0x000a, 0x4119: 0x000a, 0x411a: 0x000a, 0x411b: 0x000a, 0x411c: 0x000a, 0x411d: 0x000a,
0x411e: 0x000a, 0x411f: 0x000a, 0x4120: 0x000a, 0x4121: 0x000a, 0x4122: 0x000a, 0x4123: 0x000a,
0x4124: 0x000a, 0x4125: 0x000a, 0x4126: 0x000a, 0x4127: 0x000a, 0x4128: 0x000a, 0x4129: 0x000a,
0x412a: 0x000a, 0x412b: 0x000a, 0x412c: 0x000a, 0x412d: 0x000a,
0x4130: 0x000a, 0x4131: 0x000a, 0x4132: 0x000a, 0x4133: 0x000a, 0x4134: 0x000a, 0x4135: 0x000a,
0x4136: 0x000a, 0x4137: 0x000a, 0x4138: 0x000a, 0x4139: 0x000a, 0x413a: 0x000a, 0x413b: 0x000a,
// Block 0x105, offset 0x4140
0x4140: 0x000a, 0x4141: 0x000a,
0x4150: 0x000a, 0x4151: 0x000a,
0x4152: 0x000a, 0x4153: 0x000a, 0x4154: 0x000a, 0x4155: 0x000a, 0x4156: 0x000a, 0x4157: 0x000a,
0x4158: 0x000a,
// Block 0x106, offset 0x4180
0x4180: 0x000a, 0x4181: 0x000a, 0x4182: 0x000a, 0x4183: 0x000a, 0x4184: 0x000a, 0x4185: 0x000a,
0x4186: 0x000a, 0x4187: 0x000a, 0x4188: 0x000a, 0x4189: 0x000a, 0x418a: 0x000a, 0x418b: 0x000a,
0x418c: 0x000a, 0x418d: 0x000a, 0x418e: 0x000a, 0x418f: 0x000a, 0x4190: 0x000a, 0x4191: 0x000a,
0x4192: 0x000a, 0x4193: 0x000a, 0x4194: 0x000a, 0x4195: 0x000a, 0x4196: 0x000a, 0x4197: 0x000a,
0x41a0: 0x000a, 0x41a1: 0x000a, 0x41a2: 0x000a, 0x41a3: 0x000a,
0x41a4: 0x000a, 0x41a5: 0x000a, 0x41a6: 0x000a, 0x41a7: 0x000a, 0x41a8: 0x000a, 0x41a9: 0x000a,
0x41aa: 0x000a, 0x41ab: 0x000a, 0x41ac: 0x000a, 0x41ad: 0x000a,
0x41b0: 0x000a, 0x41b1: 0x000a, 0x41b2: 0x000a, 0x41b3: 0x000a, 0x41b4: 0x000a, 0x41b5: 0x000a,
0x41b6: 0x000a, 0x41b7: 0x000a, 0x41b8: 0x000a, 0x41b9: 0x000a, 0x41ba: 0x000a, 0x41bb: 0x000a,
0x41bc: 0x000a,
// Block 0x107, offset 0x41c0
0x41c0: 0x000a, 0x41c1: 0x000a, 0x41c2: 0x000a, 0x41c3: 0x000a, 0x41c4: 0x000a, 0x41c5: 0x000a,
0x41c6: 0x000a, 0x41c7: 0x000a, 0x41c8: 0x000a, 0x41c9: 0x000a, 0x41ca: 0x000a,
0x41ce: 0x000a, 0x41cf: 0x000a, 0x41d0: 0x000a, 0x41d1: 0x000a,
0x41d2: 0x000a, 0x41d3: 0x000a, 0x41d4: 0x000a, 0x41d5: 0x000a, 0x41d6: 0x000a, 0x41d7: 0x000a,
0x41d8: 0x000a, 0x41d9: 0x000a, 0x41da: 0x000a, 0x41db: 0x000a, 0x41dc: 0x000a, 0x41dd: 0x000a,
0x41de: 0x000a, 0x41df: 0x000a, 0x41e0: 0x000a, 0x41e1: 0x000a, 0x41e2: 0x000a, 0x41e3: 0x000a,
0x41e4: 0x000a, 0x41e5: 0x000a, 0x41e6: 0x000a, 0x41e7: 0x000a, 0x41e8: 0x000a, 0x41e9: 0x000a,
0x41ea: 0x000a, 0x41eb: 0x000a, 0x41ec: 0x000a, 0x41ed: 0x000a, 0x41ee: 0x000a, 0x41ef: 0x000a,
0x41f0: 0x000a, 0x41f1: 0x000a, 0x41f2: 0x000a, 0x41f3: 0x000a, 0x41f4: 0x000a, 0x41f5: 0x000a,
0x41f6: 0x000a, 0x41f7: 0x000a, 0x41f8: 0x000a, 0x41f9: 0x000a, 0x41fa: 0x000a, 0x41fb: 0x000a,
0x41fc: 0x000a, 0x41fd: 0x000a, 0x41fe: 0x000a, 0x41ff: 0x000a,
// Block 0x108, offset 0x4200
0x4200: 0x000a, 0x4201: 0x000a, 0x4202: 0x000a, 0x4203: 0x000a, 0x4204: 0x000a, 0x4205: 0x000a,
0x4206: 0x000a, 0x4208: 0x000a,
0x420d: 0x000a, 0x420e: 0x000a, 0x420f: 0x000a, 0x4210: 0x000a, 0x4211: 0x000a,
0x4212: 0x000a, 0x4213: 0x000a, 0x4214: 0x000a, 0x4215: 0x000a, 0x4216: 0x000a, 0x4217: 0x000a,
0x4218: 0x000a, 0x4219: 0x000a, 0x421a: 0x000a, 0x421b: 0x000a, 0x421c: 0x000a,
0x421f: 0x000a, 0x4220: 0x000a, 0x4221: 0x000a, 0x4222: 0x000a, 0x4223: 0x000a,
0x4224: 0x000a, 0x4225: 0x000a, 0x4226: 0x000a, 0x4227: 0x000a, 0x4228: 0x000a, 0x4229: 0x000a,
0x422a: 0x000a, 0x422f: 0x000a,
0x4230: 0x000a, 0x4231: 0x000a, 0x4232: 0x000a, 0x4233: 0x000a, 0x4234: 0x000a, 0x4235: 0x000a,
0x4236: 0x000a, 0x4237: 0x000a, 0x4238: 0x000a,
// Block 0x109, offset 0x4240
0x4240: 0x000a, 0x4241: 0x000a, 0x4242: 0x000a, 0x4243: 0x000a, 0x4244: 0x000a, 0x4245: 0x000a,
0x4246: 0x000a, 0x4247: 0x000a, 0x4248: 0x000a, 0x4249: 0x000a, 0x424a: 0x000a, 0x424b: 0x000a,
0x424c: 0x000a, 0x424d: 0x000a, 0x424e: 0x000a, 0x424f: 0x000a, 0x4250: 0x000a, 0x4251: 0x000a,
0x4252: 0x000a, 0x4254: 0x000a, 0x4255: 0x000a, 0x4256: 0x000a, 0x4257: 0x000a,
0x4258: 0x000a, 0x4259: 0x000a, 0x425a: 0x000a, 0x425b: 0x000a, 0x425c: 0x000a, 0x425d: 0x000a,
0x425e: 0x000a, 0x425f: 0x000a, 0x4260: 0x000a, 0x4261: 0x000a, 0x4262: 0x000a, 0x4263: 0x000a,
0x4264: 0x000a, 0x4265: 0x000a, 0x4266: 0x000a, 0x4267: 0x000a, 0x4268: 0x000a, 0x4269: 0x000a,
0x426a: 0x000a, 0x426b: 0x000a, 0x426c: 0x000a, 0x426d: 0x000a, 0x426e: 0x000a, 0x426f: 0x000a,
0x4270: 0x000a, 0x4271: 0x000a, 0x4272: 0x000a, 0x4273: 0x000a, 0x4274: 0x000a, 0x4275: 0x000a,
0x4276: 0x000a, 0x4277: 0x000a, 0x4278: 0x000a, 0x4279: 0x000a, 0x427a: 0x000a, 0x427b: 0x000a,
0x427c: 0x000a, 0x427d: 0x000a, 0x427e: 0x000a, 0x427f: 0x000a,
// Block 0x10a, offset 0x4280
0x4280: 0x000a, 0x4281: 0x000a, 0x4282: 0x000a, 0x4283: 0x000a, 0x4284: 0x000a, 0x4285: 0x000a,
0x4286: 0x000a, 0x4287: 0x000a, 0x4288: 0x000a, 0x4289: 0x000a, 0x428a: 0x000a, 0x428b: 0x000a,
0x428c: 0x000a, 0x428d: 0x000a, 0x428e: 0x000a, 0x428f: 0x000a, 0x4290: 0x000a, 0x4291: 0x000a,
0x4292: 0x000a, 0x4293: 0x000a, 0x4294: 0x000a, 0x4295: 0x000a, 0x4296: 0x000a, 0x4297: 0x000a,
0x4298: 0x000a, 0x4299: 0x000a, 0x429a: 0x000a, 0x429b: 0x000a, 0x429c: 0x000a, 0x429d: 0x000a,
0x429e: 0x000a, 0x429f: 0x000a, 0x42a0: 0x000a, 0x42a1: 0x000a, 0x42a2: 0x000a, 0x42a3: 0x000a,
0x42a4: 0x000a, 0x42a5: 0x000a, 0x42a6: 0x000a, 0x42a7: 0x000a, 0x42a8: 0x000a, 0x42a9: 0x000a,
0x42aa: 0x000a, 0x42ab: 0x000a, 0x42ac: 0x000a, 0x42ad: 0x000a, 0x42ae: 0x000a, 0x42af: 0x000a,
0x42b0: 0x0002, 0x42b1: 0x0002, 0x42b2: 0x0002, 0x42b3: 0x0002, 0x42b4: 0x0002, 0x42b5: 0x0002,
0x42b6: 0x0002, 0x42b7: 0x0002, 0x42b8: 0x0002, 0x42b9: 0x0002, 0x42ba: 0x000a,
// Block 0x10b, offset 0x42c0
0x42fe: 0x000b, 0x42ff: 0x000b,
// Block 0x10c, offset 0x4300
0x4300: 0x000b, 0x4301: 0x000b, 0x4302: 0x000b, 0x4303: 0x000b, 0x4304: 0x000b, 0x4305: 0x000b,
0x4306: 0x000b, 0x4307: 0x000b, 0x4308: 0x000b, 0x4309: 0x000b, 0x430a: 0x000b, 0x430b: 0x000b,
0x430c: 0x000b, 0x430d: 0x000b, 0x430e: 0x000b, 0x430f: 0x000b, 0x4310: 0x000b, 0x4311: 0x000b,
0x4312: 0x000b, 0x4313: 0x000b, 0x4314: 0x000b, 0x4315: 0x000b, 0x4316: 0x000b, 0x4317: 0x000b,
0x4318: 0x000b, 0x4319: 0x000b, 0x431a: 0x000b, 0x431b: 0x000b, 0x431c: 0x000b, 0x431d: 0x000b,
0x431e: 0x000b, 0x431f: 0x000b, 0x4320: 0x000b, 0x4321: 0x000b, 0x4322: 0x000b, 0x4323: 0x000b,
0x4324: 0x000b, 0x4325: 0x000b, 0x4326: 0x000b, 0x4327: 0x000b, 0x4328: 0x000b, 0x4329: 0x000b,
0x432a: 0x000b, 0x432b: 0x000b, 0x432c: 0x000b, 0x432d: 0x000b, 0x432e: 0x000b, 0x432f: 0x000b,
0x4330: 0x000b, 0x4331: 0x000b, 0x4332: 0x000b, 0x4333: 0x000b, 0x4334: 0x000b, 0x4335: 0x000b,
0x4336: 0x000b, 0x4337: 0x000b, 0x4338: 0x000b, 0x4339: 0x000b, 0x433a: 0x000b, 0x433b: 0x000b,
0x433c: 0x000b, 0x433d: 0x000b, 0x433e: 0x000b, 0x433f: 0x000b,
// Block 0x10d, offset 0x4340
0x4340: 0x000c, 0x4341: 0x000c, 0x4342: 0x000c, 0x4343: 0x000c, 0x4344: 0x000c, 0x4345: 0x000c,
0x4346: 0x000c, 0x4347: 0x000c, 0x4348: 0x000c, 0x4349: 0x000c, 0x434a: 0x000c, 0x434b: 0x000c,
0x434c: 0x000c, 0x434d: 0x000c, 0x434e: 0x000c, 0x434f: 0x000c, 0x4350: 0x000c, 0x4351: 0x000c,
0x4352: 0x000c, 0x4353: 0x000c, 0x4354: 0x000c, 0x4355: 0x000c, 0x4356: 0x000c, 0x4357: 0x000c,
0x4358: 0x000c, 0x4359: 0x000c, 0x435a: 0x000c, 0x435b: 0x000c, 0x435c: 0x000c, 0x435d: 0x000c,
0x435e: 0x000c, 0x435f: 0x000c, 0x4360: 0x000c, 0x4361: 0x000c, 0x4362: 0x000c, 0x4363: 0x000c,
0x4364: 0x000c, 0x4365: 0x000c, 0x4366: 0x000c, 0x4367: 0x000c, 0x4368: 0x000c, 0x4369: 0x000c,
0x436a: 0x000c, 0x436b: 0x000c, 0x436c: 0x000c, 0x436d: 0x000c, 0x436e: 0x000c, 0x436f: 0x000c,
0x4370: 0x000b, 0x4371: 0x000b, 0x4372: 0x000b, 0x4373: 0x000b, 0x4374: 0x000b, 0x4375: 0x000b,
0x4376: 0x000b, 0x4377: 0x000b, 0x4378: 0x000b, 0x4379: 0x000b, 0x437a: 0x000b, 0x437b: 0x000b,
0x437c: 0x000b, 0x437d: 0x000b, 0x437e: 0x000b, 0x437f: 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: 0x55, 0x1af: 0x55,
0x1b3: 0x64, 0x1b5: 0x65, 0x1b7: 0x66,
0x1b8: 0x67, 0x1b9: 0x68, 0x1ba: 0x69, 0x1bb: 0x6a, 0x1bc: 0x55, 0x1bd: 0x55, 0x1be: 0x55, 0x1bf: 0x6b,
// Block 0x7, offset 0x1c0
0x1c0: 0x6c, 0x1c2: 0x6d, 0x1c3: 0x6e, 0x1c7: 0x6f,
0x1c8: 0x70, 0x1c9: 0x71, 0x1ca: 0x72, 0x1cb: 0x73, 0x1cd: 0x74, 0x1cf: 0x75,
// Block 0x8, offset 0x200
0x237: 0x55,
// Block 0x9, offset 0x240
0x252: 0x76, 0x253: 0x77,
0x258: 0x78, 0x259: 0x79, 0x25a: 0x7a, 0x25b: 0x7b, 0x25c: 0x7c, 0x25e: 0x7d,
0x260: 0x7e, 0x261: 0x7f, 0x263: 0x80, 0x264: 0x81, 0x265: 0x82, 0x266: 0x83, 0x267: 0x84,
0x268: 0x85, 0x269: 0x86, 0x26a: 0x87, 0x26b: 0x88, 0x26d: 0x89, 0x26f: 0x8a,
// Block 0xa, offset 0x280
0x2ac: 0x8b, 0x2ad: 0x8c, 0x2ae: 0x0e, 0x2af: 0x8d,
0x2b0: 0x0e, 0x2b1: 0x0e, 0x2b2: 0x0e, 0x2b3: 0x0e, 0x2b4: 0x8e, 0x2b5: 0x8f, 0x2b6: 0x90, 0x2b7: 0x91,
0x2b8: 0x92, 0x2b9: 0x93, 0x2ba: 0x0e, 0x2bb: 0x94, 0x2bc: 0x95, 0x2bd: 0x96, 0x2bf: 0x97,
// Block 0xb, offset 0x2c0
0x2c4: 0x98, 0x2c5: 0x55, 0x2c6: 0x99, 0x2c7: 0x9a,
0x2cb: 0x9b, 0x2cd: 0x9c,
0x2e0: 0x9d, 0x2e1: 0x9d, 0x2e2: 0x9d, 0x2e3: 0x9d, 0x2e4: 0x9e, 0x2e5: 0x9d, 0x2e6: 0x9d, 0x2e7: 0x9d,
0x2e8: 0x9f, 0x2e9: 0x9d, 0x2ea: 0x9d, 0x2eb: 0xa0, 0x2ec: 0xa1, 0x2ed: 0x9d, 0x2ee: 0x9d, 0x2ef: 0x9d,
0x2f0: 0x9d, 0x2f1: 0x9d, 0x2f2: 0x9d, 0x2f3: 0x9d, 0x2f4: 0xa2, 0x2f5: 0xa3, 0x2f6: 0x9d, 0x2f7: 0x9d,
0x2f8: 0x9d, 0x2f9: 0xa4, 0x2fa: 0xa5, 0x2fb: 0xa6, 0x2fc: 0xa7, 0x2fd: 0xa8, 0x2fe: 0xa9, 0x2ff: 0x9d,
// Block 0xc, offset 0x300
0x300: 0xaa, 0x301: 0xab, 0x302: 0xac, 0x303: 0x21, 0x304: 0xad, 0x305: 0xae, 0x306: 0xaf, 0x307: 0xb0,
0x308: 0xb1, 0x309: 0x28, 0x30b: 0xb2, 0x30c: 0x26, 0x30d: 0xb3, 0x30e: 0xb4, 0x30f: 0xb5,
0x310: 0xb6, 0x311: 0xb7, 0x312: 0xb8, 0x313: 0xb9, 0x316: 0xba, 0x317: 0xbb,
0x318: 0xbc, 0x319: 0xbd, 0x31a: 0xbe, 0x31c: 0xbf,
0x320: 0xc0, 0x324: 0xc1, 0x325: 0xc2, 0x327: 0xc3,
0x328: 0xc4, 0x329: 0xc5, 0x32a: 0xc6, 0x32d: 0xc7,
0x330: 0xc8, 0x332: 0xc9, 0x334: 0xca, 0x335: 0xcb, 0x336: 0xcc,
0x33b: 0xcd, 0x33c: 0xce, 0x33d: 0xcf, 0x33f: 0xd0,
// Block 0xd, offset 0x340
0x351: 0xd1,
// Block 0xe, offset 0x380
0x384: 0xd2,
0x3ab: 0xd3, 0x3ac: 0xd4,
0x3bd: 0xd5, 0x3be: 0xd6, 0x3bf: 0xd7,
// Block 0xf, offset 0x3c0
0x3f2: 0xd8,
// Block 0x10, offset 0x400
0x430: 0x55, 0x431: 0x55, 0x432: 0x55, 0x433: 0xd9, 0x434: 0x55, 0x435: 0x55, 0x436: 0x55, 0x437: 0x55,
0x438: 0x55, 0x439: 0x55, 0x43a: 0xda, 0x43b: 0xdb, 0x43c: 0xdc, 0x43d: 0xdd,
// Block 0x11, offset 0x440
0x445: 0xde, 0x446: 0xdf, 0x447: 0xe0,
0x448: 0x55, 0x449: 0xe1, 0x44c: 0x55, 0x44d: 0xe2,
0x45b: 0xe3, 0x45c: 0xe4, 0x45d: 0xe5, 0x45e: 0xe6, 0x45f: 0xe7,
0x468: 0xe8, 0x469: 0xe9, 0x46a: 0xea,
// Block 0x12, offset 0x480
0x480: 0xeb, 0x482: 0xd5, 0x484: 0xd4,
0x48a: 0xec, 0x48b: 0xed,
0x493: 0xee, 0x497: 0xef,
0x49b: 0xf0,
0x4a0: 0x9d, 0x4a1: 0x9d, 0x4a2: 0x9d, 0x4a3: 0xf1, 0x4a4: 0x9d, 0x4a5: 0xf2, 0x4a6: 0x9d, 0x4a7: 0x9d,
0x4a8: 0x9d, 0x4a9: 0x9d, 0x4aa: 0x9d, 0x4ab: 0x9d, 0x4ac: 0x9d, 0x4ad: 0x9d, 0x4ae: 0x9d, 0x4af: 0x9d,
0x4b0: 0x9d, 0x4b1: 0xf3, 0x4b2: 0xf4, 0x4b3: 0x9d, 0x4b4: 0xf5, 0x4b5: 0x9d, 0x4b6: 0x9d, 0x4b7: 0x9d,
0x4b8: 0x0e, 0x4b9: 0x0e, 0x4ba: 0x0e, 0x4bb: 0xf6, 0x4bc: 0x9d, 0x4bd: 0x9d, 0x4be: 0x9d, 0x4bf: 0x9d,
// Block 0x13, offset 0x4c0
0x4c0: 0xf7, 0x4c1: 0x55, 0x4c2: 0xf8, 0x4c3: 0xf9, 0x4c4: 0xfa, 0x4c5: 0xfb, 0x4c6: 0xfc,
0x4c9: 0xfd, 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: 0xfe, 0x4dc: 0x55, 0x4dd: 0x55, 0x4de: 0x55, 0x4df: 0xff,
0x4e0: 0x100, 0x4e1: 0x101, 0x4e2: 0x102, 0x4e3: 0x103, 0x4e4: 0x55, 0x4e5: 0x55, 0x4e6: 0x55, 0x4e7: 0x55,
0x4e8: 0x55, 0x4e9: 0x104, 0x4ea: 0x105, 0x4eb: 0x106, 0x4ec: 0x55, 0x4ed: 0x55, 0x4ee: 0x107, 0x4ef: 0x108,
0x4ff: 0x109,
// Block 0x14, offset 0x500
0x53f: 0x109,
// 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: 0x10a, 0x5c1: 0x10a, 0x5c2: 0x10a, 0x5c3: 0x10a, 0x5c4: 0x05, 0x5c5: 0x05, 0x5c6: 0x05, 0x5c7: 0x10b,
0x5c8: 0x10a, 0x5c9: 0x10a, 0x5ca: 0x10a, 0x5cb: 0x10a, 0x5cc: 0x10a, 0x5cd: 0x10a, 0x5ce: 0x10a, 0x5cf: 0x10a,
0x5d0: 0x10a, 0x5d1: 0x10a, 0x5d2: 0x10a, 0x5d3: 0x10a, 0x5d4: 0x10a, 0x5d5: 0x10a, 0x5d6: 0x10a, 0x5d7: 0x10a,
0x5d8: 0x10a, 0x5d9: 0x10a, 0x5da: 0x10a, 0x5db: 0x10a, 0x5dc: 0x10a, 0x5dd: 0x10a, 0x5de: 0x10a, 0x5df: 0x10a,
0x5e0: 0x10a, 0x5e1: 0x10a, 0x5e2: 0x10a, 0x5e3: 0x10a, 0x5e4: 0x10a, 0x5e5: 0x10a, 0x5e6: 0x10a, 0x5e7: 0x10a,
0x5e8: 0x10a, 0x5e9: 0x10a, 0x5ea: 0x10a, 0x5eb: 0x10a, 0x5ec: 0x10a, 0x5ed: 0x10a, 0x5ee: 0x10a, 0x5ef: 0x10a,
0x5f0: 0x10a, 0x5f1: 0x10a, 0x5f2: 0x10a, 0x5f3: 0x10a, 0x5f4: 0x10a, 0x5f5: 0x10a, 0x5f6: 0x10a, 0x5f7: 0x10a,
0x5f8: 0x10a, 0x5f9: 0x10a, 0x5fa: 0x10a, 0x5fb: 0x10a, 0x5fc: 0x10a, 0x5fd: 0x10a, 0x5fe: 0x10a, 0x5ff: 0x10a,
// Block 0x18, offset 0x600
0x60f: 0x12,
0x61f: 0x12,
0x620: 0x15,
0x62f: 0x12,
0x63f: 0x12,
// Block 0x19, offset 0x640
0x64f: 0x12,
}
// Total table size 20664 bytes (20KiB); 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)
// 12..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), with 33 mapped to 31 to fit in 5 bits.
// (If any 31- or 32-byte decompositions come along, we could switch to using
// use a general lookup table as long as there are at most 32 distinct lengths.)
// The three most significant bits of this length byte correspond
// to bit 5, 4, and 3 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 = 0x1F // extract the length value from the header byte (31 => 33)
headerFlagsMask = 0xE0 // 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 6 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 6 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
if n == 31 {
n = 33
}
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 {
n := uint16(h & headerLenMask)
if n == 31 {
n = 33
}
v += n + 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.27
package norm
import "sync"
const (
// Version is the Unicode edition from which the tables are derived.
Version = "17.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 = 0x2EBF
firstLeadingCCC = 0x4B3F
firstCCCZeroExcept = 0x4C99
firstStarterWithNLead = 0x4CC0
lastDecomp = 0x4CC2
maxDecomp = 0x8000
)
// decomps: 19650 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, 0x5F, 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, 0x44, 0x44, 0x5A,
0xCC, 0x8C, 0xCD, 0x44, 0x44, 0x7A, 0xCC, 0x8C,
0xCD, 0x44, 0x64, 0x7A, 0xCC, 0x8C, 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, 0x49,
// Bytes 2e00 - 2e3f
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, 0x83, 0x9B,
0xE3, 0x82, 0x9A, 0x11, 0x4C, 0xE3, 0x83, 0xA4,
0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x82,
// Bytes 2e40 - 2e7f
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, 0xE3, 0x82,
0xAF, 0xE3, 0x82, 0x99, 0x11, 0x4F, 0xE3, 0x83,
0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3,
// Bytes 2e80 - 2ebf
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, 0x95, 0xE3,
0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83,
0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x11, 0x03,
// Bytes 2ec0 - 2eff
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, 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,
// Bytes 2f00 - 2f3f
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, 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,
// Bytes 2f40 - 2f7f
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, 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,
// Bytes 2f80 - 2fbf
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, 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,
// Bytes 2fc0 - 2fff
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, 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,
// Bytes 3000 - 303f
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, 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,
// Bytes 3040 - 307f
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, 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,
// Bytes 3080 - 30bf
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, 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,
// Bytes 30c0 - 30ff
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, 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,
// Bytes 3100 - 313f
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, 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,
// Bytes 3140 - 317f
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, 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,
// Bytes 3180 - 31bf
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, 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,
// Bytes 31c0 - 31ff
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, 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,
// Bytes 3200 - 323f
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, 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,
// Bytes 3240 - 327f
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, 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,
// Bytes 3280 - 32bf
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, 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,
// Bytes 32c0 - 32ff
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, 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,
// Bytes 3300 - 333f
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, 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,
// Bytes 3340 - 337f
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, 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,
// Bytes 3380 - 33bf
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, 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,
// Bytes 33c0 - 33ff
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, 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,
// Bytes 3400 - 343f
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, 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,
// Bytes 3440 - 347f
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, 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,
// Bytes 3480 - 34bf
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, 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,
// Bytes 34c0 - 34ff
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, 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,
// Bytes 3500 - 353f
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, 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,
// Bytes 3540 - 357f
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, 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,
// Bytes 3580 - 35bf
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, 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,
// Bytes 35c0 - 35ff
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, 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,
// Bytes 3600 - 363f
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, 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,
// Bytes 3640 - 367f
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, 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,
// Bytes 3680 - 36bf
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, 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,
// Bytes 36c0 - 36ff
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, 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,
// Bytes 3700 - 373f
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, 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,
// Bytes 3740 - 377f
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, 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,
// Bytes 3780 - 37bf
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, 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,
// Bytes 37c0 - 37ff
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, 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,
// Bytes 3800 - 383f
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, 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,
// Bytes 3840 - 387f
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, 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,
// Bytes 3880 - 38bf
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, 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,
// Bytes 38c0 - 38ff
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, 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,
// Bytes 3900 - 393f
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, 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,
// Bytes 3940 - 397f
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, 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,
// Bytes 3980 - 39bf
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, 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,
// Bytes 39c0 - 39ff
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, 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,
// Bytes 3a00 - 3a3f
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, 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,
// Bytes 3a40 - 3a7f
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, 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,
// Bytes 3a80 - 3abf
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, 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,
// Bytes 3ac0 - 3aff
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, 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,
// Bytes 3b00 - 3b3f
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, 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,
// Bytes 3b40 - 3b7f
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, 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,
// Bytes 3b80 - 3bbf
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, 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,
// Bytes 3bc0 - 3bff
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, 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,
// Bytes 3c00 - 3c3f
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, 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,
// Bytes 3c40 - 3c7f
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, 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,
// Bytes 3c80 - 3cbf
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, 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,
// Bytes 3cc0 - 3cff
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, 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,
// Bytes 3d00 - 3d3f
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, 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,
// Bytes 3d40 - 3d7f
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, 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,
// Bytes 3d80 - 3dbf
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, 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,
// Bytes 3dc0 - 3dff
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, 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,
// Bytes 3e00 - 3e3f
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, 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,
// Bytes 3e40 - 3e7f
0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x0D, 0x06,
0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x0D, 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, 0x92, 0xE0, 0xAF, 0x97, 0x01, 0x06,
// Bytes 3e80 - 3ebf
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, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x89, 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,
// Bytes 3ec0 - 3eff
0xE0, 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x01, 0x06,
0xE0, 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x01, 0x06,
0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A, 0x15, 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,
// Bytes 3f00 - 3f3f
0xE1, 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x01, 0x06,
0xE1, 0xAC, 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, 0x06,
// Bytes 3f40 - 3f7f
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, 0x11, 0x06,
// Bytes 3f80 - 3fbf
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, 0x11, 0x06,
// Bytes 3fc0 - 3fff
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, 0x11, 0x06,
// Bytes 4000 - 403f
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, 0x11, 0x06,
// Bytes 4040 - 407f
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, 0x11, 0x06,
// Bytes 4080 - 40bf
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, 0x11, 0x06,
// Bytes 40c0 - 40ff
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, 0x11, 0x06,
// Bytes 4100 - 413f
0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0x11, 0x06,
0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x11, 0x06,
0xF0, 0x90, 0x97, 0x92, 0xCC, 0x87, 0xCD, 0x06,
0xF0, 0x90, 0x97, 0x9A, 0xCC, 0x87, 0xCD, 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,
// Bytes 4140 - 417f
0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDF, 0x08,
0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 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,
// Bytes 4180 - 41bf
0xCD, 0x85, 0xDF, 0x08, 0xCE, 0x97, 0xCC, 0x94,
0xCC, 0x81, 0xCD, 0x85, 0xDF, 0x08, 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,
// Bytes 41c0 - 41ff
0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85,
0xDF, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 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,
// Bytes 4200 - 423f
0xCC, 0x81, 0xCD, 0x85, 0xDF, 0x08, 0xCE, 0xB1,
0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 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,
// Bytes 4240 - 427f
0xDF, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x82,
0xCD, 0x85, 0xDF, 0x08, 0xCF, 0x89, 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,
// Bytes 4280 - 42bf
0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDF, 0x08,
0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82, 0xBA,
0x0D, 0x08, 0xF0, 0x91, 0x82, 0x9B, 0xF0, 0x91,
0x82, 0xBA, 0x0D, 0x08, 0xF0, 0x91, 0x82, 0xA5,
0xF0, 0x91, 0x82, 0xBA, 0x0D, 0x08, 0xF0, 0x91,
0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x01, 0x08,
0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84, 0xA7,
0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87, 0xF0, 0x91,
// Bytes 42c0 - 42ff
0x8C, 0xBE, 0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87,
0xF0, 0x91, 0x8D, 0x97, 0x01, 0x08, 0xF0, 0x91,
0x8E, 0x82, 0xF0, 0x91, 0x8F, 0x89, 0x01, 0x08,
0xF0, 0x91, 0x8E, 0x84, 0xF0, 0x91, 0x8E, 0xBB,
0x01, 0x08, 0xF0, 0x91, 0x8E, 0x8B, 0xF0, 0x91,
0x8F, 0x82, 0x01, 0x08, 0xF0, 0x91, 0x8E, 0x90,
0xF0, 0x91, 0x8F, 0x89, 0x01, 0x08, 0xF0, 0x91,
0x92, 0xB9, 0xF0, 0x91, 0x92, 0xB0, 0x01, 0x08,
// Bytes 4300 - 433f
0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xBA,
0x01, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91,
0x92, 0xBD, 0x01, 0x08, 0xF0, 0x91, 0x96, 0xB8,
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,
// Bytes 4340 - 437f
0xE0, 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x16, 0x0C,
0xF0, 0x96, 0xB5, 0xA3, 0xF0, 0x96, 0xB5, 0xA7,
0xF0, 0x96, 0xB5, 0xA7, 0x02, 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, 0xCC, 0x8A,
// Bytes 4380 - 43bf
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, 0x20, 0xD9,
// Bytes 43c0 - 43ff
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, 0xCD, 0x44,
// Bytes 4400 - 443f
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, 0xCC, 0x81,
// Bytes 4440 - 447f
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, 0xD7, 0x95,
// Bytes 4480 - 44bf
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, 0x45, 0x44,
// Bytes 44c0 - 44ff
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, 0xD6, 0xBC,
// Bytes 4500 - 453f
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, 0xD9, 0x80,
// Bytes 4540 - 457f
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, 0xCC, 0x81,
// Bytes 4580 - 45bf
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, 0x91, 0x76,
// Bytes 45c0 - 45ff
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, 0xD6, 0xBC,
// Bytes 4600 - 463f
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, 0xA1, 0xE0,
// Bytes 4640 - 467f
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, 0x97, 0xE0,
// Bytes 4680 - 46bf
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, 0xB3, 0xE0,
// Bytes 46c0 - 46ff
0xBE, 0x80, 0xA1, 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, 0x01, 0x46, 0xE1, 0x84, 0x87, 0xE1,
0x85, 0xA1, 0x01, 0x46, 0xE1, 0x84, 0x89, 0xE1,
0x85, 0xA1, 0x01, 0x46, 0xE1, 0x84, 0x8B, 0xE1,
// Bytes 4700 - 473f
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, 0x01, 0x46, 0xE1, 0x84, 0x91, 0xE1,
0x85, 0xA1, 0x01, 0x46, 0xE1, 0x84, 0x92, 0xE1,
0x85, 0xA1, 0x01, 0x46, 0xE3, 0x83, 0x86, 0xE3,
// Bytes 4740 - 477f
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, 0x49, 0xE0,
0xBE, 0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80,
// Bytes 4780 - 47bf
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, 0x85, 0xB1,
0xB2, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D,
// Bytes 47c0 - 47ff
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, 0xF0, 0x9D,
0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xB2, 0x83,
// Bytes 4800 - 483f
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, 0x83, 0x49,
0xCC, 0x88, 0xCD, 0x83, 0x4C, 0xCC, 0xA3, 0xB9,
// Bytes 4840 - 487f
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, 0xCD, 0x83,
0x53, 0xCC, 0xA3, 0xB9, 0x83, 0x55, 0xCC, 0x83,
// Bytes 4880 - 48bf
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, 0x82, 0xCD,
0x83, 0x65, 0xCC, 0x84, 0xCD, 0x83, 0x65, 0xCC,
// Bytes 48c0 - 48ff
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, 0xCC, 0xA8,
0xA9, 0x83, 0x72, 0xCC, 0xA3, 0xB9, 0x83, 0x73,
// Bytes 4900 - 493f
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, 0xCC, 0x94,
0xCD, 0x84, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x84,
// Bytes 4940 - 497f
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, 0xCE, 0xB1,
0xCC, 0x81, 0xCD, 0x84, 0xCE, 0xB1, 0xCC, 0x93,
// Bytes 4980 - 49bf
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, 0xCD, 0x84,
0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x84, 0xCE, 0xB9,
// Bytes 49c0 - 49ff
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, 0xCC, 0x93,
0xCD, 0x84, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x84,
// Bytes 4a00 - 4a3f
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, 0xCE, 0x97,
0xCC, 0x93, 0xCC, 0x80, 0xCE, 0x86, 0xCE, 0x97,
// Bytes 4a40 - 4a7f
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, 0xCE, 0xA9,
0xCC, 0x93, 0xCD, 0x82, 0xCE, 0x86, 0xCE, 0xA9,
// Bytes 4a80 - 4abf
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, 0xCE, 0xB1,
0xCC, 0x94, 0xCC, 0x81, 0xCE, 0x86, 0xCE, 0xB1,
// Bytes 4ac0 - 4aff
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, 0xCF, 0x89,
0xCC, 0x93, 0xCC, 0x80, 0xCE, 0x86, 0xCF, 0x89,
// Bytes 4b00 - 4b3f
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, 0x86, 0xE0, 0xB3,
0x86, 0xE0, 0xB3, 0x82, 0x01, 0x86, 0xE0, 0xB7,
0x99, 0xE0, 0xB7, 0x8F, 0x01, 0x88, 0xF0, 0x96,
0xB5, 0xA3, 0xF0, 0x96, 0xB5, 0xA7, 0x01, 0x42,
// Bytes 4b40 - 4b7f
0xCC, 0x80, 0xCD, 0x33, 0x42, 0xCC, 0x81, 0xCD,
0x33, 0x42, 0xCC, 0x93, 0xCD, 0x33, 0x43, 0xE1,
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,
// Bytes 4b80 - 4bbf
0x85, 0xA9, 0x01, 0x00, 0x43, 0xE1, 0x85, 0xAA,
0x01, 0x00, 0x43, 0xE1, 0x85, 0xAB, 0x01, 0x00,
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,
// Bytes 4bc0 - 4bff
0x43, 0xE1, 0x85, 0xB4, 0x01, 0x00, 0x43, 0xE1,
0x85, 0xB5, 0x01, 0x00, 0x43, 0xE1, 0x86, 0xAA,
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,
// Bytes 4c00 - 4c3f
0x01, 0x00, 0x44, 0xCC, 0x88, 0xCC, 0x81, 0xCE,
0x33, 0x68, 0xF0, 0x91, 0x8F, 0x82, 0xF0, 0x91,
0x8E, 0xB8, 0x02, 0x00, 0x68, 0xF0, 0x91, 0x8F,
0x82, 0xF0, 0x91, 0x8F, 0x82, 0x02, 0x00, 0x68,
0xF0, 0x91, 0x8F, 0x82, 0xF0, 0x91, 0x8F, 0x89,
0x02, 0x00, 0x68, 0xF0, 0x96, 0x84, 0x9E, 0xF0,
0x96, 0x84, 0x9F, 0x02, 0x00, 0x68, 0xF0, 0x96,
0x84, 0x9E, 0xF0, 0x96, 0x84, 0xA0, 0x02, 0x00,
// Bytes 4c40 - 4c7f
0x68, 0xF0, 0x96, 0x84, 0xA9, 0xF0, 0x96, 0x84,
0x9F, 0x02, 0x00, 0x68, 0xF0, 0x96, 0xB5, 0xA7,
0xF0, 0x96, 0xB5, 0xA7, 0x02, 0x00, 0x6C, 0xF0,
0x96, 0x84, 0x9E, 0xF0, 0x96, 0x84, 0x9E, 0xF0,
0x96, 0x84, 0x9F, 0x03, 0x00, 0x6C, 0xF0, 0x96,
0x84, 0x9E, 0xF0, 0x96, 0x84, 0x9E, 0xF0, 0x96,
0x84, 0xA0, 0x03, 0x00, 0x6C, 0xF0, 0x96, 0x84,
0x9E, 0xF0, 0x96, 0x84, 0xA9, 0xF0, 0x96, 0x84,
// Bytes 4c80 - 4cbf
0x9F, 0x03, 0x00, 0xE8, 0xF0, 0x96, 0x84, 0x9E,
0xF0, 0x96, 0x84, 0x9E, 0x02, 0x00, 0xE8, 0xF0,
0x96, 0x84, 0x9E, 0xF0, 0x96, 0x84, 0xA9, 0x02,
0x00, 0x43, 0xE3, 0x82, 0x99, 0x11, 0x04, 0x43,
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,
// Bytes 4cc0 - 4cff
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: 11042 bytes (10.78 KiB). Checksum: cd75f956cd2316a9.
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: 0x2ece, 0xc1: 0x2ed3, 0xc2: 0x47ff, 0xc3: 0x2ed8, 0xc4: 0x480e, 0xc5: 0x4813,
0xc6: 0xa000, 0xc7: 0x481d, 0xc8: 0x2f41, 0xc9: 0x2f46, 0xca: 0x4822, 0xcb: 0x2f5a,
0xcc: 0x2fcd, 0xcd: 0x2fd2, 0xce: 0x2fd7, 0xcf: 0x4836, 0xd1: 0x3063,
0xd2: 0x3086, 0xd3: 0x308b, 0xd4: 0x4840, 0xd5: 0x4845, 0xd6: 0x4854,
0xd8: 0xa000, 0xd9: 0x3112, 0xda: 0x3117, 0xdb: 0x311c, 0xdc: 0x4886, 0xdd: 0x3194,
0xe0: 0x31da, 0xe1: 0x31df, 0xe2: 0x4890, 0xe3: 0x31e4,
0xe4: 0x489f, 0xe5: 0x48a4, 0xe6: 0xa000, 0xe7: 0x48ae, 0xe8: 0x324d, 0xe9: 0x3252,
0xea: 0x48b3, 0xeb: 0x3266, 0xec: 0x32de, 0xed: 0x32e3, 0xee: 0x32e8, 0xef: 0x48c7,
0xf1: 0x3374, 0xf2: 0x3397, 0xf3: 0x339c, 0xf4: 0x48d1, 0xf5: 0x48d6,
0xf6: 0x48e5, 0xf8: 0xa000, 0xf9: 0x3428, 0xfa: 0x342d, 0xfb: 0x3432,
0xfc: 0x4917, 0xfd: 0x34af, 0xff: 0x34c8,
// Block 0x4, offset 0x100
0x100: 0x2edd, 0x101: 0x31e9, 0x102: 0x4804, 0x103: 0x4895, 0x104: 0x2efb, 0x105: 0x3207,
0x106: 0x2f0f, 0x107: 0x321b, 0x108: 0x2f14, 0x109: 0x3220, 0x10a: 0x2f19, 0x10b: 0x3225,
0x10c: 0x2f1e, 0x10d: 0x322a, 0x10e: 0x2f28, 0x10f: 0x3234,
0x112: 0x4827, 0x113: 0x48b8, 0x114: 0x2f50, 0x115: 0x325c, 0x116: 0x2f55, 0x117: 0x3261,
0x118: 0x2f73, 0x119: 0x327f, 0x11a: 0x2f64, 0x11b: 0x3270, 0x11c: 0x2f8c, 0x11d: 0x3298,
0x11e: 0x2f96, 0x11f: 0x32a2, 0x120: 0x2f9b, 0x121: 0x32a7, 0x122: 0x2fa5, 0x123: 0x32b1,
0x124: 0x2faa, 0x125: 0x32b6, 0x128: 0x2fdc, 0x129: 0x32ed,
0x12a: 0x2fe1, 0x12b: 0x32f2, 0x12c: 0x2fe6, 0x12d: 0x32f7, 0x12e: 0x3009, 0x12f: 0x3315,
0x130: 0x2feb, 0x134: 0x3013, 0x135: 0x331f,
0x136: 0x3027, 0x137: 0x3338, 0x139: 0x3031, 0x13a: 0x3342, 0x13b: 0x303b,
0x13c: 0x334c, 0x13d: 0x3036, 0x13e: 0x3347,
// Block 0x5, offset 0x140
0x143: 0x305e, 0x144: 0x336f, 0x145: 0x3077,
0x146: 0x3388, 0x147: 0x306d, 0x148: 0x337e,
0x14c: 0x484a, 0x14d: 0x48db, 0x14e: 0x3090, 0x14f: 0x33a1, 0x150: 0x309a, 0x151: 0x33ab,
0x154: 0x30b8, 0x155: 0x33c9, 0x156: 0x30d1, 0x157: 0x33e2,
0x158: 0x30c2, 0x159: 0x33d3, 0x15a: 0x486d, 0x15b: 0x48fe, 0x15c: 0x30db, 0x15d: 0x33ec,
0x15e: 0x30ea, 0x15f: 0x33fb, 0x160: 0x4872, 0x161: 0x4903, 0x162: 0x3103, 0x163: 0x3419,
0x164: 0x30f4, 0x165: 0x340a, 0x168: 0x487c, 0x169: 0x490d,
0x16a: 0x4881, 0x16b: 0x4912, 0x16c: 0x3121, 0x16d: 0x3437, 0x16e: 0x312b, 0x16f: 0x3441,
0x170: 0x3130, 0x171: 0x3446, 0x172: 0x314e, 0x173: 0x3464, 0x174: 0x3171, 0x175: 0x3487,
0x176: 0x3199, 0x177: 0x34b4, 0x178: 0x31ad, 0x179: 0x31bc, 0x17a: 0x34dc, 0x17b: 0x31c6,
0x17c: 0x34e6, 0x17d: 0x31cb, 0x17e: 0x34eb, 0x17f: 0xa000,
// Block 0x6, offset 0x180
0x184: 0x8100, 0x185: 0x8100,
0x186: 0x8100,
0x18d: 0x2ee7, 0x18e: 0x31f3, 0x18f: 0x2ff5, 0x190: 0x3301, 0x191: 0x309f,
0x192: 0x33b0, 0x193: 0x3135, 0x194: 0x344b, 0x195: 0x392e, 0x196: 0x3abd, 0x197: 0x3927,
0x198: 0x3ab6, 0x199: 0x3935, 0x19a: 0x3ac4, 0x19b: 0x3920, 0x19c: 0x3aaf,
0x19e: 0x380f, 0x19f: 0x399e, 0x1a0: 0x3808, 0x1a1: 0x3997, 0x1a2: 0x3512, 0x1a3: 0x3524,
0x1a6: 0x2fa0, 0x1a7: 0x32ac, 0x1a8: 0x301d, 0x1a9: 0x332e,
0x1aa: 0x4863, 0x1ab: 0x48f4, 0x1ac: 0x38ef, 0x1ad: 0x3a7e, 0x1ae: 0x3536, 0x1af: 0x353c,
0x1b0: 0x3324, 0x1b4: 0x2f87, 0x1b5: 0x3293,
0x1b8: 0x3059, 0x1b9: 0x336a, 0x1ba: 0x3816, 0x1bb: 0x39a5,
0x1bc: 0x350c, 0x1bd: 0x351e, 0x1be: 0x3518, 0x1bf: 0x352a,
// Block 0x7, offset 0x1c0
0x1c0: 0x2eec, 0x1c1: 0x31f8, 0x1c2: 0x2ef1, 0x1c3: 0x31fd, 0x1c4: 0x2f69, 0x1c5: 0x3275,
0x1c6: 0x2f6e, 0x1c7: 0x327a, 0x1c8: 0x2ffa, 0x1c9: 0x3306, 0x1ca: 0x2fff, 0x1cb: 0x330b,
0x1cc: 0x30a4, 0x1cd: 0x33b5, 0x1ce: 0x30a9, 0x1cf: 0x33ba, 0x1d0: 0x30c7, 0x1d1: 0x33d8,
0x1d2: 0x30cc, 0x1d3: 0x33dd, 0x1d4: 0x313a, 0x1d5: 0x3450, 0x1d6: 0x313f, 0x1d7: 0x3455,
0x1d8: 0x30e5, 0x1d9: 0x33f6, 0x1da: 0x30fe, 0x1db: 0x3414,
0x1de: 0x2fb9, 0x1df: 0x32c5,
0x1e6: 0x4809, 0x1e7: 0x489a, 0x1e8: 0x4831, 0x1e9: 0x48c2,
0x1ea: 0x38be, 0x1eb: 0x3a4d, 0x1ec: 0x389b, 0x1ed: 0x3a2a, 0x1ee: 0x484f, 0x1ef: 0x48e0,
0x1f0: 0x38b7, 0x1f1: 0x3a46, 0x1f2: 0x31a3, 0x1f3: 0x34be,
// 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: 0x4b3f, 0x241: 0x4b44, 0x242: 0x9933, 0x243: 0x4b49, 0x244: 0x4c02, 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: 0x3500,
0x286: 0x3548, 0x287: 0x00ce, 0x288: 0x3566, 0x289: 0x3572, 0x28a: 0x3584,
0x28c: 0x35a2, 0x28e: 0x35b4, 0x28f: 0x35d2, 0x290: 0x3d67, 0x291: 0xa000,
0x295: 0xa000, 0x297: 0xa000,
0x299: 0xa000,
0x29f: 0xa000, 0x2a1: 0xa000,
0x2a5: 0xa000, 0x2a9: 0xa000,
0x2aa: 0x3596, 0x2ab: 0x35c6, 0x2ac: 0x4975, 0x2ad: 0x35f6, 0x2ae: 0x499f, 0x2af: 0x3608,
0x2b0: 0x3dcf, 0x2b1: 0xa000, 0x2b5: 0xa000,
0x2b7: 0xa000, 0x2b9: 0xa000,
0x2bf: 0xa000,
// Block 0xb, offset 0x2c0
0x2c0: 0x3680, 0x2c1: 0x368c, 0x2c3: 0x367a,
0x2c6: 0xa000, 0x2c7: 0x3668,
0x2cc: 0x36bc, 0x2cd: 0x36a4, 0x2ce: 0x36ce, 0x2d0: 0xa000,
0x2d3: 0xa000, 0x2d5: 0xa000, 0x2d6: 0xa000, 0x2d7: 0xa000,
0x2d8: 0xa000, 0x2d9: 0x36b0, 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: 0x3734, 0x2fa: 0xa000,
0x2fe: 0xa000,
// Block 0xc, offset 0x300
0x301: 0x3692, 0x302: 0x3716,
0x310: 0x366e, 0x311: 0x36f2,
0x312: 0x3674, 0x313: 0x36f8, 0x316: 0x3686, 0x317: 0x370a,
0x318: 0xa000, 0x319: 0xa000, 0x31a: 0x3788, 0x31b: 0x378e, 0x31c: 0x3698, 0x31d: 0x371c,
0x31e: 0x369e, 0x31f: 0x3722, 0x322: 0x36aa, 0x323: 0x372e,
0x324: 0x36b6, 0x325: 0x373a, 0x326: 0x36c2, 0x327: 0x3746, 0x328: 0xa000, 0x329: 0xa000,
0x32a: 0x3794, 0x32b: 0x379a, 0x32c: 0x36ec, 0x32d: 0x3770, 0x32e: 0x36c8, 0x32f: 0x374c,
0x330: 0x36d4, 0x331: 0x3758, 0x332: 0x36da, 0x333: 0x375e, 0x334: 0x36e0, 0x335: 0x3764,
0x338: 0x36e6, 0x339: 0x376a,
// 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: 0x3ee7, 0x407: 0xa000, 0x408: 0x3eef, 0x409: 0xa000, 0x40a: 0x3ef7, 0x40b: 0xa000,
0x40c: 0x3eff, 0x40d: 0xa000, 0x40e: 0x3f07, 0x411: 0xa000,
0x412: 0x3f0f,
0x434: 0x8103, 0x435: 0x9900,
0x43a: 0xa000, 0x43b: 0x3f17,
0x43c: 0xa000, 0x43d: 0x3f1f, 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: 0x2ef6, 0x481: 0x3202, 0x482: 0x2f00, 0x483: 0x320c, 0x484: 0x2f05, 0x485: 0x3211,
0x486: 0x2f0a, 0x487: 0x3216, 0x488: 0x382b, 0x489: 0x39ba, 0x48a: 0x2f23, 0x48b: 0x322f,
0x48c: 0x2f2d, 0x48d: 0x3239, 0x48e: 0x2f3c, 0x48f: 0x3248, 0x490: 0x2f32, 0x491: 0x323e,
0x492: 0x2f37, 0x493: 0x3243, 0x494: 0x384e, 0x495: 0x39dd, 0x496: 0x3855, 0x497: 0x39e4,
0x498: 0x2f78, 0x499: 0x3284, 0x49a: 0x2f7d, 0x49b: 0x3289, 0x49c: 0x3863, 0x49d: 0x39f2,
0x49e: 0x2f82, 0x49f: 0x328e, 0x4a0: 0x2f91, 0x4a1: 0x329d, 0x4a2: 0x2faf, 0x4a3: 0x32bb,
0x4a4: 0x2fbe, 0x4a5: 0x32ca, 0x4a6: 0x2fb4, 0x4a7: 0x32c0, 0x4a8: 0x2fc3, 0x4a9: 0x32cf,
0x4aa: 0x2fc8, 0x4ab: 0x32d4, 0x4ac: 0x300e, 0x4ad: 0x331a, 0x4ae: 0x386a, 0x4af: 0x39f9,
0x4b0: 0x3018, 0x4b1: 0x3329, 0x4b2: 0x3022, 0x4b3: 0x3333, 0x4b4: 0x302c, 0x4b5: 0x333d,
0x4b6: 0x483b, 0x4b7: 0x48cc, 0x4b8: 0x3871, 0x4b9: 0x3a00, 0x4ba: 0x3045, 0x4bb: 0x3356,
0x4bc: 0x3040, 0x4bd: 0x3351, 0x4be: 0x304a, 0x4bf: 0x335b,
// Block 0x13, offset 0x4c0
0x4c0: 0x304f, 0x4c1: 0x3360, 0x4c2: 0x3054, 0x4c3: 0x3365, 0x4c4: 0x3068, 0x4c5: 0x3379,
0x4c6: 0x3072, 0x4c7: 0x3383, 0x4c8: 0x3081, 0x4c9: 0x3392, 0x4ca: 0x307c, 0x4cb: 0x338d,
0x4cc: 0x3894, 0x4cd: 0x3a23, 0x4ce: 0x38a2, 0x4cf: 0x3a31, 0x4d0: 0x38a9, 0x4d1: 0x3a38,
0x4d2: 0x38b0, 0x4d3: 0x3a3f, 0x4d4: 0x30ae, 0x4d5: 0x33bf, 0x4d6: 0x30b3, 0x4d7: 0x33c4,
0x4d8: 0x30bd, 0x4d9: 0x33ce, 0x4da: 0x4868, 0x4db: 0x48f9, 0x4dc: 0x38f6, 0x4dd: 0x3a85,
0x4de: 0x30d6, 0x4df: 0x33e7, 0x4e0: 0x30e0, 0x4e1: 0x33f1, 0x4e2: 0x4877, 0x4e3: 0x4908,
0x4e4: 0x38fd, 0x4e5: 0x3a8c, 0x4e6: 0x3904, 0x4e7: 0x3a93, 0x4e8: 0x390b, 0x4e9: 0x3a9a,
0x4ea: 0x30ef, 0x4eb: 0x3400, 0x4ec: 0x30f9, 0x4ed: 0x340f, 0x4ee: 0x310d, 0x4ef: 0x3423,
0x4f0: 0x3108, 0x4f1: 0x341e, 0x4f2: 0x3149, 0x4f3: 0x345f, 0x4f4: 0x3158, 0x4f5: 0x346e,
0x4f6: 0x3153, 0x4f7: 0x3469, 0x4f8: 0x3912, 0x4f9: 0x3aa1, 0x4fa: 0x3919, 0x4fb: 0x3aa8,
0x4fc: 0x315d, 0x4fd: 0x3473, 0x4fe: 0x3162, 0x4ff: 0x3478,
// Block 0x14, offset 0x500
0x500: 0x3167, 0x501: 0x347d, 0x502: 0x316c, 0x503: 0x3482, 0x504: 0x317b, 0x505: 0x3491,
0x506: 0x3176, 0x507: 0x348c, 0x508: 0x3180, 0x509: 0x349b, 0x50a: 0x3185, 0x50b: 0x34a0,
0x50c: 0x318a, 0x50d: 0x34a5, 0x50e: 0x31a8, 0x50f: 0x34c3, 0x510: 0x31c1, 0x511: 0x34e1,
0x512: 0x31d0, 0x513: 0x34f0, 0x514: 0x31d5, 0x515: 0x34f5, 0x516: 0x32d9, 0x517: 0x3405,
0x518: 0x3496, 0x519: 0x34d2, 0x51b: 0x3530,
0x520: 0x4818, 0x521: 0x48a9, 0x522: 0x2ee2, 0x523: 0x31ee,
0x524: 0x37d7, 0x525: 0x3966, 0x526: 0x37d0, 0x527: 0x395f, 0x528: 0x37e5, 0x529: 0x3974,
0x52a: 0x37de, 0x52b: 0x396d, 0x52c: 0x381d, 0x52d: 0x39ac, 0x52e: 0x37f3, 0x52f: 0x3982,
0x530: 0x37ec, 0x531: 0x397b, 0x532: 0x3801, 0x533: 0x3990, 0x534: 0x37fa, 0x535: 0x3989,
0x536: 0x3824, 0x537: 0x39b3, 0x538: 0x482c, 0x539: 0x48bd, 0x53a: 0x2f5f, 0x53b: 0x326b,
0x53c: 0x2f4b, 0x53d: 0x3257, 0x53e: 0x3839, 0x53f: 0x39c8,
// Block 0x15, offset 0x540
0x540: 0x3832, 0x541: 0x39c1, 0x542: 0x3847, 0x543: 0x39d6, 0x544: 0x3840, 0x545: 0x39cf,
0x546: 0x385c, 0x547: 0x39eb, 0x548: 0x2ff0, 0x549: 0x32fc, 0x54a: 0x3004, 0x54b: 0x3310,
0x54c: 0x485e, 0x54d: 0x48ef, 0x54e: 0x3095, 0x54f: 0x33a6, 0x550: 0x387f, 0x551: 0x3a0e,
0x552: 0x3878, 0x553: 0x3a07, 0x554: 0x388d, 0x555: 0x3a1c, 0x556: 0x3886, 0x557: 0x3a15,
0x558: 0x38e8, 0x559: 0x3a77, 0x55a: 0x38cc, 0x55b: 0x3a5b, 0x55c: 0x38c5, 0x55d: 0x3a54,
0x55e: 0x38da, 0x55f: 0x3a69, 0x560: 0x38d3, 0x561: 0x3a62, 0x562: 0x38e1, 0x563: 0x3a70,
0x564: 0x3144, 0x565: 0x345a, 0x566: 0x3126, 0x567: 0x343c, 0x568: 0x3943, 0x569: 0x3ad2,
0x56a: 0x393c, 0x56b: 0x3acb, 0x56c: 0x3951, 0x56d: 0x3ae0, 0x56e: 0x394a, 0x56f: 0x3ad9,
0x570: 0x3958, 0x571: 0x3ae7, 0x572: 0x318f, 0x573: 0x34aa, 0x574: 0x31b7, 0x575: 0x34d7,
0x576: 0x31b2, 0x577: 0x34cd, 0x578: 0x319e, 0x579: 0x34b9,
// Block 0x16, offset 0x580
0x580: 0x497b, 0x581: 0x4981, 0x582: 0x4a95, 0x583: 0x4aad, 0x584: 0x4a9d, 0x585: 0x4ab5,
0x586: 0x4aa5, 0x587: 0x4abd, 0x588: 0x4921, 0x589: 0x4927, 0x58a: 0x4a05, 0x58b: 0x4a1d,
0x58c: 0x4a0d, 0x58d: 0x4a25, 0x58e: 0x4a15, 0x58f: 0x4a2d, 0x590: 0x498d, 0x591: 0x4993,
0x592: 0x3d17, 0x593: 0x3d27, 0x594: 0x3d1f, 0x595: 0x3d2f,
0x598: 0x492d, 0x599: 0x4933, 0x59a: 0x3c47, 0x59b: 0x3c57, 0x59c: 0x3c4f, 0x59d: 0x3c5f,
0x5a0: 0x49a5, 0x5a1: 0x49ab, 0x5a2: 0x4ac5, 0x5a3: 0x4add,
0x5a4: 0x4acd, 0x5a5: 0x4ae5, 0x5a6: 0x4ad5, 0x5a7: 0x4aed, 0x5a8: 0x4939, 0x5a9: 0x493f,
0x5aa: 0x4a35, 0x5ab: 0x4a4d, 0x5ac: 0x4a3d, 0x5ad: 0x4a55, 0x5ae: 0x4a45, 0x5af: 0x4a5d,
0x5b0: 0x49bd, 0x5b1: 0x49c3, 0x5b2: 0x3d77, 0x5b3: 0x3d8f, 0x5b4: 0x3d7f, 0x5b5: 0x3d97,
0x5b6: 0x3d87, 0x5b7: 0x3d9f, 0x5b8: 0x4945, 0x5b9: 0x494b, 0x5ba: 0x3c77, 0x5bb: 0x3c8f,
0x5bc: 0x3c7f, 0x5bd: 0x3c97, 0x5be: 0x3c87, 0x5bf: 0x3c9f,
// Block 0x17, offset 0x5c0
0x5c0: 0x49c9, 0x5c1: 0x49cf, 0x5c2: 0x3da7, 0x5c3: 0x3db7, 0x5c4: 0x3daf, 0x5c5: 0x3dbf,
0x5c8: 0x4951, 0x5c9: 0x4957, 0x5ca: 0x3ca7, 0x5cb: 0x3cb7,
0x5cc: 0x3caf, 0x5cd: 0x3cbf, 0x5d0: 0x49db, 0x5d1: 0x49e1,
0x5d2: 0x3ddf, 0x5d3: 0x3df7, 0x5d4: 0x3de7, 0x5d5: 0x3dff, 0x5d6: 0x3def, 0x5d7: 0x3e07,
0x5d9: 0x495d, 0x5db: 0x3cc7, 0x5dd: 0x3ccf,
0x5df: 0x3cd7, 0x5e0: 0x49f3, 0x5e1: 0x49f9, 0x5e2: 0x4af5, 0x5e3: 0x4b0d,
0x5e4: 0x4afd, 0x5e5: 0x4b15, 0x5e6: 0x4b05, 0x5e7: 0x4b1d, 0x5e8: 0x4963, 0x5e9: 0x4969,
0x5ea: 0x4a65, 0x5eb: 0x4a7d, 0x5ec: 0x4a6d, 0x5ed: 0x4a85, 0x5ee: 0x4a75, 0x5ef: 0x4a8d,
0x5f0: 0x496f, 0x5f1: 0x441d, 0x5f2: 0x35f0, 0x5f3: 0x4423, 0x5f4: 0x4999, 0x5f5: 0x4429,
0x5f6: 0x3602, 0x5f7: 0x442f, 0x5f8: 0x3620, 0x5f9: 0x4435, 0x5fa: 0x3638, 0x5fb: 0x443b,
0x5fc: 0x49e7, 0x5fd: 0x4441,
// Block 0x18, offset 0x600
0x600: 0x3cff, 0x601: 0x3d07, 0x602: 0x41d3, 0x603: 0x41f1, 0x604: 0x41dd, 0x605: 0x41fb,
0x606: 0x41e7, 0x607: 0x4205, 0x608: 0x3c37, 0x609: 0x3c3f, 0x60a: 0x411f, 0x60b: 0x413d,
0x60c: 0x4129, 0x60d: 0x4147, 0x60e: 0x4133, 0x60f: 0x4151, 0x610: 0x3d47, 0x611: 0x3d4f,
0x612: 0x420f, 0x613: 0x422d, 0x614: 0x4219, 0x615: 0x4237, 0x616: 0x4223, 0x617: 0x4241,
0x618: 0x3c67, 0x619: 0x3c6f, 0x61a: 0x415b, 0x61b: 0x4179, 0x61c: 0x4165, 0x61d: 0x4183,
0x61e: 0x416f, 0x61f: 0x418d, 0x620: 0x3e1f, 0x621: 0x3e27, 0x622: 0x424b, 0x623: 0x4269,
0x624: 0x4255, 0x625: 0x4273, 0x626: 0x425f, 0x627: 0x427d, 0x628: 0x3cdf, 0x629: 0x3ce7,
0x62a: 0x4197, 0x62b: 0x41b5, 0x62c: 0x41a1, 0x62d: 0x41bf, 0x62e: 0x41ab, 0x62f: 0x41c9,
0x630: 0x35e4, 0x631: 0x35de, 0x632: 0x3cef, 0x633: 0x35ea, 0x634: 0x3cf7,
0x636: 0x4987, 0x637: 0x3d0f, 0x638: 0x3554, 0x639: 0x354e, 0x63a: 0x3542, 0x63b: 0x43ed,
0x63c: 0x355a, 0x63d: 0x8100, 0x63e: 0x0257, 0x63f: 0xa100,
// Block 0x19, offset 0x640
0x640: 0x8100, 0x641: 0x3506, 0x642: 0x3d37, 0x643: 0x35fc, 0x644: 0x3d3f,
0x646: 0x49b1, 0x647: 0x3d57, 0x648: 0x3560, 0x649: 0x43f3, 0x64a: 0x356c, 0x64b: 0x43f9,
0x64c: 0x3578, 0x64d: 0x3aee, 0x64e: 0x3af5, 0x64f: 0x3afc, 0x650: 0x3614, 0x651: 0x360e,
0x652: 0x3d5f, 0x653: 0x45e3, 0x656: 0x361a, 0x657: 0x3d6f,
0x658: 0x3590, 0x659: 0x358a, 0x65a: 0x357e, 0x65b: 0x43ff, 0x65d: 0x3b03,
0x65e: 0x3b0a, 0x65f: 0x3b11, 0x660: 0x364a, 0x661: 0x3644, 0x662: 0x3dc7, 0x663: 0x45eb,
0x664: 0x362c, 0x665: 0x3632, 0x666: 0x3650, 0x667: 0x3dd7, 0x668: 0x35c0, 0x669: 0x35ba,
0x66a: 0x35ae, 0x66b: 0x440b, 0x66c: 0x35a8, 0x66d: 0x34fa, 0x66e: 0x43e7, 0x66f: 0x0081,
0x672: 0x3e0f, 0x673: 0x3656, 0x674: 0x3e17,
0x676: 0x49ff, 0x677: 0x3e2f, 0x678: 0x359c, 0x679: 0x4405, 0x67a: 0x35cc, 0x67b: 0x4417,
0x67c: 0x35d8, 0x67d: 0x4355, 0x67e: 0xa100,
// Block 0x1a, offset 0x680
0x681: 0x3b65, 0x683: 0xa000, 0x684: 0x3b6c, 0x685: 0xa000,
0x687: 0x3b73, 0x688: 0xa000, 0x689: 0x3b7a,
0x68d: 0xa000,
0x6a0: 0x2ec4, 0x6a1: 0xa000, 0x6a2: 0x3b88,
0x6a4: 0xa000, 0x6a5: 0xa000,
0x6ad: 0x3b81, 0x6ae: 0x2ebf, 0x6af: 0x2ec9,
0x6b0: 0x3b8f, 0x6b1: 0x3b96, 0x6b2: 0xa000, 0x6b3: 0xa000, 0x6b4: 0x3b9d, 0x6b5: 0x3ba4,
0x6b6: 0xa000, 0x6b7: 0xa000, 0x6b8: 0x3bab, 0x6b9: 0x3bb2, 0x6ba: 0xa000, 0x6bb: 0xa000,
0x6bc: 0xa000, 0x6bd: 0xa000,
// Block 0x1b, offset 0x6c0
0x6c0: 0x3bb9, 0x6c1: 0x3bc0, 0x6c2: 0xa000, 0x6c3: 0xa000, 0x6c4: 0x3bd5, 0x6c5: 0x3bdc,
0x6c6: 0xa000, 0x6c7: 0xa000, 0x6c8: 0x3be3, 0x6c9: 0x3bea,
0x6d1: 0xa000,
0x6d2: 0xa000,
0x6e2: 0xa000,
0x6e8: 0xa000, 0x6e9: 0xa000,
0x6eb: 0xa000, 0x6ec: 0x3bff, 0x6ed: 0x3c06, 0x6ee: 0x3c0d, 0x6ef: 0x3c14,
0x6f2: 0xa000, 0x6f3: 0xa000, 0x6f4: 0xa000, 0x6f5: 0xa000,
// Block 0x1c, offset 0x700
0x706: 0xa000, 0x70b: 0xa000,
0x70c: 0x3f47, 0x70d: 0xa000, 0x70e: 0x3f4f, 0x70f: 0xa000, 0x710: 0x3f57, 0x711: 0xa000,
0x712: 0x3f5f, 0x713: 0xa000, 0x714: 0x3f67, 0x715: 0xa000, 0x716: 0x3f6f, 0x717: 0xa000,
0x718: 0x3f77, 0x719: 0xa000, 0x71a: 0x3f7f, 0x71b: 0xa000, 0x71c: 0x3f87, 0x71d: 0xa000,
0x71e: 0x3f8f, 0x71f: 0xa000, 0x720: 0x3f97, 0x721: 0xa000, 0x722: 0x3f9f,
0x724: 0xa000, 0x725: 0x3fa7, 0x726: 0xa000, 0x727: 0x3faf, 0x728: 0xa000, 0x729: 0x3fb7,
0x72f: 0xa000,
0x730: 0x3fbf, 0x731: 0x3fc7, 0x732: 0xa000, 0x733: 0x3fcf, 0x734: 0x3fd7, 0x735: 0xa000,
0x736: 0x3fdf, 0x737: 0x3fe7, 0x738: 0xa000, 0x739: 0x3fef, 0x73a: 0x3ff7, 0x73b: 0xa000,
0x73c: 0x3fff, 0x73d: 0x4007,
// Block 0x1d, offset 0x740
0x754: 0x3f3f,
0x759: 0x9904, 0x75a: 0x9904, 0x75b: 0x8100, 0x75c: 0x8100, 0x75d: 0xa000,
0x75e: 0x400f,
0x766: 0xa000,
0x76b: 0xa000, 0x76c: 0x401f, 0x76d: 0xa000, 0x76e: 0x4027, 0x76f: 0xa000,
0x770: 0x402f, 0x771: 0xa000, 0x772: 0x4037, 0x773: 0xa000, 0x774: 0x403f, 0x775: 0xa000,
0x776: 0x4047, 0x777: 0xa000, 0x778: 0x404f, 0x779: 0xa000, 0x77a: 0x4057, 0x77b: 0xa000,
0x77c: 0x405f, 0x77d: 0xa000, 0x77e: 0x4067, 0x77f: 0xa000,
// Block 0x1e, offset 0x780
0x780: 0x406f, 0x781: 0xa000, 0x782: 0x4077, 0x784: 0xa000, 0x785: 0x407f,
0x786: 0xa000, 0x787: 0x4087, 0x788: 0xa000, 0x789: 0x408f,
0x78f: 0xa000, 0x790: 0x4097, 0x791: 0x409f,
0x792: 0xa000, 0x793: 0x40a7, 0x794: 0x40af, 0x795: 0xa000, 0x796: 0x40b7, 0x797: 0x40bf,
0x798: 0xa000, 0x799: 0x40c7, 0x79a: 0x40cf, 0x79b: 0xa000, 0x79c: 0x40d7, 0x79d: 0x40df,
0x7af: 0xa000,
0x7b0: 0xa000, 0x7b1: 0xa000, 0x7b2: 0xa000, 0x7b4: 0x4017,
0x7b7: 0x40e7, 0x7b8: 0x40ef, 0x7b9: 0x40f7, 0x7ba: 0x40ff,
0x7bd: 0xa000, 0x7be: 0x4107,
// 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,
0x357: 0xa1,
0x368: 0xa2, 0x36b: 0xa3,
0x374: 0xa4, 0x375: 0xa5,
0x37a: 0xa6, 0x37b: 0xa7, 0x37d: 0xa8, 0x37e: 0xa9,
// Block 0xe, offset 0x380
0x381: 0xaa, 0x382: 0xab, 0x384: 0xac, 0x385: 0x84, 0x387: 0xad,
0x388: 0xae, 0x38b: 0xaf, 0x38c: 0xb0, 0x38d: 0xb1, 0x38e: 0xb2, 0x38f: 0xb3,
0x391: 0xb4, 0x392: 0xb5, 0x393: 0xb6, 0x396: 0xb7, 0x397: 0xb8,
0x398: 0x75, 0x39a: 0xb9, 0x39c: 0xba,
0x3a0: 0xbb, 0x3a4: 0xbc, 0x3a5: 0xbd, 0x3a7: 0xbe,
0x3a8: 0xbf, 0x3a9: 0xc0, 0x3aa: 0xc1,
0x3b0: 0x75, 0x3b5: 0xc2, 0x3b6: 0xc3,
0x3bd: 0xc4,
// Block 0xf, offset 0x3c0
0x3c4: 0xc5,
0x3eb: 0xc6, 0x3ec: 0xc7,
0x3f5: 0xc8,
0x3ff: 0xc9,
// Block 0x10, offset 0x400
0x432: 0xca,
// Block 0x11, offset 0x440
0x445: 0xcb, 0x446: 0xcc, 0x447: 0xcd,
0x449: 0xce,
// Block 0x12, offset 0x480
0x480: 0xcf, 0x482: 0xd0, 0x484: 0xc7,
0x48a: 0xd1, 0x48b: 0xd2,
0x493: 0xd3, 0x497: 0xd4,
0x49b: 0xd5,
0x4a3: 0xd6, 0x4a5: 0xd7,
// Block 0x13, offset 0x4c0
0x4c8: 0xd8,
// 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: 171 entries, 342 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, 0x130, 0x139, 0x13b, 0x13e, 0x140, 0x14b, 0x14f, 0x15d, 0x160, 0x166, 0x16c, 0x177, 0x17b, 0x17d, 0x17f, 0x181, 0x183, 0x185, 0x18b, 0x18f, 0x191, 0x193, 0x19b, 0x19f, 0x1a2, 0x1a4, 0x1a6, 0x1a9, 0x1ac, 0x1ae, 0x1b0, 0x1b2, 0x1b4, 0x1ba, 0x1bd, 0x1bf, 0x1c6, 0x1cc, 0x1d2, 0x1da, 0x1e0, 0x1e6, 0x1ec, 0x1f0, 0x1fe, 0x207, 0x20a, 0x20d, 0x20f, 0x212, 0x214, 0x218, 0x21d, 0x21f, 0x221, 0x226, 0x22c, 0x22e, 0x230, 0x232, 0x237, 0x23d, 0x240, 0x242, 0x244, 0x246, 0x249, 0x24f, 0x253, 0x257, 0x25f, 0x266, 0x269, 0x26c, 0x26e, 0x271, 0x279, 0x283, 0x28a, 0x28e, 0x295, 0x298, 0x29e, 0x2a0, 0x2a3, 0x2a5, 0x2a8, 0x2ad, 0x2af, 0x2b1, 0x2b3, 0x2b5, 0x2b7, 0x2ba, 0x2bc, 0x2be, 0x2cb, 0x2cd, 0x2cf, 0x2d5, 0x2d7, 0x2d9, 0x2e6, 0x2f0, 0x2f2, 0x2f4, 0x2fa, 0x2fc, 0x2fe, 0x300, 0x304, 0x307, 0x30c, 0x30e, 0x311}
// nfcSparseValues: 787 entries, 3148 bytes
var nfcSparseValues = [787]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: 0x4859, lo: 0xa0, hi: 0xa1},
{value: 0x488b, 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: 0x49b7, lo: 0x8a, hi: 0x8a},
{value: 0x49d5, lo: 0x8b, hi: 0x8b},
{value: 0x3626, lo: 0x8c, hi: 0x8c},
{value: 0x363e, lo: 0x8d, hi: 0x8d},
{value: 0x49ed, lo: 0x8e, hi: 0x8e},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x365c, 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: 0x3704, lo: 0x90, hi: 0x90},
{value: 0x3710, lo: 0x91, hi: 0x91},
{value: 0x36fe, lo: 0x93, hi: 0x93},
{value: 0xa000, lo: 0x96, hi: 0x96},
{value: 0x3776, lo: 0x97, hi: 0x97},
{value: 0x3740, lo: 0x9c, hi: 0x9c},
{value: 0x3728, lo: 0x9d, hi: 0x9d},
{value: 0x3752, lo: 0x9e, hi: 0x9e},
{value: 0xa000, lo: 0xb4, hi: 0xb5},
{value: 0x377c, lo: 0xb6, hi: 0xb6},
{value: 0x3782, 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: 0x37a0, lo: 0xa2, hi: 0xa2},
{value: 0x37a6, lo: 0xa3, hi: 0xa3},
{value: 0x37b2, lo: 0xa4, hi: 0xa4},
{value: 0x37ac, lo: 0xa5, hi: 0xa5},
{value: 0x37b8, lo: 0xa6, hi: 0xa6},
{value: 0xa000, lo: 0xa7, hi: 0xa7},
// Block 0x9, offset 0x3a
{value: 0x0000, lo: 0x0e},
{value: 0x37ca, lo: 0x80, hi: 0x80},
{value: 0xa000, lo: 0x81, hi: 0x81},
{value: 0x37be, lo: 0x82, hi: 0x82},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x37c4, 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: 0x97, 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: 0x3e37, lo: 0xa9, hi: 0xa9},
{value: 0xa000, lo: 0xb0, hi: 0xb0},
{value: 0x3e3f, lo: 0xb1, hi: 0xb1},
{value: 0xa000, lo: 0xb3, hi: 0xb3},
{value: 0x3e47, 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: 0x461b, 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: 0x3e4f, lo: 0x8b, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
{value: 0x465b, lo: 0x9c, hi: 0x9d},
{value: 0x466b, lo: 0x9f, hi: 0x9f},
{value: 0x8133, lo: 0xbe, hi: 0xbe},
// Block 0x14, offset 0x88
{value: 0x0000, lo: 0x03},
{value: 0x4693, lo: 0xb3, hi: 0xb3},
{value: 0x469b, 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: 0x4673, lo: 0x99, hi: 0x9b},
{value: 0x468b, 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: 0x3e67, lo: 0x88, hi: 0x88},
{value: 0x3e5f, lo: 0x8b, hi: 0x8b},
{value: 0x3e6f, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x96, hi: 0x97},
{value: 0x46a3, lo: 0x9c, hi: 0x9c},
{value: 0x46ab, lo: 0x9d, hi: 0x9d},
// Block 0x19, offset 0x9d
{value: 0x0000, lo: 0x03},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x3e77, 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: 0x3e7f, lo: 0x8a, hi: 0x8a},
{value: 0x3e8f, lo: 0x8b, hi: 0x8b},
{value: 0x3e87, 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: 0x3e97, 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: 0x3e9f, lo: 0x80, hi: 0x80},
{value: 0x9900, lo: 0x82, hi: 0x82},
{value: 0xa000, lo: 0x86, hi: 0x86},
{value: 0x3ea7, lo: 0x87, hi: 0x87},
{value: 0x3eaf, lo: 0x88, hi: 0x88},
{value: 0x4b25, lo: 0x8a, hi: 0x8a},
{value: 0x4331, 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: 0x3eb7, lo: 0x8a, hi: 0x8a},
{value: 0x3ec7, lo: 0x8b, hi: 0x8b},
{value: 0x3ebf, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
// Block 0x20, offset 0xc4
{value: 0x5a29, lo: 0x07},
{value: 0x9905, lo: 0x8a, hi: 0x8a},
{value: 0x9900, lo: 0x8f, hi: 0x8f},
{value: 0xa000, lo: 0x99, hi: 0x99},
{value: 0x3ecf, lo: 0x9a, hi: 0x9a},
{value: 0x4b2d, lo: 0x9c, hi: 0x9c},
{value: 0x433c, lo: 0x9d, hi: 0x9d},
{value: 0x3ed7, 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: 0x4ca5, lo: 0xb3, hi: 0xb3},
{value: 0x8129, lo: 0xb4, hi: 0xb4},
{value: 0x4cae, lo: 0xb5, hi: 0xb5},
{value: 0x46b3, lo: 0xb6, hi: 0xb6},
{value: 0x8200, lo: 0xb7, hi: 0xb7},
{value: 0x46bb, 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: 0x4cb7, 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: 0x3edf, 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: 0x0b},
{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: 0x9c},
{value: 0x812e, lo: 0x9d, hi: 0x9d},
{value: 0x8133, lo: 0xa0, hi: 0xa5},
{value: 0x812e, lo: 0xa6, hi: 0xa6},
{value: 0x8133, lo: 0xa7, hi: 0xaa},
{value: 0x8136, lo: 0xab, hi: 0xab},
// Block 0x38, offset 0x130
{value: 0x0000, lo: 0x08},
{value: 0x3f27, lo: 0x80, hi: 0x80},
{value: 0x3f2f, lo: 0x81, hi: 0x81},
{value: 0xa000, lo: 0x82, hi: 0x82},
{value: 0x3f37, 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 0x139
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xaa, hi: 0xab},
// Block 0x3a, offset 0x13b
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xa6, hi: 0xa6},
{value: 0x8105, lo: 0xb2, hi: 0xb3},
// Block 0x3b, offset 0x13e
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
// Block 0x3c, offset 0x140
{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 0x14b
{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 0x14f
{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 0x15d
{value: 0x437a, lo: 0x02},
{value: 0x023c, lo: 0xa6, hi: 0xa6},
{value: 0x0057, lo: 0xaa, hi: 0xab},
// Block 0x40, offset 0x160
{value: 0x0007, lo: 0x05},
{value: 0xa000, lo: 0x90, hi: 0x90},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0xa000, lo: 0x94, hi: 0x94},
{value: 0x3b18, lo: 0x9a, hi: 0x9b},
{value: 0x3b26, lo: 0xae, hi: 0xae},
// Block 0x41, offset 0x166
{value: 0x000e, lo: 0x05},
{value: 0x3b2d, lo: 0x8d, hi: 0x8e},
{value: 0x3b34, 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 0x16c
{value: 0x64a9, lo: 0x0a},
{value: 0xa000, lo: 0x83, hi: 0x83},
{value: 0x3b42, lo: 0x84, hi: 0x84},
{value: 0xa000, lo: 0x88, hi: 0x88},
{value: 0x3b49, lo: 0x89, hi: 0x89},
{value: 0xa000, lo: 0x8b, hi: 0x8b},
{value: 0x3b50, lo: 0x8c, hi: 0x8c},
{value: 0xa000, lo: 0xa3, hi: 0xa3},
{value: 0x3b57, lo: 0xa4, hi: 0xa5},
{value: 0x3b5e, lo: 0xa6, hi: 0xa6},
{value: 0xa000, lo: 0xbc, hi: 0xbc},
// Block 0x43, offset 0x177
{value: 0x0007, lo: 0x03},
{value: 0x3bc7, lo: 0xa0, hi: 0xa1},
{value: 0x3bf1, lo: 0xa2, hi: 0xa3},
{value: 0x3c1b, lo: 0xaa, hi: 0xad},
// Block 0x44, offset 0x17b
{value: 0x0004, lo: 0x01},
{value: 0x0586, lo: 0xa9, hi: 0xaa},
// Block 0x45, offset 0x17d
{value: 0x0000, lo: 0x01},
{value: 0x45dc, lo: 0x9c, hi: 0x9c},
// Block 0x46, offset 0x17f
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xaf, hi: 0xb1},
// Block 0x47, offset 0x181
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x48, offset 0x183
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa0, hi: 0xbf},
// Block 0x49, offset 0x185
{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 0x18b
{value: 0x0000, lo: 0x03},
{value: 0x4cc0, lo: 0xb3, hi: 0xb3},
{value: 0x4cc0, lo: 0xb5, hi: 0xb6},
{value: 0x4cc0, lo: 0xba, hi: 0xbf},
// Block 0x4b, offset 0x18f
{value: 0x0000, lo: 0x01},
{value: 0x4cc0, lo: 0x8f, hi: 0xa3},
// Block 0x4c, offset 0x191
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0xae, hi: 0xbe},
// Block 0x4d, offset 0x193
{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 0x19b
{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 0x19f
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xaf, hi: 0xaf},
{value: 0x8133, lo: 0xb4, hi: 0xbd},
// Block 0x50, offset 0x1a2
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x9e, hi: 0x9f},
// Block 0x51, offset 0x1a4
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb0, hi: 0xb1},
// Block 0x52, offset 0x1a6
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x86, hi: 0x86},
{value: 0x8105, lo: 0xac, hi: 0xac},
// Block 0x53, offset 0x1a9
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x84, hi: 0x84},
{value: 0x8133, lo: 0xa0, hi: 0xb1},
// Block 0x54, offset 0x1ac
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xab, hi: 0xad},
// Block 0x55, offset 0x1ae
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x93, hi: 0x93},
// Block 0x56, offset 0x1b0
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xb3, hi: 0xb3},
// Block 0x57, offset 0x1b2
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x80, hi: 0x80},
// Block 0x58, offset 0x1b4
{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 0x1ba
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x81, hi: 0x81},
{value: 0x8105, lo: 0xb6, hi: 0xb6},
// Block 0x5a, offset 0x1bd
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xad, hi: 0xad},
// Block 0x5b, offset 0x1bf
{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 0x1c6
{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 0x1cc
{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 0x1d2
{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 0x1da
{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 0x1e0
{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 0x1e6
{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 0x1ec
{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 0x1f0
{value: 0x0006, lo: 0x0d},
{value: 0x448f, lo: 0x9d, hi: 0x9d},
{value: 0x8116, lo: 0x9e, hi: 0x9e},
{value: 0x4501, lo: 0x9f, hi: 0x9f},
{value: 0x44ef, lo: 0xaa, hi: 0xab},
{value: 0x45f3, lo: 0xac, hi: 0xac},
{value: 0x45fb, lo: 0xad, hi: 0xad},
{value: 0x4447, lo: 0xae, hi: 0xb1},
{value: 0x4465, lo: 0xb2, hi: 0xb4},
{value: 0x447d, lo: 0xb5, hi: 0xb6},
{value: 0x4489, lo: 0xb8, hi: 0xb8},
{value: 0x4495, lo: 0xb9, hi: 0xbb},
{value: 0x44ad, lo: 0xbc, hi: 0xbc},
{value: 0x44b3, lo: 0xbe, hi: 0xbe},
// Block 0x64, offset 0x1fe
{value: 0x0006, lo: 0x08},
{value: 0x44b9, lo: 0x80, hi: 0x81},
{value: 0x44c5, lo: 0x83, hi: 0x84},
{value: 0x44d7, lo: 0x86, hi: 0x89},
{value: 0x44fb, lo: 0x8a, hi: 0x8a},
{value: 0x4477, lo: 0x8b, hi: 0x8b},
{value: 0x445f, lo: 0x8c, hi: 0x8c},
{value: 0x44a7, lo: 0x8d, hi: 0x8d},
{value: 0x44d1, lo: 0x8e, hi: 0x8e},
// Block 0x65, offset 0x207
{value: 0x0000, lo: 0x02},
{value: 0x8100, lo: 0xa4, hi: 0xa5},
{value: 0x8100, lo: 0xb0, hi: 0xb1},
// Block 0x66, offset 0x20a
{value: 0x0000, lo: 0x02},
{value: 0x8100, lo: 0x9b, hi: 0x9d},
{value: 0x8200, lo: 0x9e, hi: 0xa3},
// Block 0x67, offset 0x20d
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0x90, hi: 0x90},
// Block 0x68, offset 0x20f
{value: 0x0000, lo: 0x02},
{value: 0x8100, lo: 0x99, hi: 0x99},
{value: 0x8200, lo: 0xb2, hi: 0xb4},
// Block 0x69, offset 0x212
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0xbc, hi: 0xbd},
// Block 0x6a, offset 0x214
{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 0x218
{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 0x21d
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0x81, hi: 0x8c},
// Block 0x6d, offset 0x21f
{value: 0x0000, lo: 0x01},
{value: 0x8100, lo: 0xb5, hi: 0xba},
// Block 0x6e, offset 0x221
{value: 0x0000, lo: 0x04},
{value: 0x4cc0, lo: 0x9e, hi: 0x9f},
{value: 0x4cc0, lo: 0xa3, hi: 0xa3},
{value: 0x4cc0, lo: 0xa5, hi: 0xa6},
{value: 0x4cc0, lo: 0xaa, hi: 0xaf},
// Block 0x6f, offset 0x226
{value: 0x0000, lo: 0x05},
{value: 0x4cc0, lo: 0x82, hi: 0x87},
{value: 0x4cc0, lo: 0x8a, hi: 0x8f},
{value: 0x4cc0, lo: 0x92, hi: 0x97},
{value: 0x4cc0, lo: 0x9a, hi: 0x9c},
{value: 0x8100, lo: 0xa3, hi: 0xa3},
// Block 0x70, offset 0x22c
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xbd, hi: 0xbd},
// Block 0x71, offset 0x22e
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xa0, hi: 0xa0},
// Block 0x72, offset 0x230
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb6, hi: 0xba},
// Block 0x73, offset 0x232
{value: 0x0000, lo: 0x04},
{value: 0x410f, lo: 0x89, hi: 0x89},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0xa000, lo: 0x9a, hi: 0x9a},
{value: 0x4117, lo: 0xa4, hi: 0xa4},
// Block 0x74, offset 0x237
{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 0x75, offset 0x23d
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xa5, hi: 0xa5},
{value: 0x812e, lo: 0xa6, hi: 0xa6},
// Block 0x76, offset 0x240
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa4, hi: 0xa7},
// Block 0x77, offset 0x242
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa9, hi: 0xad},
// Block 0x78, offset 0x244
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xab, hi: 0xac},
// Block 0x79, offset 0x246
{value: 0x0000, lo: 0x02},
{value: 0x812e, lo: 0xba, hi: 0xbb},
{value: 0x812e, lo: 0xbd, hi: 0xbf},
// Block 0x7a, offset 0x249
{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 0x7b, offset 0x24f
{value: 0x0005, lo: 0x03},
{value: 0x8133, lo: 0x82, hi: 0x82},
{value: 0x812e, lo: 0x83, hi: 0x84},
{value: 0x812e, lo: 0x85, hi: 0x85},
// Block 0x7c, offset 0x253
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0x86, hi: 0x86},
{value: 0x8105, lo: 0xb0, hi: 0xb0},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x7d, offset 0x257
{value: 0x17fe, lo: 0x07},
{value: 0xa000, lo: 0x99, hi: 0x99},
{value: 0x4287, lo: 0x9a, hi: 0x9a},
{value: 0xa000, lo: 0x9b, hi: 0x9b},
{value: 0x4291, lo: 0x9c, hi: 0x9c},
{value: 0xa000, lo: 0xa5, hi: 0xa5},
{value: 0x429b, lo: 0xab, hi: 0xab},
{value: 0x8105, lo: 0xb9, hi: 0xba},
// Block 0x7e, offset 0x25f
{value: 0x0000, lo: 0x06},
{value: 0x8133, lo: 0x80, hi: 0x82},
{value: 0x9900, lo: 0xa7, hi: 0xa7},
{value: 0x42a5, lo: 0xae, hi: 0xae},
{value: 0x42af, lo: 0xaf, hi: 0xaf},
{value: 0xa000, lo: 0xb1, hi: 0xb2},
{value: 0x8105, lo: 0xb3, hi: 0xb4},
// Block 0x7f, offset 0x266
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x80, hi: 0x80},
{value: 0x8103, lo: 0x8a, hi: 0x8a},
// Block 0x80, offset 0x269
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb5, hi: 0xb5},
{value: 0x8103, lo: 0xb6, hi: 0xb6},
// Block 0x81, offset 0x26c
{value: 0x0002, lo: 0x01},
{value: 0x8103, lo: 0xa9, hi: 0xaa},
// Block 0x82, offset 0x26e
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xbb, hi: 0xbc},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x83, offset 0x271
{value: 0x0000, lo: 0x07},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0x42b9, lo: 0x8b, hi: 0x8b},
{value: 0x42c3, 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 0x84, offset 0x279
{value: 0x5d33, lo: 0x09},
{value: 0xa000, lo: 0x82, hi: 0x82},
{value: 0x42cd, lo: 0x83, hi: 0x84},
{value: 0x42d7, lo: 0x85, hi: 0x85},
{value: 0xa000, lo: 0x8b, hi: 0x8b},
{value: 0x42e1, lo: 0x8e, hi: 0x8e},
{value: 0xa000, lo: 0x90, hi: 0x90},
{value: 0x42eb, lo: 0x91, hi: 0x91},
{value: 0x9900, lo: 0xb8, hi: 0xb8},
{value: 0x9900, lo: 0xbb, hi: 0xbb},
// Block 0x85, offset 0x283
{value: 0x0000, lo: 0x06},
{value: 0xb900, lo: 0x82, hi: 0x82},
{value: 0x4c14, lo: 0x85, hi: 0x85},
{value: 0x4c09, lo: 0x87, hi: 0x87},
{value: 0x4c1f, lo: 0x88, hi: 0x88},
{value: 0x9900, lo: 0x89, hi: 0x89},
{value: 0x8105, lo: 0x8e, hi: 0x90},
// Block 0x86, offset 0x28a
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0x82, hi: 0x82},
{value: 0x8103, lo: 0x86, hi: 0x86},
{value: 0x8133, lo: 0x9e, hi: 0x9e},
// Block 0x87, offset 0x28e
{value: 0x560b, lo: 0x06},
{value: 0x9900, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xb9, hi: 0xb9},
{value: 0x9900, lo: 0xba, hi: 0xba},
{value: 0x42ff, lo: 0xbb, hi: 0xbb},
{value: 0x42f5, lo: 0xbc, hi: 0xbd},
{value: 0x4309, lo: 0xbe, hi: 0xbe},
// Block 0x88, offset 0x295
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x82, hi: 0x82},
{value: 0x8103, lo: 0x83, hi: 0x83},
// Block 0x89, offset 0x298
{value: 0x0000, lo: 0x05},
{value: 0x9900, lo: 0xaf, hi: 0xaf},
{value: 0xa000, lo: 0xb8, hi: 0xb9},
{value: 0x4313, lo: 0xba, hi: 0xba},
{value: 0x431d, lo: 0xbb, hi: 0xbb},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x8a, offset 0x29e
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0x80, hi: 0x80},
// Block 0x8b, offset 0x2a0
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb6, hi: 0xb6},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
// Block 0x8c, offset 0x2a3
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xab, hi: 0xab},
// Block 0x8d, offset 0x2a5
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb9, hi: 0xb9},
{value: 0x8103, lo: 0xba, hi: 0xba},
// Block 0x8e, offset 0x2a8
{value: 0x0000, lo: 0x04},
{value: 0x9900, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xb5, hi: 0xb5},
{value: 0x4327, lo: 0xb8, hi: 0xb8},
{value: 0x8105, lo: 0xbd, hi: 0xbe},
// Block 0x8f, offset 0x2ad
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0x83, hi: 0x83},
// Block 0x90, offset 0x2af
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xa0, hi: 0xa0},
// Block 0x91, offset 0x2b1
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xb4, hi: 0xb4},
// Block 0x92, offset 0x2b3
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x87, hi: 0x87},
// Block 0x93, offset 0x2b5
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x99, hi: 0x99},
// Block 0x94, offset 0x2b7
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0x82, hi: 0x82},
{value: 0x8105, lo: 0x84, hi: 0x85},
// Block 0x95, offset 0x2ba
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x97, hi: 0x97},
// Block 0x96, offset 0x2bc
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x81, hi: 0x82},
// Block 0x97, offset 0x2be
{value: 0x0000, lo: 0x0c},
{value: 0xb900, lo: 0x9e, hi: 0x9e},
{value: 0x9900, lo: 0x9f, hi: 0xa0},
{value: 0x4c83, lo: 0xa1, hi: 0xa1},
{value: 0x4c8e, lo: 0xa2, hi: 0xa2},
{value: 0x4c2a, lo: 0xa3, hi: 0xa3},
{value: 0x4c40, lo: 0xa4, hi: 0xa4},
{value: 0x4c35, lo: 0xa5, hi: 0xa5},
{value: 0x4c56, lo: 0xa6, hi: 0xa6},
{value: 0x4c74, lo: 0xa7, hi: 0xa7},
{value: 0x4c65, lo: 0xa8, hi: 0xa8},
{value: 0xb900, lo: 0xa9, hi: 0xa9},
{value: 0x8105, lo: 0xaf, hi: 0xaf},
// Block 0x98, offset 0x2cb
{value: 0x0000, lo: 0x01},
{value: 0x8101, lo: 0xb0, hi: 0xb4},
// Block 0x99, offset 0x2cd
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb0, hi: 0xb6},
// Block 0x9a, offset 0x2cf
{value: 0x0000, lo: 0x05},
{value: 0xa000, lo: 0xa3, hi: 0xa3},
{value: 0xb900, lo: 0xa7, hi: 0xa7},
{value: 0x4c4b, lo: 0xa8, hi: 0xa8},
{value: 0x4b35, lo: 0xa9, hi: 0xa9},
{value: 0x4347, lo: 0xaa, hi: 0xaa},
// Block 0x9b, offset 0x2d5
{value: 0x0000, lo: 0x01},
{value: 0x8102, lo: 0xb0, hi: 0xb1},
// Block 0x9c, offset 0x2d7
{value: 0x0000, lo: 0x01},
{value: 0x8101, lo: 0x9e, hi: 0x9e},
// Block 0x9d, offset 0x2d9
{value: 0x0000, lo: 0x0c},
{value: 0x4743, lo: 0x9e, hi: 0x9e},
{value: 0x474d, lo: 0x9f, hi: 0x9f},
{value: 0x4781, lo: 0xa0, hi: 0xa0},
{value: 0x478f, lo: 0xa1, hi: 0xa1},
{value: 0x479d, lo: 0xa2, hi: 0xa2},
{value: 0x47ab, lo: 0xa3, hi: 0xa3},
{value: 0x47b9, 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 0x9e, offset 0x2e6
{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: 0x4757, lo: 0xbb, hi: 0xbb},
{value: 0x4761, lo: 0xbc, hi: 0xbc},
{value: 0x47c7, lo: 0xbd, hi: 0xbd},
{value: 0x47e3, lo: 0xbe, hi: 0xbe},
{value: 0x47d5, lo: 0xbf, hi: 0xbf},
// Block 0x9f, offset 0x2f0
{value: 0x0000, lo: 0x01},
{value: 0x47f1, lo: 0x80, hi: 0x80},
// Block 0xa0, offset 0x2f2
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x82, hi: 0x84},
// Block 0xa1, offset 0x2f4
{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 0xa2, offset 0x2fa
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x8f, hi: 0x8f},
// Block 0xa3, offset 0x2fc
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xae, hi: 0xae},
// Block 0xa4, offset 0x2fe
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xac, hi: 0xaf},
// Block 0xa5, offset 0x300
{value: 0x0000, lo: 0x03},
{value: 0x8134, lo: 0xac, hi: 0xad},
{value: 0x812e, lo: 0xae, hi: 0xae},
{value: 0x8133, lo: 0xaf, hi: 0xaf},
// Block 0xa6, offset 0x304
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xae, hi: 0xae},
{value: 0x812e, lo: 0xaf, hi: 0xaf},
// Block 0xa7, offset 0x307
{value: 0x0000, lo: 0x04},
{value: 0x8133, lo: 0xa3, hi: 0xa3},
{value: 0x8133, lo: 0xa6, hi: 0xa6},
{value: 0x8133, lo: 0xae, hi: 0xaf},
{value: 0x8133, lo: 0xb5, hi: 0xb5},
// Block 0xa8, offset 0x30c
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x90, hi: 0x96},
// Block 0xa9, offset 0x30e
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x84, hi: 0x89},
{value: 0x8103, lo: 0x8a, hi: 0x8a},
// Block 0xaa, offset 0x311
{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: 19650 bytes (19.19 KiB). Checksum: 29892d851eed0531.
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: 0x2ece, 0xc1: 0x2ed3, 0xc2: 0x47ff, 0xc3: 0x2ed8, 0xc4: 0x480e, 0xc5: 0x4813,
0xc6: 0xa000, 0xc7: 0x481d, 0xc8: 0x2f41, 0xc9: 0x2f46, 0xca: 0x4822, 0xcb: 0x2f5a,
0xcc: 0x2fcd, 0xcd: 0x2fd2, 0xce: 0x2fd7, 0xcf: 0x4836, 0xd1: 0x3063,
0xd2: 0x3086, 0xd3: 0x308b, 0xd4: 0x4840, 0xd5: 0x4845, 0xd6: 0x4854,
0xd8: 0xa000, 0xd9: 0x3112, 0xda: 0x3117, 0xdb: 0x311c, 0xdc: 0x4886, 0xdd: 0x3194,
0xe0: 0x31da, 0xe1: 0x31df, 0xe2: 0x4890, 0xe3: 0x31e4,
0xe4: 0x489f, 0xe5: 0x48a4, 0xe6: 0xa000, 0xe7: 0x48ae, 0xe8: 0x324d, 0xe9: 0x3252,
0xea: 0x48b3, 0xeb: 0x3266, 0xec: 0x32de, 0xed: 0x32e3, 0xee: 0x32e8, 0xef: 0x48c7,
0xf1: 0x3374, 0xf2: 0x3397, 0xf3: 0x339c, 0xf4: 0x48d1, 0xf5: 0x48d6,
0xf6: 0x48e5, 0xf8: 0xa000, 0xf9: 0x3428, 0xfa: 0x342d, 0xfb: 0x3432,
0xfc: 0x4917, 0xfd: 0x34af, 0xff: 0x34c8,
// Block 0x4, offset 0x100
0x100: 0x2edd, 0x101: 0x31e9, 0x102: 0x4804, 0x103: 0x4895, 0x104: 0x2efb, 0x105: 0x3207,
0x106: 0x2f0f, 0x107: 0x321b, 0x108: 0x2f14, 0x109: 0x3220, 0x10a: 0x2f19, 0x10b: 0x3225,
0x10c: 0x2f1e, 0x10d: 0x322a, 0x10e: 0x2f28, 0x10f: 0x3234,
0x112: 0x4827, 0x113: 0x48b8, 0x114: 0x2f50, 0x115: 0x325c, 0x116: 0x2f55, 0x117: 0x3261,
0x118: 0x2f73, 0x119: 0x327f, 0x11a: 0x2f64, 0x11b: 0x3270, 0x11c: 0x2f8c, 0x11d: 0x3298,
0x11e: 0x2f96, 0x11f: 0x32a2, 0x120: 0x2f9b, 0x121: 0x32a7, 0x122: 0x2fa5, 0x123: 0x32b1,
0x124: 0x2faa, 0x125: 0x32b6, 0x128: 0x2fdc, 0x129: 0x32ed,
0x12a: 0x2fe1, 0x12b: 0x32f2, 0x12c: 0x2fe6, 0x12d: 0x32f7, 0x12e: 0x3009, 0x12f: 0x3315,
0x130: 0x2feb, 0x132: 0x1a8a, 0x133: 0x1b17, 0x134: 0x3013, 0x135: 0x331f,
0x136: 0x3027, 0x137: 0x3338, 0x139: 0x3031, 0x13a: 0x3342, 0x13b: 0x303b,
0x13c: 0x334c, 0x13d: 0x3036, 0x13e: 0x3347, 0x13f: 0x1cdc,
// Block 0x5, offset 0x140
0x140: 0x1d64, 0x143: 0x305e, 0x144: 0x336f, 0x145: 0x3077,
0x146: 0x3388, 0x147: 0x306d, 0x148: 0x337e, 0x149: 0x1d8c,
0x14c: 0x484a, 0x14d: 0x48db, 0x14e: 0x3090, 0x14f: 0x33a1, 0x150: 0x309a, 0x151: 0x33ab,
0x154: 0x30b8, 0x155: 0x33c9, 0x156: 0x30d1, 0x157: 0x33e2,
0x158: 0x30c2, 0x159: 0x33d3, 0x15a: 0x486d, 0x15b: 0x48fe, 0x15c: 0x30db, 0x15d: 0x33ec,
0x15e: 0x30ea, 0x15f: 0x33fb, 0x160: 0x4872, 0x161: 0x4903, 0x162: 0x3103, 0x163: 0x3419,
0x164: 0x30f4, 0x165: 0x340a, 0x168: 0x487c, 0x169: 0x490d,
0x16a: 0x4881, 0x16b: 0x4912, 0x16c: 0x3121, 0x16d: 0x3437, 0x16e: 0x312b, 0x16f: 0x3441,
0x170: 0x3130, 0x171: 0x3446, 0x172: 0x314e, 0x173: 0x3464, 0x174: 0x3171, 0x175: 0x3487,
0x176: 0x3199, 0x177: 0x34b4, 0x178: 0x31ad, 0x179: 0x31bc, 0x17a: 0x34dc, 0x17b: 0x31c6,
0x17c: 0x34e6, 0x17d: 0x31cb, 0x17e: 0x34eb, 0x17f: 0x00a7,
// Block 0x6, offset 0x180
0x184: 0x2dd5, 0x185: 0x2ddb,
0x186: 0x2de1, 0x187: 0x1a9f, 0x188: 0x1aa2, 0x189: 0x1b38, 0x18a: 0x1ab7, 0x18b: 0x1aba,
0x18c: 0x1b6e, 0x18d: 0x2ee7, 0x18e: 0x31f3, 0x18f: 0x2ff5, 0x190: 0x3301, 0x191: 0x309f,
0x192: 0x33b0, 0x193: 0x3135, 0x194: 0x344b, 0x195: 0x392e, 0x196: 0x3abd, 0x197: 0x3927,
0x198: 0x3ab6, 0x199: 0x3935, 0x19a: 0x3ac4, 0x19b: 0x3920, 0x19c: 0x3aaf,
0x19e: 0x380f, 0x19f: 0x399e, 0x1a0: 0x3808, 0x1a1: 0x3997, 0x1a2: 0x3512, 0x1a3: 0x3524,
0x1a6: 0x2fa0, 0x1a7: 0x32ac, 0x1a8: 0x301d, 0x1a9: 0x332e,
0x1aa: 0x4863, 0x1ab: 0x48f4, 0x1ac: 0x38ef, 0x1ad: 0x3a7e, 0x1ae: 0x3536, 0x1af: 0x353c,
0x1b0: 0x3324, 0x1b1: 0x1a6f, 0x1b2: 0x1a72, 0x1b3: 0x1aff, 0x1b4: 0x2f87, 0x1b5: 0x3293,
0x1b8: 0x3059, 0x1b9: 0x336a, 0x1ba: 0x3816, 0x1bb: 0x39a5,
0x1bc: 0x350c, 0x1bd: 0x351e, 0x1be: 0x3518, 0x1bf: 0x352a,
// Block 0x7, offset 0x1c0
0x1c0: 0x2eec, 0x1c1: 0x31f8, 0x1c2: 0x2ef1, 0x1c3: 0x31fd, 0x1c4: 0x2f69, 0x1c5: 0x3275,
0x1c6: 0x2f6e, 0x1c7: 0x327a, 0x1c8: 0x2ffa, 0x1c9: 0x3306, 0x1ca: 0x2fff, 0x1cb: 0x330b,
0x1cc: 0x30a4, 0x1cd: 0x33b5, 0x1ce: 0x30a9, 0x1cf: 0x33ba, 0x1d0: 0x30c7, 0x1d1: 0x33d8,
0x1d2: 0x30cc, 0x1d3: 0x33dd, 0x1d4: 0x313a, 0x1d5: 0x3450, 0x1d6: 0x313f, 0x1d7: 0x3455,
0x1d8: 0x30e5, 0x1d9: 0x33f6, 0x1da: 0x30fe, 0x1db: 0x3414,
0x1de: 0x2fb9, 0x1df: 0x32c5,
0x1e6: 0x4809, 0x1e7: 0x489a, 0x1e8: 0x4831, 0x1e9: 0x48c2,
0x1ea: 0x38be, 0x1eb: 0x3a4d, 0x1ec: 0x389b, 0x1ed: 0x3a2a, 0x1ee: 0x484f, 0x1ef: 0x48e0,
0x1f0: 0x38b7, 0x1f1: 0x3a46, 0x1f2: 0x31a3, 0x1f3: 0x34be,
// 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: 0x4b3f, 0x241: 0x4b44, 0x242: 0x9933, 0x243: 0x4b49, 0x244: 0x4c02, 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: 0x43a4,
0x27e: 0x0037,
// Block 0xa, offset 0x280
0x284: 0x4359, 0x285: 0x457a,
0x286: 0x3548, 0x287: 0x00ce, 0x288: 0x3566, 0x289: 0x3572, 0x28a: 0x3584,
0x28c: 0x35a2, 0x28e: 0x35b4, 0x28f: 0x35d2, 0x290: 0x3d67, 0x291: 0xa000,
0x295: 0xa000, 0x297: 0xa000,
0x299: 0xa000,
0x29f: 0xa000, 0x2a1: 0xa000,
0x2a5: 0xa000, 0x2a9: 0xa000,
0x2aa: 0x3596, 0x2ab: 0x35c6, 0x2ac: 0x4975, 0x2ad: 0x35f6, 0x2ae: 0x499f, 0x2af: 0x3608,
0x2b0: 0x3dcf, 0x2b1: 0xa000, 0x2b5: 0xa000,
0x2b7: 0xa000, 0x2b9: 0xa000,
0x2bf: 0xa000,
// Block 0xb, offset 0x2c0
0x2c1: 0xa000, 0x2c5: 0xa000,
0x2c9: 0xa000, 0x2ca: 0x49b7, 0x2cb: 0x49d5,
0x2cc: 0x3626, 0x2cd: 0x363e, 0x2ce: 0x49ed, 0x2d0: 0x0242, 0x2d1: 0x0254,
0x2d2: 0x0230, 0x2d3: 0x440b, 0x2d4: 0x4411, 0x2d5: 0x027e, 0x2d6: 0x026c,
0x2f0: 0x025a, 0x2f1: 0x026f, 0x2f2: 0x0272, 0x2f4: 0x020c, 0x2f5: 0x024b,
0x2f9: 0x022a,
// Block 0xc, offset 0x300
0x300: 0x3680, 0x301: 0x368c, 0x303: 0x367a,
0x306: 0xa000, 0x307: 0x3668,
0x30c: 0x36bc, 0x30d: 0x36a4, 0x30e: 0x36ce, 0x310: 0xa000,
0x313: 0xa000, 0x315: 0xa000, 0x316: 0xa000, 0x317: 0xa000,
0x318: 0xa000, 0x319: 0x36b0, 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: 0x3734, 0x33a: 0xa000,
0x33e: 0xa000,
// Block 0xd, offset 0x340
0x341: 0x3692, 0x342: 0x3716,
0x350: 0x366e, 0x351: 0x36f2,
0x352: 0x3674, 0x353: 0x36f8, 0x356: 0x3686, 0x357: 0x370a,
0x358: 0xa000, 0x359: 0xa000, 0x35a: 0x3788, 0x35b: 0x378e, 0x35c: 0x3698, 0x35d: 0x371c,
0x35e: 0x369e, 0x35f: 0x3722, 0x362: 0x36aa, 0x363: 0x372e,
0x364: 0x36b6, 0x365: 0x373a, 0x366: 0x36c2, 0x367: 0x3746, 0x368: 0xa000, 0x369: 0xa000,
0x36a: 0x3794, 0x36b: 0x379a, 0x36c: 0x36ec, 0x36d: 0x3770, 0x36e: 0x36c8, 0x36f: 0x374c,
0x370: 0x36d4, 0x371: 0x3758, 0x372: 0x36da, 0x373: 0x375e, 0x374: 0x36e0, 0x375: 0x3764,
0x378: 0x36e6, 0x379: 0x376a,
// 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: 0x3ee7, 0x447: 0xa000, 0x448: 0x3eef, 0x449: 0xa000, 0x44a: 0x3ef7, 0x44b: 0xa000,
0x44c: 0x3eff, 0x44d: 0xa000, 0x44e: 0x3f07, 0x451: 0xa000,
0x452: 0x3f0f,
0x474: 0x8103, 0x475: 0x9900,
0x47a: 0xa000, 0x47b: 0x3f17,
0x47c: 0xa000, 0x47d: 0x3f1f, 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: 0x2ef6, 0x541: 0x3202, 0x542: 0x2f00, 0x543: 0x320c, 0x544: 0x2f05, 0x545: 0x3211,
0x546: 0x2f0a, 0x547: 0x3216, 0x548: 0x382b, 0x549: 0x39ba, 0x54a: 0x2f23, 0x54b: 0x322f,
0x54c: 0x2f2d, 0x54d: 0x3239, 0x54e: 0x2f3c, 0x54f: 0x3248, 0x550: 0x2f32, 0x551: 0x323e,
0x552: 0x2f37, 0x553: 0x3243, 0x554: 0x384e, 0x555: 0x39dd, 0x556: 0x3855, 0x557: 0x39e4,
0x558: 0x2f78, 0x559: 0x3284, 0x55a: 0x2f7d, 0x55b: 0x3289, 0x55c: 0x3863, 0x55d: 0x39f2,
0x55e: 0x2f82, 0x55f: 0x328e, 0x560: 0x2f91, 0x561: 0x329d, 0x562: 0x2faf, 0x563: 0x32bb,
0x564: 0x2fbe, 0x565: 0x32ca, 0x566: 0x2fb4, 0x567: 0x32c0, 0x568: 0x2fc3, 0x569: 0x32cf,
0x56a: 0x2fc8, 0x56b: 0x32d4, 0x56c: 0x300e, 0x56d: 0x331a, 0x56e: 0x386a, 0x56f: 0x39f9,
0x570: 0x3018, 0x571: 0x3329, 0x572: 0x3022, 0x573: 0x3333, 0x574: 0x302c, 0x575: 0x333d,
0x576: 0x483b, 0x577: 0x48cc, 0x578: 0x3871, 0x579: 0x3a00, 0x57a: 0x3045, 0x57b: 0x3356,
0x57c: 0x3040, 0x57d: 0x3351, 0x57e: 0x304a, 0x57f: 0x335b,
// Block 0x16, offset 0x580
0x580: 0x304f, 0x581: 0x3360, 0x582: 0x3054, 0x583: 0x3365, 0x584: 0x3068, 0x585: 0x3379,
0x586: 0x3072, 0x587: 0x3383, 0x588: 0x3081, 0x589: 0x3392, 0x58a: 0x307c, 0x58b: 0x338d,
0x58c: 0x3894, 0x58d: 0x3a23, 0x58e: 0x38a2, 0x58f: 0x3a31, 0x590: 0x38a9, 0x591: 0x3a38,
0x592: 0x38b0, 0x593: 0x3a3f, 0x594: 0x30ae, 0x595: 0x33bf, 0x596: 0x30b3, 0x597: 0x33c4,
0x598: 0x30bd, 0x599: 0x33ce, 0x59a: 0x4868, 0x59b: 0x48f9, 0x59c: 0x38f6, 0x59d: 0x3a85,
0x59e: 0x30d6, 0x59f: 0x33e7, 0x5a0: 0x30e0, 0x5a1: 0x33f1, 0x5a2: 0x4877, 0x5a3: 0x4908,
0x5a4: 0x38fd, 0x5a5: 0x3a8c, 0x5a6: 0x3904, 0x5a7: 0x3a93, 0x5a8: 0x390b, 0x5a9: 0x3a9a,
0x5aa: 0x30ef, 0x5ab: 0x3400, 0x5ac: 0x30f9, 0x5ad: 0x340f, 0x5ae: 0x310d, 0x5af: 0x3423,
0x5b0: 0x3108, 0x5b1: 0x341e, 0x5b2: 0x3149, 0x5b3: 0x345f, 0x5b4: 0x3158, 0x5b5: 0x346e,
0x5b6: 0x3153, 0x5b7: 0x3469, 0x5b8: 0x3912, 0x5b9: 0x3aa1, 0x5ba: 0x3919, 0x5bb: 0x3aa8,
0x5bc: 0x315d, 0x5bd: 0x3473, 0x5be: 0x3162, 0x5bf: 0x3478,
// Block 0x17, offset 0x5c0
0x5c0: 0x3167, 0x5c1: 0x347d, 0x5c2: 0x316c, 0x5c3: 0x3482, 0x5c4: 0x317b, 0x5c5: 0x3491,
0x5c6: 0x3176, 0x5c7: 0x348c, 0x5c8: 0x3180, 0x5c9: 0x349b, 0x5ca: 0x3185, 0x5cb: 0x34a0,
0x5cc: 0x318a, 0x5cd: 0x34a5, 0x5ce: 0x31a8, 0x5cf: 0x34c3, 0x5d0: 0x31c1, 0x5d1: 0x34e1,
0x5d2: 0x31d0, 0x5d3: 0x34f0, 0x5d4: 0x31d5, 0x5d5: 0x34f5, 0x5d6: 0x32d9, 0x5d7: 0x3405,
0x5d8: 0x3496, 0x5d9: 0x34d2, 0x5da: 0x1d10, 0x5db: 0x43d6,
0x5e0: 0x4818, 0x5e1: 0x48a9, 0x5e2: 0x2ee2, 0x5e3: 0x31ee,
0x5e4: 0x37d7, 0x5e5: 0x3966, 0x5e6: 0x37d0, 0x5e7: 0x395f, 0x5e8: 0x37e5, 0x5e9: 0x3974,
0x5ea: 0x37de, 0x5eb: 0x396d, 0x5ec: 0x381d, 0x5ed: 0x39ac, 0x5ee: 0x37f3, 0x5ef: 0x3982,
0x5f0: 0x37ec, 0x5f1: 0x397b, 0x5f2: 0x3801, 0x5f3: 0x3990, 0x5f4: 0x37fa, 0x5f5: 0x3989,
0x5f6: 0x3824, 0x5f7: 0x39b3, 0x5f8: 0x482c, 0x5f9: 0x48bd, 0x5fa: 0x2f5f, 0x5fb: 0x326b,
0x5fc: 0x2f4b, 0x5fd: 0x3257, 0x5fe: 0x3839, 0x5ff: 0x39c8,
// Block 0x18, offset 0x600
0x600: 0x3832, 0x601: 0x39c1, 0x602: 0x3847, 0x603: 0x39d6, 0x604: 0x3840, 0x605: 0x39cf,
0x606: 0x385c, 0x607: 0x39eb, 0x608: 0x2ff0, 0x609: 0x32fc, 0x60a: 0x3004, 0x60b: 0x3310,
0x60c: 0x485e, 0x60d: 0x48ef, 0x60e: 0x3095, 0x60f: 0x33a6, 0x610: 0x387f, 0x611: 0x3a0e,
0x612: 0x3878, 0x613: 0x3a07, 0x614: 0x388d, 0x615: 0x3a1c, 0x616: 0x3886, 0x617: 0x3a15,
0x618: 0x38e8, 0x619: 0x3a77, 0x61a: 0x38cc, 0x61b: 0x3a5b, 0x61c: 0x38c5, 0x61d: 0x3a54,
0x61e: 0x38da, 0x61f: 0x3a69, 0x620: 0x38d3, 0x621: 0x3a62, 0x622: 0x38e1, 0x623: 0x3a70,
0x624: 0x3144, 0x625: 0x345a, 0x626: 0x3126, 0x627: 0x343c, 0x628: 0x3943, 0x629: 0x3ad2,
0x62a: 0x393c, 0x62b: 0x3acb, 0x62c: 0x3951, 0x62d: 0x3ae0, 0x62e: 0x394a, 0x62f: 0x3ad9,
0x630: 0x3958, 0x631: 0x3ae7, 0x632: 0x318f, 0x633: 0x34aa, 0x634: 0x31b7, 0x635: 0x34d7,
0x636: 0x31b2, 0x637: 0x34cd, 0x638: 0x319e, 0x639: 0x34b9,
// Block 0x19, offset 0x640
0x640: 0x497b, 0x641: 0x4981, 0x642: 0x4a95, 0x643: 0x4aad, 0x644: 0x4a9d, 0x645: 0x4ab5,
0x646: 0x4aa5, 0x647: 0x4abd, 0x648: 0x4921, 0x649: 0x4927, 0x64a: 0x4a05, 0x64b: 0x4a1d,
0x64c: 0x4a0d, 0x64d: 0x4a25, 0x64e: 0x4a15, 0x64f: 0x4a2d, 0x650: 0x498d, 0x651: 0x4993,
0x652: 0x3d17, 0x653: 0x3d27, 0x654: 0x3d1f, 0x655: 0x3d2f,
0x658: 0x492d, 0x659: 0x4933, 0x65a: 0x3c47, 0x65b: 0x3c57, 0x65c: 0x3c4f, 0x65d: 0x3c5f,
0x660: 0x49a5, 0x661: 0x49ab, 0x662: 0x4ac5, 0x663: 0x4add,
0x664: 0x4acd, 0x665: 0x4ae5, 0x666: 0x4ad5, 0x667: 0x4aed, 0x668: 0x4939, 0x669: 0x493f,
0x66a: 0x4a35, 0x66b: 0x4a4d, 0x66c: 0x4a3d, 0x66d: 0x4a55, 0x66e: 0x4a45, 0x66f: 0x4a5d,
0x670: 0x49bd, 0x671: 0x49c3, 0x672: 0x3d77, 0x673: 0x3d8f, 0x674: 0x3d7f, 0x675: 0x3d97,
0x676: 0x3d87, 0x677: 0x3d9f, 0x678: 0x4945, 0x679: 0x494b, 0x67a: 0x3c77, 0x67b: 0x3c8f,
0x67c: 0x3c7f, 0x67d: 0x3c97, 0x67e: 0x3c87, 0x67f: 0x3c9f,
// Block 0x1a, offset 0x680
0x680: 0x49c9, 0x681: 0x49cf, 0x682: 0x3da7, 0x683: 0x3db7, 0x684: 0x3daf, 0x685: 0x3dbf,
0x688: 0x4951, 0x689: 0x4957, 0x68a: 0x3ca7, 0x68b: 0x3cb7,
0x68c: 0x3caf, 0x68d: 0x3cbf, 0x690: 0x49db, 0x691: 0x49e1,
0x692: 0x3ddf, 0x693: 0x3df7, 0x694: 0x3de7, 0x695: 0x3dff, 0x696: 0x3def, 0x697: 0x3e07,
0x699: 0x495d, 0x69b: 0x3cc7, 0x69d: 0x3ccf,
0x69f: 0x3cd7, 0x6a0: 0x49f3, 0x6a1: 0x49f9, 0x6a2: 0x4af5, 0x6a3: 0x4b0d,
0x6a4: 0x4afd, 0x6a5: 0x4b15, 0x6a6: 0x4b05, 0x6a7: 0x4b1d, 0x6a8: 0x4963, 0x6a9: 0x4969,
0x6aa: 0x4a65, 0x6ab: 0x4a7d, 0x6ac: 0x4a6d, 0x6ad: 0x4a85, 0x6ae: 0x4a75, 0x6af: 0x4a8d,
0x6b0: 0x496f, 0x6b1: 0x441d, 0x6b2: 0x35f0, 0x6b3: 0x4423, 0x6b4: 0x4999, 0x6b5: 0x4429,
0x6b6: 0x3602, 0x6b7: 0x442f, 0x6b8: 0x3620, 0x6b9: 0x4435, 0x6ba: 0x3638, 0x6bb: 0x443b,
0x6bc: 0x49e7, 0x6bd: 0x4441,
// Block 0x1b, offset 0x6c0
0x6c0: 0x3cff, 0x6c1: 0x3d07, 0x6c2: 0x41d3, 0x6c3: 0x41f1, 0x6c4: 0x41dd, 0x6c5: 0x41fb,
0x6c6: 0x41e7, 0x6c7: 0x4205, 0x6c8: 0x3c37, 0x6c9: 0x3c3f, 0x6ca: 0x411f, 0x6cb: 0x413d,
0x6cc: 0x4129, 0x6cd: 0x4147, 0x6ce: 0x4133, 0x6cf: 0x4151, 0x6d0: 0x3d47, 0x6d1: 0x3d4f,
0x6d2: 0x420f, 0x6d3: 0x422d, 0x6d4: 0x4219, 0x6d5: 0x4237, 0x6d6: 0x4223, 0x6d7: 0x4241,
0x6d8: 0x3c67, 0x6d9: 0x3c6f, 0x6da: 0x415b, 0x6db: 0x4179, 0x6dc: 0x4165, 0x6dd: 0x4183,
0x6de: 0x416f, 0x6df: 0x418d, 0x6e0: 0x3e1f, 0x6e1: 0x3e27, 0x6e2: 0x424b, 0x6e3: 0x4269,
0x6e4: 0x4255, 0x6e5: 0x4273, 0x6e6: 0x425f, 0x6e7: 0x427d, 0x6e8: 0x3cdf, 0x6e9: 0x3ce7,
0x6ea: 0x4197, 0x6eb: 0x41b5, 0x6ec: 0x41a1, 0x6ed: 0x41bf, 0x6ee: 0x41ab, 0x6ef: 0x41c9,
0x6f0: 0x35e4, 0x6f1: 0x35de, 0x6f2: 0x3cef, 0x6f3: 0x35ea, 0x6f4: 0x3cf7,
0x6f6: 0x4987, 0x6f7: 0x3d0f, 0x6f8: 0x3554, 0x6f9: 0x354e, 0x6fa: 0x3542, 0x6fb: 0x43ed,
0x6fc: 0x355a, 0x6fd: 0x4386, 0x6fe: 0x0257, 0x6ff: 0x4386,
// Block 0x1c, offset 0x700
0x700: 0x439f, 0x701: 0x4581, 0x702: 0x3d37, 0x703: 0x35fc, 0x704: 0x3d3f,
0x706: 0x49b1, 0x707: 0x3d57, 0x708: 0x3560, 0x709: 0x43f3, 0x70a: 0x356c, 0x70b: 0x43f9,
0x70c: 0x3578, 0x70d: 0x4588, 0x70e: 0x458f, 0x70f: 0x4596, 0x710: 0x3614, 0x711: 0x360e,
0x712: 0x3d5f, 0x713: 0x45e3, 0x716: 0x361a, 0x717: 0x3d6f,
0x718: 0x3590, 0x719: 0x358a, 0x71a: 0x357e, 0x71b: 0x43ff, 0x71d: 0x459d,
0x71e: 0x45a4, 0x71f: 0x45ab, 0x720: 0x364a, 0x721: 0x3644, 0x722: 0x3dc7, 0x723: 0x45eb,
0x724: 0x362c, 0x725: 0x3632, 0x726: 0x3650, 0x727: 0x3dd7, 0x728: 0x35c0, 0x729: 0x35ba,
0x72a: 0x35ae, 0x72b: 0x440b, 0x72c: 0x35a8, 0x72d: 0x4573, 0x72e: 0x457a, 0x72f: 0x0081,
0x732: 0x3e0f, 0x733: 0x3656, 0x734: 0x3e17,
0x736: 0x49ff, 0x737: 0x3e2f, 0x738: 0x359c, 0x739: 0x4405, 0x73a: 0x35cc, 0x73b: 0x4417,
0x73c: 0x35d8, 0x73d: 0x4359, 0x73e: 0x438b,
// 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: 0x43d1, 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: 0x3b65, 0x7c3: 0xa000, 0x7c4: 0x3b6c, 0x7c5: 0xa000,
0x7c7: 0x3b73, 0x7c8: 0xa000, 0x7c9: 0x3b7a,
0x7cd: 0xa000,
0x7e0: 0x2ec4, 0x7e1: 0xa000, 0x7e2: 0x3b88,
0x7e4: 0xa000, 0x7e5: 0xa000,
0x7ed: 0x3b81, 0x7ee: 0x2ebf, 0x7ef: 0x2ec9,
0x7f0: 0x3b8f, 0x7f1: 0x3b96, 0x7f2: 0xa000, 0x7f3: 0xa000, 0x7f4: 0x3b9d, 0x7f5: 0x3ba4,
0x7f6: 0xa000, 0x7f7: 0xa000, 0x7f8: 0x3bab, 0x7f9: 0x3bb2, 0x7fa: 0xa000, 0x7fb: 0xa000,
0x7fc: 0xa000, 0x7fd: 0xa000,
// Block 0x20, offset 0x800
0x800: 0x3bb9, 0x801: 0x3bc0, 0x802: 0xa000, 0x803: 0xa000, 0x804: 0x3bd5, 0x805: 0x3bdc,
0x806: 0xa000, 0x807: 0xa000, 0x808: 0x3be3, 0x809: 0x3bea,
0x811: 0xa000,
0x812: 0xa000,
0x822: 0xa000,
0x828: 0xa000, 0x829: 0xa000,
0x82b: 0xa000, 0x82c: 0x3bff, 0x82d: 0x3c06, 0x82e: 0x3c0d, 0x82f: 0x3c14,
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: 0x3f47, 0x98d: 0xa000, 0x98e: 0x3f4f, 0x98f: 0xa000, 0x990: 0x3f57, 0x991: 0xa000,
0x992: 0x3f5f, 0x993: 0xa000, 0x994: 0x3f67, 0x995: 0xa000, 0x996: 0x3f6f, 0x997: 0xa000,
0x998: 0x3f77, 0x999: 0xa000, 0x99a: 0x3f7f, 0x99b: 0xa000, 0x99c: 0x3f87, 0x99d: 0xa000,
0x99e: 0x3f8f, 0x99f: 0xa000, 0x9a0: 0x3f97, 0x9a1: 0xa000, 0x9a2: 0x3f9f,
0x9a4: 0xa000, 0x9a5: 0x3fa7, 0x9a6: 0xa000, 0x9a7: 0x3faf, 0x9a8: 0xa000, 0x9a9: 0x3fb7,
0x9af: 0xa000,
0x9b0: 0x3fbf, 0x9b1: 0x3fc7, 0x9b2: 0xa000, 0x9b3: 0x3fcf, 0x9b4: 0x3fd7, 0x9b5: 0xa000,
0x9b6: 0x3fdf, 0x9b7: 0x3fe7, 0x9b8: 0xa000, 0x9b9: 0x3fef, 0x9ba: 0x3ff7, 0x9bb: 0xa000,
0x9bc: 0x3fff, 0x9bd: 0x4007,
// Block 0x27, offset 0x9c0
0x9d4: 0x3f3f,
0x9d9: 0x9904, 0x9da: 0x9904, 0x9db: 0x43db, 0x9dc: 0x43e1, 0x9dd: 0xa000,
0x9de: 0x400f, 0x9df: 0x27e4,
0x9e6: 0xa000,
0x9eb: 0xa000, 0x9ec: 0x401f, 0x9ed: 0xa000, 0x9ee: 0x4027, 0x9ef: 0xa000,
0x9f0: 0x402f, 0x9f1: 0xa000, 0x9f2: 0x4037, 0x9f3: 0xa000, 0x9f4: 0x403f, 0x9f5: 0xa000,
0x9f6: 0x4047, 0x9f7: 0xa000, 0x9f8: 0x404f, 0x9f9: 0xa000, 0x9fa: 0x4057, 0x9fb: 0xa000,
0x9fc: 0x405f, 0x9fd: 0xa000, 0x9fe: 0x4067, 0x9ff: 0xa000,
// Block 0x28, offset 0xa00
0xa00: 0x406f, 0xa01: 0xa000, 0xa02: 0x4077, 0xa04: 0xa000, 0xa05: 0x407f,
0xa06: 0xa000, 0xa07: 0x4087, 0xa08: 0xa000, 0xa09: 0x408f,
0xa0f: 0xa000, 0xa10: 0x4097, 0xa11: 0x409f,
0xa12: 0xa000, 0xa13: 0x40a7, 0xa14: 0x40af, 0xa15: 0xa000, 0xa16: 0x40b7, 0xa17: 0x40bf,
0xa18: 0xa000, 0xa19: 0x40c7, 0xa1a: 0x40cf, 0xa1b: 0xa000, 0xa1c: 0x40d7, 0xa1d: 0x40df,
0xa2f: 0xa000,
0xa30: 0xa000, 0xa31: 0xa000, 0xa32: 0xa000, 0xa34: 0x4017,
0xa37: 0x40e7, 0xa38: 0x40ef, 0xa39: 0x40f7, 0xa3a: 0x40ff,
0xa3d: 0xa000, 0xa3e: 0x4107, 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: 0x4b4e, 0xa50: 0x4b54, 0xa51: 0x4b5a,
0xa52: 0x4b60, 0xa53: 0x4b66, 0xa54: 0x4b6c, 0xa55: 0x4b72, 0xa56: 0x4b78, 0xa57: 0x4b7e,
0xa58: 0x4b84, 0xa59: 0x4b8a, 0xa5a: 0x4b90, 0xa5b: 0x4b96, 0xa5c: 0x4b9c, 0xa5d: 0x4ba2,
0xa5e: 0x4ba8, 0xa5f: 0x4bae, 0xa60: 0x4bb4, 0xa61: 0x4bba, 0xa62: 0x4bc0, 0xa63: 0x4bc6,
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: 0x46c3, 0xb2f: 0x46cb,
0xb30: 0x46d3, 0xb31: 0x46db, 0xb32: 0x46e3, 0xb33: 0x46eb, 0xb34: 0x46f3, 0xb35: 0x46fb,
0xb36: 0x470b, 0xb37: 0x4713, 0xb38: 0x471b, 0xb39: 0x4723, 0xb3a: 0x472b, 0xb3b: 0x4733,
0xb3c: 0x2e42, 0xb3d: 0x2e0a, 0xb3e: 0x4703,
// 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: 0x2e53, 0xbc5: 0x29c1,
0xbc6: 0x29cb, 0xbc7: 0x2e97, 0xbc8: 0x2aec, 0xbc9: 0x29d5, 0xbca: 0x29df, 0xbcb: 0x29e9,
0xbcc: 0x2b13, 0xbcd: 0x2b20, 0xbce: 0x2af9, 0xbcf: 0x2b06, 0xbd0: 0x2e18, 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: 0x2e26, 0xbdf: 0x2b61, 0xbe0: 0x2c73, 0xbe1: 0x2e64, 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: 0x2eab, 0xbf3: 0x2b95, 0xbf4: 0x2d7a, 0xbf5: 0x2a57,
0xbf6: 0x2c93, 0xbf7: 0x2a61, 0xbf8: 0x2baf, 0xbf9: 0x2a6b, 0xbfa: 0x2bbc, 0xbfb: 0x2e75,
0xbfc: 0x2ba2, 0xbfd: 0x2ca3, 0xbfe: 0x2bc9, 0xbff: 0x280e,
// Block 0x30, offset 0xc00
0xc00: 0x2e86, 0xc01: 0x2a75, 0xc02: 0x2a7f, 0xc03: 0x2bd6, 0xc04: 0x2a89, 0xc05: 0x2a93,
0xc06: 0x2a9d, 0xc07: 0x2cb3, 0xc08: 0x2be3, 0xc09: 0x2815, 0xc0a: 0x2d8d, 0xc0b: 0x2dff,
0xc0c: 0x2cc3, 0xc0d: 0x2bf0, 0xc0e: 0x2e34, 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: 0x448f,
0xede: 0x8116, 0xedf: 0x4501, 0xee0: 0x0320, 0xee1: 0x0308, 0xee2: 0x0311, 0xee3: 0x0314,
0xee4: 0x0317, 0xee5: 0x031a, 0xee6: 0x031d, 0xee7: 0x0323, 0xee8: 0x0326, 0xee9: 0x0017,
0xeea: 0x44ef, 0xeeb: 0x44f5, 0xeec: 0x45f3, 0xeed: 0x45fb, 0xeee: 0x4447, 0xeef: 0x444d,
0xef0: 0x4453, 0xef1: 0x4459, 0xef2: 0x4465, 0xef3: 0x446b, 0xef4: 0x4471, 0xef5: 0x447d,
0xef6: 0x4483, 0xef8: 0x4489, 0xef9: 0x4495, 0xefa: 0x449b, 0xefb: 0x44a1,
0xefc: 0x44ad, 0xefe: 0x44b3,
// Block 0x3c, offset 0xf00
0xf00: 0x44b9, 0xf01: 0x44bf, 0xf03: 0x44c5, 0xf04: 0x44cb,
0xf06: 0x44d7, 0xf07: 0x44dd, 0xf08: 0x44e3, 0xf09: 0x44e9, 0xf0a: 0x44fb, 0xf0b: 0x4477,
0xf0c: 0x445f, 0xf0d: 0x44a7, 0xf0e: 0x44d1, 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: 0x456d, 0xf65: 0x456d, 0xf66: 0x03e0, 0xf67: 0x03e0, 0xf68: 0x03e0, 0xf69: 0x03e0,
0xf6a: 0x03dd, 0xf6b: 0x03dd, 0xf6c: 0x03dd, 0xf6d: 0x03dd, 0xf6e: 0x03fb, 0xf6f: 0x03fb,
0xf70: 0x4567, 0xf71: 0x4567,
// 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: 0x451f, 0x101c: 0x4525, 0x101d: 0x455b,
0x101e: 0x45b2, 0x101f: 0x45b9, 0x1020: 0x45c0, 0x1021: 0x45c7, 0x1022: 0x45ce, 0x1023: 0x45d5,
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: 0x455b, 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: 0x454f, 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: 0x4603, 0x10b3: 0x460b, 0x10b4: 0x4613, 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: 0x4507, 0x10fd: 0x4507,
// 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: 0x4368, 0x120a: 0x4368, 0x120b: 0x4368,
0x120c: 0x4368, 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: 0x43a9, 0x1231: 0x452b, 0x1232: 0x43ae, 0x1234: 0x43b3,
0x1236: 0x43b8, 0x1237: 0x4531, 0x1238: 0x43bd, 0x1239: 0x4537, 0x123a: 0x43c2, 0x123b: 0x453d,
0x123c: 0x43c7, 0x123d: 0x4543, 0x123e: 0x43cc, 0x123f: 0x4549,
// Block 0x49, offset 0x1240
0x1240: 0x0329, 0x1241: 0x450d, 0x1242: 0x450d, 0x1243: 0x4513, 0x1244: 0x4513, 0x1245: 0x4555,
0x1246: 0x4555, 0x1247: 0x4519, 0x1248: 0x4519, 0x1249: 0x4561, 0x124a: 0x4561, 0x124b: 0x4561,
0x124c: 0x4561, 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: 0x2de7,
0x12b6: 0x2de7, 0x12b7: 0x2def, 0x12b8: 0x2def, 0x12b9: 0x2df7, 0x12ba: 0x2df7, 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: 0x4c99, 0x131f: 0x4c9f, 0x1320: 0x04b6, 0x1321: 0x0406, 0x1322: 0x040a, 0x1323: 0x4bcc,
0x1324: 0x040e, 0x1325: 0x4bd2, 0x1326: 0x4bd8, 0x1327: 0x0412, 0x1328: 0x0416, 0x1329: 0x041a,
0x132a: 0x4bde, 0x132b: 0x4be4, 0x132c: 0x4bea, 0x132d: 0x4bf0, 0x132e: 0x4bf6, 0x132f: 0x4bfc,
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: 0x4b4e, 0x1343: 0x4b54, 0x1344: 0x4b5a, 0x1345: 0x4b60,
0x1346: 0x4b66, 0x1347: 0x4b6c, 0x134a: 0x4b72, 0x134b: 0x4b78,
0x134c: 0x4b7e, 0x134d: 0x4b84, 0x134e: 0x4b8a, 0x134f: 0x4b90,
0x1352: 0x4b96, 0x1353: 0x4b9c, 0x1354: 0x4ba2, 0x1355: 0x4ba8, 0x1356: 0x4bae, 0x1357: 0x4bb4,
0x135a: 0x4bba, 0x135b: 0x4bc0, 0x135c: 0x4bc6,
0x1360: 0x00bf, 0x1361: 0x00c2, 0x1362: 0x00cb, 0x1363: 0x4363,
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: 0x473b, 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: 23 blocks, 1472 entries, 2944 bytes
// Block 0 is the zero block.
var nfkcIndex = [1472]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: 0x14,
// 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,
0x357: 0xce,
0x35e: 0x4c,
0x368: 0xcf, 0x36b: 0xd0,
0x374: 0xd1, 0x375: 0xd2,
0x37a: 0xd3, 0x37b: 0xd4, 0x37d: 0xd5, 0x37e: 0xd6,
// Block 0xe, offset 0x380
0x381: 0xd7, 0x382: 0xd8, 0x384: 0xd9, 0x385: 0xbc, 0x387: 0xda,
0x388: 0xdb, 0x38b: 0xdc, 0x38c: 0xdd, 0x38d: 0xde, 0x38e: 0xdf, 0x38f: 0xe0,
0x391: 0xe1, 0x392: 0xe2, 0x393: 0xe3, 0x396: 0xe4, 0x397: 0xe5,
0x398: 0xe6, 0x39a: 0xe7, 0x39c: 0xe8,
0x3a0: 0xe9, 0x3a4: 0xea, 0x3a5: 0xeb, 0x3a7: 0xec,
0x3a8: 0xed, 0x3a9: 0xee, 0x3aa: 0xef,
0x3b0: 0xe6, 0x3b5: 0xf0, 0x3b6: 0xf1,
0x3bd: 0xf2,
// Block 0xf, offset 0x3c0
0x3c4: 0xf3,
0x3eb: 0xf4, 0x3ec: 0xf5,
0x3f5: 0xf6,
0x3ff: 0xf7,
// Block 0x10, offset 0x400
0x432: 0xf8,
// Block 0x11, offset 0x440
0x473: 0xf9,
// Block 0x12, offset 0x480
0x485: 0xfa, 0x486: 0xfb, 0x487: 0xfc,
0x489: 0xfd,
0x490: 0xfe, 0x491: 0xff, 0x492: 0x100, 0x493: 0x101, 0x494: 0x102, 0x495: 0x103, 0x496: 0x104, 0x497: 0x105,
0x498: 0x106, 0x499: 0x107, 0x49a: 0x4d, 0x49b: 0x108, 0x49c: 0x109, 0x49d: 0x10a, 0x49e: 0x10b, 0x49f: 0x4e,
// Block 0x13, offset 0x4c0
0x4c0: 0x4f, 0x4c1: 0x50, 0x4c2: 0x10c, 0x4c4: 0xf5,
0x4ca: 0x10d, 0x4cb: 0x10e,
0x4d3: 0x10f, 0x4d7: 0x110,
0x4db: 0x111,
0x4e3: 0x112, 0x4e5: 0x113,
0x4f8: 0x51, 0x4f9: 0x52, 0x4fa: 0x53,
// Block 0x14, offset 0x500
0x504: 0x54, 0x505: 0x114, 0x506: 0x115,
0x508: 0x55, 0x509: 0x116,
0x52f: 0x117,
// Block 0x15, offset 0x540
0x560: 0x56, 0x561: 0x57, 0x562: 0x58, 0x563: 0x59, 0x564: 0x5a, 0x565: 0x5b, 0x566: 0x5c, 0x567: 0x5d,
0x568: 0x5e,
// Block 0x16, offset 0x580
0x590: 0x0b, 0x591: 0x0c, 0x596: 0x0d,
0x59b: 0x0e, 0x59c: 0x0f, 0x59d: 0x10, 0x59e: 0x11, 0x59f: 0x12,
0x5af: 0x13,
}
// nfkcSparseOffset: 185 entries, 370 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, 0x145, 0x14e, 0x150, 0x153, 0x155, 0x160, 0x16b, 0x179, 0x187, 0x197, 0x1a5, 0x1ac, 0x1b2, 0x1c1, 0x1c5, 0x1c7, 0x1cb, 0x1cd, 0x1d0, 0x1d2, 0x1d5, 0x1d7, 0x1da, 0x1dc, 0x1de, 0x1e0, 0x1ec, 0x1f6, 0x200, 0x203, 0x207, 0x209, 0x20b, 0x211, 0x214, 0x217, 0x219, 0x21b, 0x21d, 0x21f, 0x225, 0x228, 0x22d, 0x22f, 0x236, 0x23c, 0x242, 0x24a, 0x250, 0x256, 0x25c, 0x260, 0x262, 0x264, 0x266, 0x268, 0x26d, 0x273, 0x276, 0x278, 0x27a, 0x27c, 0x27f, 0x285, 0x289, 0x28d, 0x295, 0x29c, 0x29f, 0x2a2, 0x2a4, 0x2a7, 0x2af, 0x2b9, 0x2c0, 0x2c4, 0x2cb, 0x2ce, 0x2d4, 0x2d6, 0x2d8, 0x2db, 0x2dd, 0x2e0, 0x2e5, 0x2e7, 0x2e9, 0x2eb, 0x2ed, 0x2ef, 0x2f2, 0x2f4, 0x2f6, 0x303, 0x305, 0x307, 0x30d, 0x30f, 0x311, 0x314, 0x321, 0x32b, 0x32d, 0x32f, 0x333, 0x338, 0x344, 0x349, 0x352, 0x358, 0x35d, 0x361, 0x366, 0x36a, 0x37a, 0x388, 0x396, 0x3a4, 0x3a6, 0x3a8, 0x3aa, 0x3ae, 0x3b1, 0x3b6, 0x3b8, 0x3bb, 0x3c6, 0x3c8, 0x3d2}
// nfkcSparseValues: 980 entries, 3920 bytes
var nfkcSparseValues = [980]valueRange{
// Block 0x0, offset 0x0
{value: 0x0002, lo: 0x0d},
{value: 0x0001, lo: 0xa0, hi: 0xa0},
{value: 0x4377, lo: 0xa8, hi: 0xa8},
{value: 0x0083, lo: 0xaa, hi: 0xaa},
{value: 0x4363, lo: 0xaf, hi: 0xaf},
{value: 0x0025, lo: 0xb2, hi: 0xb3},
{value: 0x4359, lo: 0xb4, hi: 0xb4},
{value: 0x0260, lo: 0xb5, hi: 0xb5},
{value: 0x4390, 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: 0x4859, lo: 0xa0, hi: 0xa1},
{value: 0x488b, 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: 0x436d, lo: 0x98, hi: 0x98},
{value: 0x4372, lo: 0x99, hi: 0x9a},
{value: 0x4395, lo: 0x9b, hi: 0x9b},
{value: 0x435e, lo: 0x9c, hi: 0x9c},
{value: 0x4381, 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: 0x3704, lo: 0x90, hi: 0x90},
{value: 0x3710, lo: 0x91, hi: 0x91},
{value: 0x36fe, lo: 0x93, hi: 0x93},
{value: 0xa000, lo: 0x96, hi: 0x96},
{value: 0x3776, lo: 0x97, hi: 0x97},
{value: 0x3740, lo: 0x9c, hi: 0x9c},
{value: 0x3728, lo: 0x9d, hi: 0x9d},
{value: 0x3752, lo: 0x9e, hi: 0x9e},
{value: 0xa000, lo: 0xb4, hi: 0xb5},
{value: 0x377c, lo: 0xb6, hi: 0xb6},
{value: 0x3782, 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: 0x37a0, lo: 0xa2, hi: 0xa2},
{value: 0x37a6, lo: 0xa3, hi: 0xa3},
{value: 0x37b2, lo: 0xa4, hi: 0xa4},
{value: 0x37ac, lo: 0xa5, hi: 0xa5},
{value: 0x37b8, lo: 0xa6, hi: 0xa6},
{value: 0xa000, lo: 0xa7, hi: 0xa7},
// Block 0x8, offset 0x48
{value: 0x0000, lo: 0x0e},
{value: 0x37ca, lo: 0x80, hi: 0x80},
{value: 0xa000, lo: 0x81, hi: 0x81},
{value: 0x37be, lo: 0x82, hi: 0x82},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x37c4, 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: 0x97, 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: 0x3e37, lo: 0xa9, hi: 0xa9},
{value: 0xa000, lo: 0xb0, hi: 0xb0},
{value: 0x3e3f, lo: 0xb1, hi: 0xb1},
{value: 0xa000, lo: 0xb3, hi: 0xb3},
{value: 0x3e47, 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: 0x461b, 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: 0x3e4f, lo: 0x8b, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
{value: 0x465b, lo: 0x9c, hi: 0x9d},
{value: 0x466b, lo: 0x9f, hi: 0x9f},
{value: 0x8133, lo: 0xbe, hi: 0xbe},
// Block 0x13, offset 0x96
{value: 0x0000, lo: 0x03},
{value: 0x4693, lo: 0xb3, hi: 0xb3},
{value: 0x469b, 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: 0x4673, lo: 0x99, hi: 0x9b},
{value: 0x468b, 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: 0x3e67, lo: 0x88, hi: 0x88},
{value: 0x3e5f, lo: 0x8b, hi: 0x8b},
{value: 0x3e6f, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x96, hi: 0x97},
{value: 0x46a3, lo: 0x9c, hi: 0x9c},
{value: 0x46ab, lo: 0x9d, hi: 0x9d},
// Block 0x18, offset 0xab
{value: 0x0000, lo: 0x03},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0x3e77, 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: 0x3e7f, lo: 0x8a, hi: 0x8a},
{value: 0x3e8f, lo: 0x8b, hi: 0x8b},
{value: 0x3e87, 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: 0x3e97, 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: 0x3e9f, lo: 0x80, hi: 0x80},
{value: 0x9900, lo: 0x82, hi: 0x82},
{value: 0xa000, lo: 0x86, hi: 0x86},
{value: 0x3ea7, lo: 0x87, hi: 0x87},
{value: 0x3eaf, lo: 0x88, hi: 0x88},
{value: 0x4b25, lo: 0x8a, hi: 0x8a},
{value: 0x4331, 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: 0x3eb7, lo: 0x8a, hi: 0x8a},
{value: 0x3ec7, lo: 0x8b, hi: 0x8b},
{value: 0x3ebf, lo: 0x8c, hi: 0x8c},
{value: 0x8105, lo: 0x8d, hi: 0x8d},
{value: 0x9900, lo: 0x97, hi: 0x97},
// Block 0x1f, offset 0xd2
{value: 0x5a29, lo: 0x07},
{value: 0x9905, lo: 0x8a, hi: 0x8a},
{value: 0x9900, lo: 0x8f, hi: 0x8f},
{value: 0xa000, lo: 0x99, hi: 0x99},
{value: 0x3ecf, lo: 0x9a, hi: 0x9a},
{value: 0x4b2d, lo: 0x9c, hi: 0x9c},
{value: 0x433c, lo: 0x9d, hi: 0x9d},
{value: 0x3ed7, 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: 0x4ca5, lo: 0xb3, hi: 0xb3},
{value: 0x8129, lo: 0xb4, hi: 0xb4},
{value: 0x4cae, lo: 0xb5, hi: 0xb5},
{value: 0x46b3, lo: 0xb6, hi: 0xb6},
{value: 0x476b, lo: 0xb7, hi: 0xb7},
{value: 0x46bb, lo: 0xb8, hi: 0xb8},
{value: 0x4776, 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: 0x4cb7, 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: 0x3edf, 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: 0x0b},
{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: 0x9c},
{value: 0x812e, lo: 0x9d, hi: 0x9d},
{value: 0x8133, lo: 0xa0, hi: 0xa5},
{value: 0x812e, lo: 0xa6, hi: 0xa6},
{value: 0x8133, lo: 0xa7, hi: 0xaa},
{value: 0x8136, lo: 0xab, hi: 0xab},
// Block 0x38, offset 0x145
{value: 0x0000, lo: 0x08},
{value: 0x3f27, lo: 0x80, hi: 0x80},
{value: 0x3f2f, lo: 0x81, hi: 0x81},
{value: 0xa000, lo: 0x82, hi: 0x82},
{value: 0x3f37, 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 0x14e
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xaa, hi: 0xab},
// Block 0x3a, offset 0x150
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xa6, hi: 0xa6},
{value: 0x8105, lo: 0xb2, hi: 0xb3},
// Block 0x3b, offset 0x153
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
// Block 0x3c, offset 0x155
{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 0x160
{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 0x16b
{value: 0x0000, lo: 0x0d},
{value: 0x0001, lo: 0x80, hi: 0x8a},
{value: 0x0532, lo: 0x91, hi: 0x91},
{value: 0x439a, 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: 0x4368, lo: 0xbe, hi: 0xbe},
// Block 0x3f, offset 0x179
{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 0x187
{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 0x197
{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 0x1a5
{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: 0x3b18, lo: 0x9a, hi: 0x9b},
{value: 0x3b26, lo: 0xae, hi: 0xae},
// Block 0x43, offset 0x1ac
{value: 0x000e, lo: 0x05},
{value: 0x3b2d, lo: 0x8d, hi: 0x8e},
{value: 0x3b34, 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 0x1b2
{value: 0x017a, lo: 0x0e},
{value: 0xa000, lo: 0x83, hi: 0x83},
{value: 0x3b42, lo: 0x84, hi: 0x84},
{value: 0xa000, lo: 0x88, hi: 0x88},
{value: 0x3b49, lo: 0x89, hi: 0x89},
{value: 0xa000, lo: 0x8b, hi: 0x8b},
{value: 0x3b50, lo: 0x8c, hi: 0x8c},
{value: 0xa000, lo: 0xa3, hi: 0xa3},
{value: 0x3b57, lo: 0xa4, hi: 0xa4},
{value: 0xa000, lo: 0xa5, hi: 0xa5},
{value: 0x3b5e, 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 0x1c1
{value: 0x0007, lo: 0x03},
{value: 0x3bc7, lo: 0xa0, hi: 0xa1},
{value: 0x3bf1, lo: 0xa2, hi: 0xa3},
{value: 0x3c1b, lo: 0xaa, hi: 0xad},
// Block 0x46, offset 0x1c5
{value: 0x0004, lo: 0x01},
{value: 0x0586, lo: 0xa9, hi: 0xaa},
// Block 0x47, offset 0x1c7
{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 0x1cb
{value: 0x0000, lo: 0x01},
{value: 0x2ad2, lo: 0x8c, hi: 0x8c},
// Block 0x49, offset 0x1cd
{value: 0x0266, lo: 0x02},
{value: 0x1cbc, lo: 0xb4, hi: 0xb4},
{value: 0x1a5a, lo: 0xb5, hi: 0xb6},
// Block 0x4a, offset 0x1d0
{value: 0x0000, lo: 0x01},
{value: 0x45dc, lo: 0x9c, hi: 0x9c},
// Block 0x4b, offset 0x1d2
{value: 0x0000, lo: 0x02},
{value: 0x0095, lo: 0xbc, hi: 0xbc},
{value: 0x006d, lo: 0xbd, hi: 0xbd},
// Block 0x4c, offset 0x1d5
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xaf, hi: 0xb1},
// Block 0x4d, offset 0x1d7
{value: 0x0000, lo: 0x02},
{value: 0x057a, lo: 0xaf, hi: 0xaf},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x4e, offset 0x1da
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa0, hi: 0xbf},
// Block 0x4f, offset 0x1dc
{value: 0x0000, lo: 0x01},
{value: 0x0ebe, lo: 0x9f, hi: 0x9f},
// Block 0x50, offset 0x1de
{value: 0x0000, lo: 0x01},
{value: 0x172a, lo: 0xb3, hi: 0xb3},
// Block 0x51, offset 0x1e0
{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 0x1ec
{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 0x1f6
{value: 0x0006, lo: 0x09},
{value: 0x0406, lo: 0xb1, hi: 0xb1},
{value: 0x040a, lo: 0xb2, hi: 0xb2},
{value: 0x4bcc, lo: 0xb3, hi: 0xb3},
{value: 0x040e, lo: 0xb4, hi: 0xb4},
{value: 0x4bd2, lo: 0xb5, hi: 0xb6},
{value: 0x0412, lo: 0xb7, hi: 0xb7},
{value: 0x0416, lo: 0xb8, hi: 0xb8},
{value: 0x041a, lo: 0xb9, hi: 0xb9},
{value: 0x4bde, lo: 0xba, hi: 0xbf},
// Block 0x54, offset 0x200
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xaf, hi: 0xaf},
{value: 0x8133, lo: 0xb4, hi: 0xbd},
// Block 0x55, offset 0x203
{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 0x207
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb0, hi: 0xb1},
// Block 0x57, offset 0x209
{value: 0x0000, lo: 0x01},
{value: 0x173e, lo: 0xb0, hi: 0xb0},
// Block 0x58, offset 0x20b
{value: 0x0006, lo: 0x05},
{value: 0x0067, lo: 0xb1, hi: 0xb1},
{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 0x211
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x86, hi: 0x86},
{value: 0x8105, lo: 0xac, hi: 0xac},
// Block 0x5a, offset 0x214
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x84, hi: 0x84},
{value: 0x8133, lo: 0xa0, hi: 0xb1},
// Block 0x5b, offset 0x217
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xab, hi: 0xad},
// Block 0x5c, offset 0x219
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x93, hi: 0x93},
// Block 0x5d, offset 0x21b
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0xb3, hi: 0xb3},
// Block 0x5e, offset 0x21d
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x80, hi: 0x80},
// Block 0x5f, offset 0x21f
{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 0x225
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x81, hi: 0x81},
{value: 0x8105, lo: 0xb6, hi: 0xb6},
// Block 0x61, offset 0x228
{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 0x22d
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xad, hi: 0xad},
// Block 0x63, offset 0x22f
{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 0x236
{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 0x23c
{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 0x242
{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 0x24a
{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 0x250
{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 0x256
{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 0x25c
{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 0x260
{value: 0x0002, lo: 0x01},
{value: 0x0003, lo: 0x81, hi: 0xbf},
// Block 0x6c, offset 0x262
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xbd, hi: 0xbd},
// Block 0x6d, offset 0x264
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0xa0, hi: 0xa0},
// Block 0x6e, offset 0x266
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb6, hi: 0xba},
// Block 0x6f, offset 0x268
{value: 0x0000, lo: 0x04},
{value: 0x410f, lo: 0x89, hi: 0x89},
{value: 0xa000, lo: 0x92, hi: 0x92},
{value: 0xa000, lo: 0x9a, hi: 0x9a},
{value: 0x4117, lo: 0xa4, hi: 0xa4},
// Block 0x70, offset 0x26d
{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 0x71, offset 0x273
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xa5, hi: 0xa5},
{value: 0x812e, lo: 0xa6, hi: 0xa6},
// Block 0x72, offset 0x276
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa4, hi: 0xa7},
// Block 0x73, offset 0x278
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xa9, hi: 0xad},
// Block 0x74, offset 0x27a
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xab, hi: 0xac},
// Block 0x75, offset 0x27c
{value: 0x0000, lo: 0x02},
{value: 0x812e, lo: 0xba, hi: 0xbb},
{value: 0x812e, lo: 0xbd, hi: 0xbf},
// Block 0x76, offset 0x27f
{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 0x77, offset 0x285
{value: 0x0005, lo: 0x03},
{value: 0x8133, lo: 0x82, hi: 0x82},
{value: 0x812e, lo: 0x83, hi: 0x84},
{value: 0x812e, lo: 0x85, hi: 0x85},
// Block 0x78, offset 0x289
{value: 0x0000, lo: 0x03},
{value: 0x8105, lo: 0x86, hi: 0x86},
{value: 0x8105, lo: 0xb0, hi: 0xb0},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x79, offset 0x28d
{value: 0x17fe, lo: 0x07},
{value: 0xa000, lo: 0x99, hi: 0x99},
{value: 0x4287, lo: 0x9a, hi: 0x9a},
{value: 0xa000, lo: 0x9b, hi: 0x9b},
{value: 0x4291, lo: 0x9c, hi: 0x9c},
{value: 0xa000, lo: 0xa5, hi: 0xa5},
{value: 0x429b, lo: 0xab, hi: 0xab},
{value: 0x8105, lo: 0xb9, hi: 0xba},
// Block 0x7a, offset 0x295
{value: 0x0000, lo: 0x06},
{value: 0x8133, lo: 0x80, hi: 0x82},
{value: 0x9900, lo: 0xa7, hi: 0xa7},
{value: 0x42a5, lo: 0xae, hi: 0xae},
{value: 0x42af, lo: 0xaf, hi: 0xaf},
{value: 0xa000, lo: 0xb1, hi: 0xb2},
{value: 0x8105, lo: 0xb3, hi: 0xb4},
// Block 0x7b, offset 0x29c
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x80, hi: 0x80},
{value: 0x8103, lo: 0x8a, hi: 0x8a},
// Block 0x7c, offset 0x29f
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb5, hi: 0xb5},
{value: 0x8103, lo: 0xb6, hi: 0xb6},
// Block 0x7d, offset 0x2a2
{value: 0x0002, lo: 0x01},
{value: 0x8103, lo: 0xa9, hi: 0xaa},
// Block 0x7e, offset 0x2a4
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0xbb, hi: 0xbc},
{value: 0x9900, lo: 0xbe, hi: 0xbe},
// Block 0x7f, offset 0x2a7
{value: 0x0000, lo: 0x07},
{value: 0xa000, lo: 0x87, hi: 0x87},
{value: 0x42b9, lo: 0x8b, hi: 0x8b},
{value: 0x42c3, 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 0x80, offset 0x2af
{value: 0x5d33, lo: 0x09},
{value: 0xa000, lo: 0x82, hi: 0x82},
{value: 0x42cd, lo: 0x83, hi: 0x84},
{value: 0x42d7, lo: 0x85, hi: 0x85},
{value: 0xa000, lo: 0x8b, hi: 0x8b},
{value: 0x42e1, lo: 0x8e, hi: 0x8e},
{value: 0xa000, lo: 0x90, hi: 0x90},
{value: 0x42eb, lo: 0x91, hi: 0x91},
{value: 0x9900, lo: 0xb8, hi: 0xb8},
{value: 0x9900, lo: 0xbb, hi: 0xbb},
// Block 0x81, offset 0x2b9
{value: 0x0000, lo: 0x06},
{value: 0xb900, lo: 0x82, hi: 0x82},
{value: 0x4c14, lo: 0x85, hi: 0x85},
{value: 0x4c09, lo: 0x87, hi: 0x87},
{value: 0x4c1f, lo: 0x88, hi: 0x88},
{value: 0x9900, lo: 0x89, hi: 0x89},
{value: 0x8105, lo: 0x8e, hi: 0x90},
// Block 0x82, offset 0x2c0
{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 0x2c4
{value: 0x560b, lo: 0x06},
{value: 0x9900, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xb9, hi: 0xb9},
{value: 0x9900, lo: 0xba, hi: 0xba},
{value: 0x42ff, lo: 0xbb, hi: 0xbb},
{value: 0x42f5, lo: 0xbc, hi: 0xbd},
{value: 0x4309, lo: 0xbe, hi: 0xbe},
// Block 0x84, offset 0x2cb
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0x82, hi: 0x82},
{value: 0x8103, lo: 0x83, hi: 0x83},
// Block 0x85, offset 0x2ce
{value: 0x0000, lo: 0x05},
{value: 0x9900, lo: 0xaf, hi: 0xaf},
{value: 0xa000, lo: 0xb8, hi: 0xb9},
{value: 0x4313, lo: 0xba, hi: 0xba},
{value: 0x431d, lo: 0xbb, hi: 0xbb},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x86, offset 0x2d4
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0x80, hi: 0x80},
// Block 0x87, offset 0x2d6
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xbf, hi: 0xbf},
// Block 0x88, offset 0x2d8
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb6, hi: 0xb6},
{value: 0x8103, lo: 0xb7, hi: 0xb7},
// Block 0x89, offset 0x2db
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xab, hi: 0xab},
// Block 0x8a, offset 0x2dd
{value: 0x0000, lo: 0x02},
{value: 0x8105, lo: 0xb9, hi: 0xb9},
{value: 0x8103, lo: 0xba, hi: 0xba},
// Block 0x8b, offset 0x2e0
{value: 0x0000, lo: 0x04},
{value: 0x9900, lo: 0xb0, hi: 0xb0},
{value: 0xa000, lo: 0xb5, hi: 0xb5},
{value: 0x4327, lo: 0xb8, hi: 0xb8},
{value: 0x8105, lo: 0xbd, hi: 0xbe},
// Block 0x8c, offset 0x2e5
{value: 0x0000, lo: 0x01},
{value: 0x8103, lo: 0x83, hi: 0x83},
// Block 0x8d, offset 0x2e7
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xa0, hi: 0xa0},
// Block 0x8e, offset 0x2e9
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0xb4, hi: 0xb4},
// Block 0x8f, offset 0x2eb
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x87, hi: 0x87},
// Block 0x90, offset 0x2ed
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x99, hi: 0x99},
// Block 0x91, offset 0x2ef
{value: 0x0000, lo: 0x02},
{value: 0x8103, lo: 0x82, hi: 0x82},
{value: 0x8105, lo: 0x84, hi: 0x85},
// Block 0x92, offset 0x2f2
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x97, hi: 0x97},
// Block 0x93, offset 0x2f4
{value: 0x0000, lo: 0x01},
{value: 0x8105, lo: 0x81, hi: 0x82},
// Block 0x94, offset 0x2f6
{value: 0x0000, lo: 0x0c},
{value: 0xb900, lo: 0x9e, hi: 0x9e},
{value: 0x9900, lo: 0x9f, hi: 0xa0},
{value: 0x4c83, lo: 0xa1, hi: 0xa1},
{value: 0x4c8e, lo: 0xa2, hi: 0xa2},
{value: 0x4c2a, lo: 0xa3, hi: 0xa3},
{value: 0x4c40, lo: 0xa4, hi: 0xa4},
{value: 0x4c35, lo: 0xa5, hi: 0xa5},
{value: 0x4c56, lo: 0xa6, hi: 0xa6},
{value: 0x4c74, lo: 0xa7, hi: 0xa7},
{value: 0x4c65, lo: 0xa8, hi: 0xa8},
{value: 0xb900, lo: 0xa9, hi: 0xa9},
{value: 0x8105, lo: 0xaf, hi: 0xaf},
// Block 0x95, offset 0x303
{value: 0x0000, lo: 0x01},
{value: 0x8101, lo: 0xb0, hi: 0xb4},
// Block 0x96, offset 0x305
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xb0, hi: 0xb6},
// Block 0x97, offset 0x307
{value: 0x0000, lo: 0x05},
{value: 0xa000, lo: 0xa3, hi: 0xa3},
{value: 0xb900, lo: 0xa7, hi: 0xa7},
{value: 0x4c4b, lo: 0xa8, hi: 0xa8},
{value: 0x4b35, lo: 0xa9, hi: 0xa9},
{value: 0x4347, lo: 0xaa, hi: 0xaa},
// Block 0x98, offset 0x30d
{value: 0x0000, lo: 0x01},
{value: 0x8102, lo: 0xb0, hi: 0xb1},
// Block 0x99, offset 0x30f
{value: 0x0000, lo: 0x01},
{value: 0x8101, lo: 0x9e, hi: 0x9e},
// Block 0x9a, offset 0x311
{value: 0x0002, lo: 0x02},
{value: 0x0043, lo: 0x96, hi: 0xaf},
{value: 0x0021, lo: 0xb0, hi: 0xb9},
// Block 0x9b, offset 0x314
{value: 0x0000, lo: 0x0c},
{value: 0x4743, lo: 0x9e, hi: 0x9e},
{value: 0x474d, lo: 0x9f, hi: 0x9f},
{value: 0x4781, lo: 0xa0, hi: 0xa0},
{value: 0x478f, lo: 0xa1, hi: 0xa1},
{value: 0x479d, lo: 0xa2, hi: 0xa2},
{value: 0x47ab, lo: 0xa3, hi: 0xa3},
{value: 0x47b9, 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 0x9c, offset 0x321
{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: 0x4757, lo: 0xbb, hi: 0xbb},
{value: 0x4761, lo: 0xbc, hi: 0xbc},
{value: 0x47c7, lo: 0xbd, hi: 0xbd},
{value: 0x47e3, lo: 0xbe, hi: 0xbe},
{value: 0x47d5, lo: 0xbf, hi: 0xbf},
// Block 0x9d, offset 0x32b
{value: 0x0000, lo: 0x01},
{value: 0x47f1, lo: 0x80, hi: 0x80},
// Block 0x9e, offset 0x32d
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x82, hi: 0x84},
// Block 0x9f, offset 0x32f
{value: 0x0002, lo: 0x03},
{value: 0x0043, lo: 0x80, hi: 0x99},
{value: 0x0083, lo: 0x9a, hi: 0xb3},
{value: 0x0043, lo: 0xb4, hi: 0xbf},
// Block 0xa0, offset 0x333
{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 0xa1, offset 0x338
{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 0xa2, offset 0x344
{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 0xa3, offset 0x349
{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 0xa4, offset 0x352
{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 0xa5, offset 0x358
{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 0xa6, offset 0x35d
{value: 0x0002, lo: 0x03},
{value: 0x008f, lo: 0x80, hi: 0x93},
{value: 0x0043, lo: 0x94, hi: 0xad},
{value: 0x0083, lo: 0xae, hi: 0xbf},
// Block 0xa7, offset 0x361
{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 0xa8, offset 0x366
{value: 0x0002, lo: 0x03},
{value: 0x004b, lo: 0x80, hi: 0x95},
{value: 0x0083, lo: 0x96, hi: 0xaf},
{value: 0x0043, lo: 0xb0, hi: 0xbf},
// Block 0xa9, offset 0x36a
{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 0xaa, offset 0x37a
{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 0xab, offset 0x388
{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 0xac, offset 0x396
{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 0xad, offset 0x3a4
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0x8f, hi: 0x8f},
// Block 0xae, offset 0x3a6
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xae, hi: 0xae},
// Block 0xaf, offset 0x3a8
{value: 0x0000, lo: 0x01},
{value: 0x8133, lo: 0xac, hi: 0xaf},
// Block 0xb0, offset 0x3aa
{value: 0x0000, lo: 0x03},
{value: 0x8134, lo: 0xac, hi: 0xad},
{value: 0x812e, lo: 0xae, hi: 0xae},
{value: 0x8133, lo: 0xaf, hi: 0xaf},
// Block 0xb1, offset 0x3ae
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0xae, hi: 0xae},
{value: 0x812e, lo: 0xaf, hi: 0xaf},
// Block 0xb2, offset 0x3b1
{value: 0x0000, lo: 0x04},
{value: 0x8133, lo: 0xa3, hi: 0xa3},
{value: 0x8133, lo: 0xa6, hi: 0xa6},
{value: 0x8133, lo: 0xae, hi: 0xaf},
{value: 0x8133, lo: 0xb5, hi: 0xb5},
// Block 0xb3, offset 0x3b6
{value: 0x0000, lo: 0x01},
{value: 0x812e, lo: 0x90, hi: 0x96},
// Block 0xb4, offset 0x3b8
{value: 0x0000, lo: 0x02},
{value: 0x8133, lo: 0x84, hi: 0x89},
{value: 0x8103, lo: 0x8a, hi: 0x8a},
// Block 0xb5, offset 0x3bb
{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 0xb6, offset 0x3c6
{value: 0x0000, lo: 0x01},
{value: 0x1a6c, lo: 0x90, hi: 0x90},
// Block 0xb7, offset 0x3c8
{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 0xb8, offset 0x3d2
{value: 0x0002, lo: 0x01},
{value: 0x0021, lo: 0xb0, hi: 0xb9},
}
// recompMap: 7688 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
"\x05\xd2\x03\a\x00\x01\x05\xc9" + // 0x05D20307: 0x000105C9
"\x05\xda\x03\a\x00\x01\x05\xe4" + // 0x05DA0307: 0x000105E4
"\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
"\x13\x82\x13\xc9\x00\x01\x13\x83" + // 0x138213C9: 0x00011383
"\x13\x84\x13\xbb\x00\x01\x13\x85" + // 0x138413BB: 0x00011385
"\x13\x8b\x13\xc2\x00\x01\x13\x8e" + // 0x138B13C2: 0x0001138E
"\x13\x90\x13\xc9\x00\x01\x13\x91" + // 0x139013C9: 0x00011391
"\x13\xc2\x13\xc2\x00\x01\x13\xc5" + // 0x13C213C2: 0x000113C5
"\x13\xc2\x13\xb8\x00\x01\x13\xc7" + // 0x13C213B8: 0x000113C7
"\x13\xc2\x13\xc9\x00\x01\x13\xc8" + // 0x13C213C9: 0x000113C8
"\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
"a\x1ea\x1e\x00\x01a!" + // 0x611E611E: 0x00016121
"a\x1ea)\x00\x01a\"" + // 0x611E6129: 0x00016122
"a\x1ea\x1f\x00\x01a#" + // 0x611E611F: 0x00016123
"a)a\x1f\x00\x01a$" + // 0x6129611F: 0x00016124
"a\x1ea \x00\x01a%" + // 0x611E6120: 0x00016125
"a!a\x1f\x00\x01a&" + // 0x6121611F: 0x00016126
"a\"a\x1f\x00\x01a'" + // 0x6122611F: 0x00016127
"a!a \x00\x01a(" + // 0x61216120: 0x00016128
"mgmg\x00\x01mh" + // 0x6D676D67: 0x00016D68
"mcmg\x00\x01mi" + // 0x6D636D67: 0x00016D69
"mimg\x00\x01mj" + // 0x6D696D67: 0x00016D6A
""
// Total size of tables: 57KB (58086 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.27
package runenames
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "17.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{ // 765 elements
// Entry 0 - 1F
0x00000001000f0930, 0x00010002f8000000, 0x0003f801080f0930, 0x00050016c002f800,
0x001bd0003019b800, 0x001c20003819e800, 0x001c6000081a2000, 0x001c7000a01a2800,
0x001d180c681ac800, 0x0029880130273000, 0x002ac80190286000, 0x002c68001829f000,
0x002c8801b82a0800, 0x002e8000d82bc000, 0x002f7800302c9800, 0x00300008702cc800,
0x00387801e0353800, 0x003a680328371800, 0x003e0001d83a4000, 0x003fe801883c1800,
0x00418000783da000, 0x00420000e03e1800, 0x0042f000083ef800, 0x00430000583f0000,
0x00438001103f5800, 0x0044b80768406800, 0x004c28004047d000, 0x004c780010481000,
0x004c9800b0482000, 0x004d50003848d000, 0x004d900008490800, 0x004db00020491000,
// Entry 20 - 3F
0x004de00048493000, 0x004e380010497800, 0x004e580020498800, 0x004eb8000849a800,
0x004ee0001049b000, 0x004ef8002049c000, 0x004f18000849e020, 0x004f3000c849e820,
0x00500800184ab020, 0x00502800304ac820, 0x00507800104af820, 0x00509800b04b0820,
0x00515000384bb820, 0x00519000104bf020, 0x0051a800104c0020, 0x0051c000104c1020,
0x0051e000084c2020, 0x0051f000284c2820, 0x00523800104c5020, 0x00525800184c6020,
0x00528800084c7820, 0x0052c800204c8020, 0x0052f000084ca020, 0x00533000884ca820,
0x00540800184d3020, 0x00542800484d4820, 0x00547800184d9020, 0x00549800b04da820,
0x00555000384e5820, 0x00559000104e9020, 0x0055a800284ea020, 0x0055e000504ec820,
// Entry 40 - 5F
0x00563800184f1820, 0x00565800184f3020, 0x00568000084f4820, 0x00570000204f5020,
0x00573000604f7020, 0x0057c800384fd020, 0x0058080018500820, 0x0058280040502020,
0x0058780010506020, 0x00589800b0507020, 0x0059500038512020, 0x0059900010515820,
0x0059a80028516820, 0x0059e00048519020, 0x005a38001051d820, 0x005a58001851e820,
0x005aa80018520020, 0x005ae00010521820, 0x005af80028522820, 0x005b300090525020,
0x005c10001052e020, 0x005c28003052f020, 0x005c700018532020, 0x005c900020533820,
0x005cc80010535820, 0x005ce00008536820, 0x005cf00010537020, 0x005d180010538020,
0x005d400018539020, 0x005d70006053a820, 0x005df00028540820, 0x005e300018543020,
// Entry 60 - 7F
0x005e500020544820, 0x005e800008546820, 0x005eb80008547020, 0x005f3000a8547820,
0x0060000068552020, 0x0060700018558820, 0x00609000b855a020, 0x0061500080565820,
0x0061e0004856d820, 0x0062300018572020, 0x0062500020573820, 0x0062a80010575820,
0x0062c00018576820, 0x0062e00010578020, 0x0063000020579020, 0x006330005057b020,
0x0063b800b0580020, 0x006470001858b020, 0x00649000b858c820, 0x0065500050598020,
0x0065a8002859d020, 0x0065e0004859f820, 0x00663000185a4020, 0x00665000205a5820,
0x0066a800105a7820, 0x0066e000185a8820, 0x00670000205aa020, 0x00673000505ac020,
0x00678800185b1020, 0x00680000685b2820, 0x00687000185b9020, 0x00689001985ba820,
// Entry 80 - 9F
0x006a3000185d4020, 0x006a5000305d5820, 0x006aa000805d8820, 0x006b3000d05e0820,
0x006c0800185ed820, 0x006c2800905ef020, 0x006cd000c05f8020, 0x006d980048604020,
0x006de80008608820, 0x006e000038609020, 0x006e50000860c820, 0x006e78003060d020,
0x006eb00008610020, 0x006ec00040610820, 0x006f300050614820, 0x006f900018619820,
0x00700801d061b020, 0x0071f800e8638020, 0x0074080010646820, 0x0074200008647820,
0x0074300028648020, 0x00746000c064a820, 0x0075280008656820, 0x00753800b8657020,
0x0076000028662820, 0x0076300008665020, 0x0076400038665820, 0x0076800050669020,
0x0076e0002066e020, 0x0078000240670020, 0x007a480120694020, 0x007b8801386a6020,
// Entry A0 - BF
0x007cc801206b9820, 0x007df000786cb820, 0x007e7000686d3020, 0x00800006306d9820,
0x008638000873c820, 0x008668000873d020, 0x0086800bc873d820, 0x00925000207fa020,
0x00928000387fc020, 0x0092c000087ff820, 0x0092d00020800020, 0x0093000148802020,
0x0094500020816820, 0x0094800108818820, 0x0095900020829020, 0x0095c0003882b020,
0x009600000882e820, 0x009610002082f020, 0x0096400078831020, 0x0096c001c8838820,
0x0098900020855020, 0x0098c00218857020, 0x009ae80100878820, 0x009c0000d0888820,
0x009d0002b0895820, 0x009fc000308c0820, 0x00a00014e88c3820, 0x00b50000c0a12020,
0x00b5c00208a1e040, 0x00b80000b0a3e840, 0x00b8f800c0a49840, 0x00ba0000a0a55840,
// Entry C0 - DF
0x00bb000068a5f840, 0x00bb700018a66040, 0x00bb900010a67840, 0x00bc0002f0a68840,
0x00bf000050a97840, 0x00bf800050a9c840, 0x00c00000d0aa1840, 0x00c10002c8aae840,
0x00c4000158adb040, 0x00c5800230af0840, 0x00c80000f8b13840, 0x00c9000060b23040,
0x00c9800060b29040, 0x00ca000008b2f040, 0x00ca200150b2f840, 0x00cb800028b44840,
0x00cc000160b47040, 0x00cd8000d0b5d040, 0x00ce800058b6a040, 0x00cef001f0b6f840,
0x00d0f00208b8e840, 0x00d30000e8baf040, 0x00d3f80058bbd840, 0x00d4800050bc3040,
0x00d5000070bc8040, 0x00d5800170bcf040, 0x00d7000060be6040, 0x00d8000268bec040,
0x00da700530c12840, 0x00dfe001e0c65840, 0x00e1d80078c83840, 0x00e26801f0c8b040,
// Entry E0 - FF
0x00e4800158caa040, 0x00e5e80058cbf840, 0x00e6800158cc5040, 0x00e80010b0cda840,
0x00f8c00030de5840, 0x00f9000130de8840, 0x00fa400030dfb840, 0x00fa800040dfe840,
0x00fac80008e02840, 0x00fad80008e03040, 0x00fae80008e03840, 0x00faf800f8e04040,
0x00fc0001a8e13840, 0x00fdb00078e2e040, 0x00fe300070e35840, 0x00feb00030e3c840,
0x00fee80098e3f840, 0x00ff900018e49040, 0x00ffb00048e4a840, 0x0100000328e4f040,
0x0103300060e81840, 0x0103a000d8e87840, 0x0104800068e95040, 0x0105000110e9b840,
0x0106800090eac840, 0x0107100078eb5860, 0x0108000460ebd060, 0x010c8014d0f03060,
0x0122000059050060, 0x0123003429055860, 0x0157280479398080, 0x015bb00bf13df880,
// Entry 100 - 11F
0x0167c8016949e880, 0x01693800094b5080, 0x01696800094b5880, 0x01698001c14b6080,
0x016b7800114d2080, 0x016bf800c14d3080, 0x016d0000394df080, 0x016d4000394e2880,
0x016d8000394e6080, 0x016dc000394e9880, 0x016e0000394ed080, 0x016e4000394f0880,
0x016e8000394f4080, 0x016ec000394f7880, 0x016f0003f14fb080, 0x01740000d153a080,
0x0174d802c9547080, 0x01780006b1573880, 0x017f8002815de880, 0x01820802b1606880,
0x0184c80339631880, 0x0188280159665080, 0x01898802f167a880, 0x018c8002b16a9880,
0x018f7801816d4880, 0x0191000f016ec880, 0x01a000ce00000370, 0x026e0002017dc880,
0x02700290000871f0, 0x05000017297fc880, 0x0517280d4196f0a0, 0x05248001b9a430a0,
// Entry 120 - 13F
0x0526800ae1a5e8a0, 0x05320005c1b0c8a0, 0x05380006e9b688a0, 0x053f8801e1bd70a0,
0x0541800051bf50a0, 0x05420001c1bfa0a0, 0x0544000231c160a0, 0x0546700061c390a0,
0x05470003a1c3f0a0, 0x054af800f1c790a0, 0x054c000271c880a0, 0x054e780059caf0a0,
0x054ef00109cb48a0, 0x05500001b9cc50a0, 0x0552000071ce08a0, 0x0552800051ce78a0,
0x0552e00339cec8a0, 0x0556d800e1d200a0, 0x0558080031d2e0a0, 0x0558480031d310a0,
0x0558880031d340a0, 0x0559000039d370a0, 0x0559400039d3a8a0, 0x05598001e1d3e0a0,
0x055b8003f1d5c0a0, 0x055f800051d9b0a0, 0x0560015d2008ea30, 0x06bd8000b9da00a0,
0x06be580189dab8a0, 0x06c0001c0009ec10, 0x06dc0004000c4b90, 0x06e00020000971f0,
// Entry 140 - 15F
0x070000c8000d29b0, 0x07c8000b71dc40a0, 0x07d3800351e7b0a0, 0x07d8000039eb00a0,
0x07d8980029eb38a0, 0x07d8e800d1eb60a0, 0x07d9c00029ec30a0, 0x07d9f00009ec58a0,
0x07da000011ec60a0, 0x07da180011ec70a0, 0x07da3000d1ec80a0, 0x07db001381ed50c0,
0x07ef80015200d0c0, 0x07f100019a0220c0, 0x07f2a0009a03b8c0, 0x07f34000220450c0,
0x07f380002a0470c0, 0x07f3b0043a0498c0, 0x07f7f8000a08d0c0, 0x07f80805f208d8c0,
0x07fe1000320ec8c0, 0x07fe5000320ef8c0, 0x07fe9000320f28c0, 0x07fed0001a0f58c0,
0x07ff00003a0f70c0, 0x07ff40003a0fa8c0, 0x07ffc8002a0fe0c0, 0x08000000621008c0,
0x08006800d21068c0, 0x080140009a1138c0, 0x0801e0001211d0c0, 0x0801f8007a11e0c0,
// Entry 160 - 17F
0x08028000721258c0, 0x08040003da12c8c0, 0x080800001a16a0c0, 0x080838016a16b8c0,
0x0809b802c21820c0, 0x080c80006a1ae0c0, 0x080d00000a1b48c0, 0x080e8001721b50c0,
0x08140000ea1cc0c0, 0x081500018a1da8c0, 0x08170000e21f30c0, 0x08180001222010c0,
0x08196800f22130c0, 0x081a80015a2220c0, 0x081c0000f22378c0, 0x081cf8012a2468c0,
0x081e4000722590c0, 0x08200004f22600c0, 0x08250000522af0c0, 0x08258001222b40c0,
0x0826c001222c60c0, 0x08280001422d80c0, 0x08298001422ec0c0, 0x082ac000623000e0,
0x082b7800623060e0, 0x082be0007a30c0e0, 0x082c60003a3138e0, 0x082ca000123170e0,
0x082cb8005a3180e0, 0x082d18007a31d8e0, 0x082d98003a3250e0, 0x082dd800123288e0,
// Entry 180 - 19F
0x082e0001a23298e0, 0x08300009ba3438e0, 0x083a0000b23df0e0, 0x083b0000423ea0e0,
0x083c0000323ee0e0, 0x083c3801523f10e0, 0x083d90004a4060e0, 0x084000003240a8e0,
0x084040000a40d8e0, 0x084050016240e0e0, 0x0841b800124240e0, 0x0841e0000a4250e0,
0x0841f800ba4258e0, 0x0842b802424310e0, 0x084538004a4550e0, 0x084700009a4598e0,
0x0847a000124630e0, 0x0847d8010a4640e0, 0x0848f800da4748e0, 0x0849f800da4820e0,
0x084c0001c248f8e0, 0x084de000a24ab8e0, 0x084e9001924b58e0, 0x08502800124ce8e0,
0x08506000424cf8e0, 0x0850a8001a4d38e0, 0x0850c800ea4d50e0, 0x0851c0001a4e38e0,
0x0851f800524e50e0, 0x085280004a4ea0e0, 0x08530002024ee8e0, 0x085600013a50e8e0,
// Entry 1A0 - 1BF
0x08575800625220e0, 0x08580001b25280e0, 0x0859c800ea5430e0, 0x085ac000da5518e0,
0x085bc000d255f0e0, 0x085cc8002256c0e0, 0x085d48003a56e0e0, 0x086000024a5718e0,
0x086400019a5960e0, 0x086600019a5af8e0, 0x0867d001725c90e0, 0x08698000525e00e0,
0x086a0001325e50e0, 0x086b4800ea5f80e0, 0x086c7000126068e0, 0x08730000fa6078e0,
0x08740001526170e0, 0x087558001a62c0e0, 0x087580001262d8e0, 0x087610003262e8e0,
0x087680004a6318e0, 0x0877d001726360e0, 0x087980015264d0e0, 0x087b8000d26620e0,
0x087d8000e266f0e0, 0x087f0000ba67d0e0, 0x08800002726888e0, 0x08829001226af8e0,
0x0883f802226c18e0, 0x088668000a6e38e0, 0x08868000ca6e40e0, 0x08878000526f08e0,
// Entry 1C0 - 1DF
0x08880001aa6f58e0, 0x0889b000927100e0, 0x088a80013a7190e0, 0x088c00030272c8e0,
0x088f0800a275c8e0, 0x08900000927668e0, 0x089098017a76f8e0, 0x089400003a7870e0,
0x089440000a78a8e0, 0x089450002278b0e0, 0x089478007a78d0e0, 0x0894f8005a7948e0,
0x08958001da79a0e0, 0x08978000527b78e0, 0x08980000227bc8e0, 0x08982800427be8e0,
0x08987800127c28e0, 0x08989800b27c38e0, 0x089950003a7ce8e0, 0x08999000127d20e0,
0x0899a8002a7d30e0, 0x0899d800527d58e0, 0x089a3800127da8e0, 0x089a58001a7db8e0,
0x089a80000a7dd0e0, 0x089ab8000a7dd8e0, 0x089ae8003a7de0e0, 0x089b30003a7e18e0,
0x089b80002a7e50e0, 0x089c0000527e78e0, 0x089c58000a7ec8e0, 0x089c70000a7ed0e0,
// Entry 1E0 - 1FF
0x089c8001327ed8e0, 0x089db800528008e0, 0x089e10000a8058e0, 0x089e28000a8060e0,
0x089e3800228068e0, 0x089e6000528088e0, 0x089eb8001280d8e0, 0x089f08001280e8e0,
0x08a00002e280f8e0, 0x08a2e8002a83d8e0, 0x08a40002428400e0, 0x08a68000528640e0,
0x08ac0001b28690e0, 0x08adc001328840e0, 0x08b000010a8970e0, 0x08b10801228a7900,
0x08b28000528b9900, 0x08b300006a8be900, 0x08b40001d28c5100, 0x08b60000528e2100,
0x08b68000a28e7100, 0x08b80000da8f1100, 0x08b8e8007a8fe900, 0x08b98000ba906100,
0x08c00001e2911900, 0x08c500029a92f900, 0x08c7f80042959100, 0x08c848000a95d100,
0x08c860004295d900, 0x08c8a80012961900, 0x08c8c000f2962900, 0x08c9b80012971900,
// Entry 200 - 21F
0x08c9d80062972900, 0x08ca800052978900, 0x08cd00004297d900, 0x08cd500172981900,
0x08ced0005a998900, 0x08d000024299e100, 0x08d280029a9c2100, 0x08d580024a9eb900,
0x08d8000052a10100, 0x08db000042a15100, 0x08de000112a19100, 0x08df800052a2a100,
0x08e000004aa2f100, 0x08e050016aa33900, 0x08e1c00072a4a100, 0x08e28000eaa51100,
0x08e3800102a5f900, 0x08e49000b2a6f900, 0x08e5480072a7a900, 0x08e800003aa81900,
0x08e8400012a85100, 0x08e8580162a86100, 0x08e9d0000aa9c100, 0x08e9e00012a9c900,
0x08e9f8004aa9d900, 0x08ea800052aa2100, 0x08eb000032aa7100, 0x08eb380012aaa100,
0x08eb50012aaab100, 0x08ec800012abd900, 0x08ec980032abe900, 0x08ed000052ac1900,
// Entry 220 - 23F
0x08ed800162ac6900, 0x08ef000052adc900, 0x08f70000caae1900, 0x08f800008aaee100,
0x08f890014aaf6900, 0x08f9f000eab0b100, 0x08fd80000ab19900, 0x08fe000192b1a100,
0x08fff81cdab33100, 0x092000037ad00900, 0x092380002ad38100, 0x0924000622d3a900,
0x097c800262d9c900, 0x097ee000badc2920, 0x09800022b2dce120, 0x09a3002ec2ff9120,
0x09d1c04e1b2e5140, 0x0a200003d37c6940, 0x0a23d00e6b803960, 0x0b080001d38ea160,
0x0b400011cb907160, 0x0b520000fba23960, 0x0b53000053a33160, 0x0b5370028ba38160,
0x0b56000053a60960, 0x0b568000f3a65960, 0x0b57800033a74960, 0x0b58000233a77960,
0x0b5a800053a9a960, 0x0b5ad8003ba9f960, 0x0b5b1800abaa3160, 0x0b5be8009baad960,
// Entry 240 - 25F
0x0b6a0001d3ab7160, 0x0b720002dbad4160, 0x0b750000cbb01960, 0x0b75d800cbb0e160,
0x0b7800025bb1a960, 0x0b7a7801cbb40160, 0x0b7c78008bb5c960, 0x0b7f00002bb65160,
0x0b7f80003bb67960, 0x0b8000c0000e7a50, 0x0c40001f3bb6b160, 0x0c5f38077bd5e980,
0x0c67f8000bdd6180, 0x0c680000f80d93b0, 0x0c6c00039bdd6980, 0x0d7f800023e10180,
0x0d7fa8003be12180, 0x0d7fe80013e15980, 0x0d8000091be16980, 0x0d8990000bea8180,
0x0d8a80001bea8980, 0x0d8aa8000beaa180, 0x0d8b200023eaa980, 0x0d8b800c63eac980,
0x0de000035bf72980, 0x0de380006bfa8180, 0x0de400004bfae980, 0x0de4800053fb3180,
0x0de4e00043fb8180, 0x0e600007ebfbc180, 0x0e68000da403a980, 0x0e75d000bc114980,
// Entry 260 - 27F
0x0e7700008c120180, 0x0e78000174128980, 0x0e798000bc13f980, 0x0e7a8003a414b180,
0x0e800007b4185180, 0x0e8800013c200180, 0x0e8948001c213980, 0x0e896005fc2151a0,
0x0e900002342749a0, 0x0e960000a42979a0, 0x0e970000a42a19a0, 0x0e980002bc2ab9a0,
0x0e9b0000cc2d71a0, 0x0ea00002ac2e39a0, 0x0ea2b0023c30e1a0, 0x0ea4f000143319a0,
0x0ea510000c3329a0, 0x0ea52800143331a0, 0x0ea54800243341a0, 0x0ea57000643361a0,
0x0ea5d8000c33c1a0, 0x0ea5e8003c33c9a0, 0x0ea628020c3401a0, 0x0ea83800243609a0,
0x0ea86800443629a0, 0x0ea8b0003c3669a0, 0x0ea8f000e436a1a0, 0x0ea9d800243781a0,
0x0eaa00002c37a1a0, 0x0eaa30000c37c9a0, 0x0eaa50003c37d1a0, 0x0eaa900aa43809a0,
// Entry 280 - 29F
0x0eb540092442a9a0, 0x0ebe700f9c4bc9a0, 0x0ece08065c5b61c0, 0x0ed4d8002c61b9c0,
0x0ed508007c61e1c0, 0x0ef80000fc6259c0, 0x0ef92800346351c0, 0x0f0000003c6381c0,
0x0f0040008c63b9c0, 0x0f00d8003c6441c0, 0x0f011800146479c0, 0x0f0130002c6489c0,
0x0f018001f464b1c0, 0x0f0478000c66a1c0, 0x0f0800016c66a9c0, 0x0f098000746811c0,
0x0f0a0000546881c0, 0x0f0a70001468d1c0, 0x0f148000fc68e1c0, 0x0f160001d469d9c0,
0x0f17f8000c6ba9c0, 0x0f268001546bb1c0, 0x0f2e80015c6d01c0, 0x0f2ff8000c6e59c0,
0x0f360000fc6e61c0, 0x0f370000b46f59c0, 0x0f37f000147009c0, 0x0f3f00003c7019c0,
0x0f3f4000247051c0, 0x0f3f6800147071c0, 0x0f3f80007c7081c0, 0x0f4000062c70f9c0,
// Entry 2A0 - 2BF
0x0f463800847721c0, 0x0f4800026477a1c0, 0x0f4a8000547a01c0, 0x0f4af000147a51c0,
0x0f638802247a61c0, 0x0f680801ec7c81c0, 0x0f700000247e69c0, 0x0f702800dc7e89c0,
0x0f710800147f61c0, 0x0f7120000c7f71c0, 0x0f7138000c7f79c0, 0x0f714800547f81c0,
0x0f71a000247fd1c0, 0x0f71c8000c7ff1c0, 0x0f71d8000c7ff9c0, 0x0f7210000c8001c0,
0x0f7238000c8009c0, 0x0f7248000c8011c0, 0x0f7258000c8019c0, 0x0f7268001c8021c0,
0x0f728800148039c0, 0x0f72a0000c8049c0, 0x0f72b8000c8051c0, 0x0f72c8000c8059c0,
0x0f72d8000c8061c0, 0x0f72e8000c8069c0, 0x0f72f8000c8071c0, 0x0f730800148079c0,
0x0f7320000c8089c0, 0x0f733800248091c0, 0x0f7360003c80b1c0, 0x0f73a0002480e9c0,
// Entry 2C0 - 2DF
0x0f73c800248109c0, 0x0f73f0000c8129c0, 0x0f740000548131c0, 0x0f7458008c8181c0,
0x0f7508001c8209c0, 0x0f7528002c8221c0, 0x0f7558008c8249c0, 0x0f7780001482d1c0,
0x0f8000016482e1c0, 0x0f818003248441c0, 0x0f8500007c8761c0, 0x0f8588007c87d9c0,
0x0f8608007c8851c0, 0x0f8688012c88c9c0, 0x0f8800057489f1c0, 0x0f8f3000ec8f61c0,
0x0f908001649049c0, 0x0f9200004c91a9c0, 0x0f9280001491f1c0, 0x0f930000349201c0,
0x0f98001b449231c0, 0x0fb340038cad71e0, 0x0fb6e0008cb0f9e0, 0x0fb780006cb181e0,
0x0fb80006d4b1e9e0, 0x0fbf000064b8b9e0, 0x0fbf80000cb919e0, 0x0fc0000064b921e0,
0x0fc08001c4b981e0, 0x0fc2800054bb41e0, 0x0fc3000144bb91e0, 0x0fc48000f4bcd1e0,
// Entry 2E0 - 2FF
0x0fc5800064bdc1e0, 0x0fc6000014be21e0, 0x0fc680004cbe31e0, 0x0fc8000ac4be79e0,
0x0fd3000074c939e0, 0x0fd380006cc9a9e0, 0x0fd400005cca11e0, 0x0fd47001ccca69e0,
0x0fd640000ccc31e0, 0x0fd6680084cc39e0, 0x0fd6f80064ccb9e0, 0x0fd7780054cd19e0,
0x0fd800049ccd69e0, 0x0fdca0033cd201e0, 0x100005370000db70, 0x153800820001b370,
0x15ba0006f0028b70, 0x15c100b470036370, 0x167580e988043b70, 0x175f80137006c370,
0x17c00010f4d539e0, 0x1800009a58051370, 0x189a80830005eb70, 0x191d808650079b70,
0x700008000ce629e0, 0x7001000304e631e0, 0x7008000784e931e0, 0x780007fff00aead0,
0x800007fff00b9ad0,
} // Size: 6144 bytes
var index = []uint16{ // 40471 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, 0xe2b9, 0xe2d0, 0xe2e9, 0xe2f5, 0xe312,
0xe32f, 0xe34b, 0xe368, 0xe37b, 0xe39c, 0xe3b0, 0xe3cc, 0xe3f0,
0xe412, 0xe438, 0xe45d, 0xe492, 0xe4b2, 0xe4d3, 0xe4fb, 0xe530,
0xe563, 0xe57e, 0xe59f, 0xe5b9, 0xe5cf, 0xe5f6, 0xe61d, 0xe643,
0xe65d, 0xe685, 0xe6ac, 0xe6cc, 0xe6fe, 0xe725, 0xe74c, 0xe772,
0xe799, 0xe7d3, 0xe7ec, 0xe805, 0xe81f, 0xe83d, 0xe85b, 0xe87a,
0xe89a, 0xe8ba, 0xe8e3, 0xe912, 0xe93a, 0xe962, 0xe996, 0xe9a8,
// Entry 840 - 87F
0xe9be, 0xe9d9, 0xea09, 0xea23, 0xea38, 0xea54, 0xea70, 0xea82,
0xea9b, 0xeac5, 0xead9, 0xeaf6, 0xeb0b, 0xeb20, 0xeb35, 0xeb56,
0xeb76, 0xeb99, 0xebb8, 0xebd6, 0xebf2, 0xec0c, 0xec28, 0xec49,
0xec65, 0xec80, 0xec99, 0xecab, 0xecbd, 0xeccf, 0xece4, 0xecf9,
0xed0e, 0xed27, 0xed41, 0xed57, 0xed70, 0xed8a, 0xeda0, 0xedb4,
0xedc8, 0xeddc, 0xedf1, 0xee07, 0xee22, 0xee3d, 0xee58, 0xee74,
0xee8f, 0xeeab, 0xeece, 0xeefa, 0xef1f, 0xef34, 0xef54, 0xef78,
0xef93, 0xefab, 0xefc2, 0xefdb, 0xefee, 0xf002, 0xf015, 0xf029,
// Entry 880 - 8BF
0xf03c, 0xf050, 0xf06b, 0xf086, 0xf0a0, 0xf0b9, 0xf0cc, 0xf0e0,
0xf0fa, 0xf113, 0xf126, 0xf13a, 0xf14e, 0xf163, 0xf177, 0xf18c,
0xf1a1, 0xf1b5, 0xf1ca, 0xf1de, 0xf1f3, 0xf208, 0xf21d, 0xf233,
0xf248, 0xf25e, 0xf273, 0xf287, 0xf29c, 0xf2b0, 0xf2c5, 0xf2d9,
0xf2ef, 0xf303, 0xf318, 0xf32c, 0xf341, 0xf355, 0xf369, 0xf37d,
0xf392, 0xf3a6, 0xf3bb, 0xf3d1, 0xf3e5, 0xf3fa, 0xf40f, 0xf423,
0xf437, 0xf44f, 0xf468, 0xf47d, 0xf495, 0xf4ad, 0xf4c4, 0xf4dc,
0xf4f3, 0xf50b, 0xf52a, 0xf54a, 0xf568, 0xf585, 0xf59c, 0xf5b4,
// Entry 8C0 - 8FF
0xf5d2, 0xf5ef, 0xf606, 0xf61e, 0xf634, 0xf659, 0xf671, 0xf67e,
0xf69b, 0xf6ba, 0xf6d1, 0xf6e8, 0xf70b, 0xf723, 0xf73c, 0xf750,
0xf766, 0xf77c, 0xf790, 0xf7a7, 0xf7bc, 0xf7d0, 0xf7e5, 0xf801,
0xf81d, 0xf83c, 0xf85c, 0xf86c, 0xf883, 0xf898, 0xf8ac, 0xf8c0,
0xf8d6, 0xf8eb, 0xf900, 0xf914, 0xf92a, 0xf940, 0xf955, 0xf971,
0xf991, 0xf9ab, 0xf9bf, 0xf9d4, 0xf9e8, 0xf9fc, 0xfa11, 0xfa2e,
0xfa43, 0xfa5d, 0xfa72, 0xfa87, 0xfaa5, 0xfabb, 0xfad0, 0xfadc,
0xfaf4, 0xfb09, 0xfb1d, 0xfb2d, 0xfb3e, 0xfb4e, 0xfb5f, 0xfb6f,
// Entry 900 - 93F
0xfb80, 0xfb98, 0xfbb0, 0xfbc0, 0xfbd1, 0xfbe1, 0xfbf2, 0xfc03,
0xfc15, 0xfc26, 0xfc38, 0xfc4a, 0xfc5b, 0xfc6d, 0xfc7e, 0xfc90,
0xfca2, 0xfcb4, 0xfcc7, 0xfcd9, 0xfcec, 0xfcfe, 0xfd0f, 0xfd21,
0xfd32, 0xfd44, 0xfd55, 0xfd66, 0xfd78, 0xfd89, 0xfd9b, 0xfdac,
0xfdbd, 0xfdce, 0xfddf, 0xfdf1, 0xfe03, 0xfe14, 0xfe25, 0xfe37,
0xfe4c, 0xfe61, 0xfe75, 0xfe8a, 0xfe9e, 0xfeb3, 0xfecf, 0xfeec,
0xff00, 0xff15, 0xff29, 0xff3e, 0xff51, 0xff69, 0xff7f, 0xff91,
0xffa3, 0xffb5, 0xffce, 0xffe7, 0x0003, 0x0020, 0x0032, 0x0043,
// Entry 940 - 97F
0x0054, 0x0067, 0x0079, 0x008b, 0x009c, 0x00af, 0x00c2, 0x00d4,
0x00fa, 0x011f, 0x0131, 0x0143, 0x0161, 0x017f, 0x019f, 0x01be,
0x01f6, 0x021a, 0x0228, 0x023a, 0x0257, 0x0270, 0x0283, 0x029b,
0x02ae, 0x02c3, 0x02d4, 0x02e6, 0x02f7, 0x0309, 0x031a, 0x032c,
0x033e, 0x0350, 0x0362, 0x0374, 0x0386, 0x0399, 0x03ab, 0x03be,
0x03d1, 0x03e3, 0x03f6, 0x0408, 0x041b, 0x042e, 0x0441, 0x0455,
0x0468, 0x047c, 0x048f, 0x04a1, 0x04b4, 0x04c6, 0x04d9, 0x04eb,
0x04fd, 0x0510, 0x0522, 0x0535, 0x0547, 0x0559, 0x056b, 0x057d,
// Entry 980 - 9BF
0x0590, 0x05a2, 0x05b5, 0x05c7, 0x05d9, 0x05ec, 0x0602, 0x0617,
0x062d, 0x0642, 0x0658, 0x066e, 0x0684, 0x069a, 0x06b0, 0x06c4,
0x06d7, 0x06eb, 0x06ff, 0x0711, 0x0724, 0x0736, 0x0749, 0x075b,
0x076d, 0x0781, 0x0794, 0x07a7, 0x07b9, 0x07cd, 0x07e1, 0x07f4,
0x0802, 0x0810, 0x081c, 0x0828, 0x0839, 0x084d, 0x0867, 0x0880,
0x0896, 0x08ab, 0x08bc, 0x08ce, 0x08df, 0x08f1, 0x0902, 0x0914,
0x092d, 0x0946, 0x095d, 0x096e, 0x0980, 0x0997, 0x09a8, 0x09ba,
0x09cc, 0x09df, 0x09f1, 0x0a04, 0x0a17, 0x0a29, 0x0a3c, 0x0a4e,
// Entry 9C0 - 9FF
0x0a61, 0x0a74, 0x0a87, 0x0a9b, 0x0aae, 0x0ac2, 0x0ad5, 0x0ae7,
0x0afa, 0x0b0c, 0x0b1f, 0x0b31, 0x0b43, 0x0b56, 0x0b68, 0x0b7b,
0x0b8d, 0x0b9f, 0x0bb1, 0x0bc3, 0x0bd6, 0x0be8, 0x0bfb, 0x0c0e,
0x0c20, 0x0c32, 0x0c45, 0x0c5b, 0x0c71, 0x0c86, 0x0c9c, 0x0cb1,
0x0cc7, 0x0ce4, 0x0d02, 0x0d1e, 0x0d33, 0x0d49, 0x0d65, 0x0d7a,
0x0d90, 0x0da4, 0x0daf, 0x0dc9, 0x0de3, 0x0e00, 0x0e1e, 0x0e31,
0x0e43, 0x0e55, 0x0e69, 0x0e7c, 0x0e8f, 0x0ea1, 0x0eb5, 0x0ec9,
0x0edc, 0x0ef6, 0x0f09, 0x0f1c, 0x0f2f, 0x0f43, 0x0f57, 0x0f7a,
// Entry A00 - A3F
0x0f9a, 0x0fbe, 0x0fd4, 0x0fe7, 0x0ff9, 0x1007, 0x1016, 0x1024,
0x1033, 0x1041, 0x1050, 0x1066, 0x107c, 0x108a, 0x1099, 0x10a7,
0x10b6, 0x10c5, 0x10d5, 0x10e4, 0x10f4, 0x1104, 0x1113, 0x1123,
0x1132, 0x1142, 0x1152, 0x1162, 0x1173, 0x1183, 0x1194, 0x11a4,
0x11b3, 0x11c3, 0x11d2, 0x11e2, 0x11f1, 0x1200, 0x1210, 0x121f,
0x122f, 0x123e, 0x124d, 0x125c, 0x126b, 0x127b, 0x128a, 0x129a,
0x12aa, 0x12b9, 0x12c8, 0x12d8, 0x12eb, 0x12fe, 0x1310, 0x1323,
0x1335, 0x1348, 0x1362, 0x137d, 0x138f, 0x13a2, 0x13b4, 0x13c7,
// Entry A40 - A7F
0x13d8, 0x13eb, 0x13ff, 0x1413, 0x1423, 0x1433, 0x1443, 0x145a,
0x1471, 0x148b, 0x14a6, 0x14b6, 0x14c5, 0x14d4, 0x14e5, 0x14f5,
0x1505, 0x1514, 0x1525, 0x1536, 0x1546, 0x1552, 0x1561, 0x157b,
0x1592, 0x15af, 0x15cb, 0x15e4, 0x1603, 0x1616, 0x1628, 0x1636,
0x1645, 0x1653, 0x1662, 0x1670, 0x167f, 0x168d, 0x169c, 0x16ab,
0x16b9, 0x16c8, 0x16d7, 0x16e6, 0x16f6, 0x1705, 0x1714, 0x1724,
0x1734, 0x1744, 0x1753, 0x1762, 0x1773, 0x1782, 0x1791, 0x17a0,
0x17af, 0x17bf, 0x17ce, 0x17de, 0x17ef, 0x17fe, 0x180e, 0x181e,
// Entry A80 - ABF
0x182d, 0x183c, 0x184f, 0x1861, 0x1874, 0x1886, 0x1899, 0x18ab,
0x18be, 0x18d1, 0x18e3, 0x18f6, 0x1909, 0x191a, 0x1922, 0x1936,
0x1946, 0x1955, 0x1964, 0x1975, 0x1985, 0x1995, 0x19a4, 0x19b5,
0x19c6, 0x19d6, 0x19e6, 0x19fe, 0x1a17, 0x1a25, 0x1a35, 0x1a44,
0x1a54, 0x1a65, 0x1a78, 0x1a88, 0x1a99, 0x1ac0, 0x1ad7, 0x1aeb,
0x1afe, 0x1b22, 0x1b31, 0x1b41, 0x1b50, 0x1b60, 0x1b6f, 0x1b7f,
0x1b96, 0x1bad, 0x1bbc, 0x1bcc, 0x1bdc, 0x1beb, 0x1bfb, 0x1c0b,
0x1c1b, 0x1c2c, 0x1c3c, 0x1c4d, 0x1c5e, 0x1c6e, 0x1c7f, 0x1c8f,
// Entry AC0 - AFF
0x1ca0, 0x1cb1, 0x1cc2, 0x1cd4, 0x1ce5, 0x1cf7, 0x1d08, 0x1d18,
0x1d29, 0x1d39, 0x1d4a, 0x1d5a, 0x1d6a, 0x1d7b, 0x1d8b, 0x1d9c,
0x1dac, 0x1dbc, 0x1dcc, 0x1ddd, 0x1ded, 0x1dfe, 0x1e10, 0x1e20,
0x1e31, 0x1e42, 0x1e52, 0x1e62, 0x1e73, 0x1e87, 0x1e9b, 0x1eae,
0x1ec2, 0x1ed5, 0x1ee9, 0x1f04, 0x1f20, 0x1f33, 0x1f47, 0x1f5b,
0x1f6e, 0x1f82, 0x1f96, 0x1fa8, 0x1fba, 0x1fcf, 0x1fe0, 0x1ff1,
0x2003, 0x2017, 0x2032, 0x204a, 0x2062, 0x207d, 0x2099, 0x20aa,
0x20ba, 0x20ca, 0x20dc, 0x20ed, 0x20fe, 0x210e, 0x2120, 0x2132,
// Entry B00 - B3F
0x2143, 0x2156, 0x2187, 0x21b7, 0x21e7, 0x2219, 0x224a, 0x227b,
0x22ae, 0x22bf, 0x22df, 0x22f7, 0x230c, 0x2320, 0x2334, 0x2344,
0x2355, 0x2365, 0x2376, 0x2386, 0x2397, 0x23af, 0x23c7, 0x23d7,
0x23e8, 0x23f9, 0x2409, 0x241a, 0x242b, 0x243c, 0x244e, 0x245f,
0x2471, 0x2483, 0x2494, 0x24a6, 0x24b7, 0x24c9, 0x24db, 0x24ed,
0x2500, 0x2512, 0x2525, 0x2537, 0x2548, 0x255a, 0x256b, 0x257d,
0x258e, 0x259f, 0x25b1, 0x25c2, 0x25d4, 0x25e5, 0x25f6, 0x2607,
0x2619, 0x262a, 0x263c, 0x264d, 0x265f, 0x2671, 0x2682, 0x2693,
// Entry B40 - B7F
0x26a5, 0x26ba, 0x26cf, 0x26e3, 0x26f8, 0x270c, 0x2721, 0x273d,
0x275a, 0x276e, 0x2783, 0x2798, 0x27ac, 0x27c1, 0x27d6, 0x27e9,
0x27fc, 0x2812, 0x2827, 0x2843, 0x2854, 0x286d, 0x2886, 0x28a2,
0x28bf, 0x28d1, 0x28e2, 0x28f3, 0x2906, 0x2918, 0x292a, 0x293b,
0x294e, 0x2961, 0x2973, 0x298b, 0x29a3, 0x29ce, 0x29f5, 0x2a0f,
0x2a26, 0x2a3c, 0x2a5b, 0x2a6d, 0x2a80, 0x2a92, 0x2aa5, 0x2ab7,
0x2aca, 0x2ae4, 0x2afe, 0x2b10, 0x2b23, 0x2b36, 0x2b48, 0x2b5b,
0x2b6e, 0x2b81, 0x2b95, 0x2ba8, 0x2bbc, 0x2bd0, 0x2be3, 0x2bf7,
// Entry B80 - BBF
0x2c0a, 0x2c1e, 0x2c32, 0x2c46, 0x2c5b, 0x2c6f, 0x2c84, 0x2c98,
0x2cab, 0x2cbf, 0x2cd2, 0x2ce6, 0x2cf9, 0x2d0e, 0x2d21, 0x2d35,
0x2d48, 0x2d5c, 0x2d6f, 0x2d82, 0x2d95, 0x2da9, 0x2dbc, 0x2dd0,
0x2de5, 0x2df8, 0x2e0c, 0x2e20, 0x2e33, 0x2e46, 0x2e5b, 0x2e7d,
0x2e9b, 0x2eb2, 0x2ec9, 0x2edf, 0x2ef6, 0x2f0c, 0x2f23, 0x2f41,
0x2f60, 0x2f76, 0x2f8d, 0x2fa4, 0x2fba, 0x2fd1, 0x2fe8, 0x2ffd,
0x3016, 0x3029, 0x3042, 0x305b, 0x3076, 0x308e, 0x30bd, 0x30dc,
0x30ff, 0x311f, 0x313b, 0x315e, 0x317a, 0x3195, 0x31b0, 0x31cb,
// Entry BC0 - BFF
0x31e9, 0x3208, 0x321c, 0x322f, 0x3242, 0x3257, 0x326b, 0x327f,
0x3292, 0x32a7, 0x32bc, 0x32d0, 0x32e4, 0x3300, 0x331d, 0x333b,
0x3356, 0x3377, 0x3397, 0x33b4, 0x33d7, 0x33ea, 0x3404, 0x341d,
0x3437, 0x3450, 0x346a, 0x3483, 0x349b, 0x34b2, 0x34c8, 0x34dd,
0x34f3, 0x3509, 0x3520, 0x3535, 0x354b, 0x3560, 0x3576, 0x358d,
0x35a5, 0x35bc, 0x35d4, 0x35e9, 0x35ff, 0x3615, 0x362a, 0x3640,
0x3656, 0x3677, 0x3699, 0x36ba, 0x36dc, 0x36fd, 0x371b, 0x373c,
0x375e, 0x377f, 0x37a1, 0x37c2, 0x37ed, 0x380b, 0x382d, 0x3850,
// Entry C00 - C3F
0x3872, 0x3895, 0x38b5, 0x38d4, 0x38f5, 0x3917, 0x3938, 0x395a,
0x3978, 0x3996, 0x39b7, 0x39d9, 0x39fa, 0x3a1c, 0x3a32, 0x3a4d,
0x3a63, 0x3a79, 0x3a97, 0x3aad, 0x3acb, 0x3aeb, 0x3b09, 0x3b1f,
0x3b3f, 0x3b55, 0x3b6b, 0x3b88, 0x3bab, 0x3bcd, 0x3bee, 0x3c0e,
0x3c30, 0x3c51, 0x3c70, 0x3c8a, 0x3ca9, 0x3cc6, 0x3cef, 0x3d1d,
0x3d47, 0x3d65, 0x3d7c, 0x3d92, 0x3da8, 0x3dc0, 0x3dd7, 0x3dee,
0x3e04, 0x3e1c, 0x3e34, 0x3e4b, 0x3e6f, 0x3e92, 0x3eb0, 0x3ec5,
0x3edc, 0x3ef4, 0x3f0c, 0x3f23, 0x3f3d, 0x3f53, 0x3f6a, 0x3f82,
// Entry C40 - C7F
0x3f9a, 0x3fae, 0x3fc5, 0x3fdb, 0x3ff2, 0x4009, 0x4020, 0x403d,
0x4057, 0x406c, 0x4081, 0x4096, 0x40ae, 0x40c7, 0x40df, 0x40f3,
0x410b, 0x4120, 0x4138, 0x414c, 0x4163, 0x4178, 0x4192, 0x41a6,
0x41bb, 0x41d0, 0x41e1, 0x41f7, 0x4208, 0x421e, 0x4234, 0x424a,
0x425f, 0x4274, 0x428b, 0x429f, 0x42b7, 0x42cf, 0x42e4, 0x42ff,
0x4315, 0x432b, 0x4340, 0x4356, 0x436c, 0x4383, 0x4398, 0x43ae,
0x43c4, 0x43dd, 0x43f2, 0x4408, 0x441d, 0x443b, 0x445a, 0x4474,
0x448b, 0x44a3, 0x44b8, 0x44ce, 0x44e4, 0x44ff, 0x4519, 0x4530,
// Entry C80 - CBF
0x4547, 0x455d, 0x456c, 0x457a, 0x4588, 0x4598, 0x45a7, 0x45b6,
0x45c4, 0x45d4, 0x45e4, 0x45f3, 0x460c, 0x4621, 0x462e, 0x4641,
0x4653, 0x4666, 0x4674, 0x4681, 0x4694, 0x46a5, 0x46b8, 0x46c6,
0x46d9, 0x46ec, 0x4700, 0x4713, 0x4727, 0x473a, 0x4747, 0x4754,
0x4767, 0x4779, 0x478c, 0x4799, 0x47a6, 0x47b3, 0x47c6, 0x47d7,
0x47e9, 0x47fb, 0x480e, 0x481b, 0x4828, 0x483a, 0x484c, 0x4859,
0x4870, 0x4887, 0x4899, 0x48ab, 0x48be, 0x48ca, 0x48db, 0x48e7,
0x48f7, 0x490d, 0x491e, 0x492f, 0x493f, 0x4950, 0x4960, 0x4971,
// Entry CC0 - CFF
0x4981, 0x4992, 0x49a6, 0x49bc, 0x49d1, 0x49e7, 0x49f7, 0x4a08,
0x4a18, 0x4a29, 0x4a3a, 0x4a43, 0x4a52, 0x4a62, 0x4a71, 0x4a84,
0x4a99, 0x4aa6, 0x4ab2, 0x4ac0, 0x4acd, 0x4ada, 0x4ae9, 0x4af7,
0x4b05, 0x4b12, 0x4b21, 0x4b30, 0x4b3e, 0x4b47, 0x4b50, 0x4b62,
0x4b75, 0x4b88, 0x4bad, 0x4bd7, 0x4c02, 0x4c26, 0x4c4a, 0x4c71,
0x4c93, 0x4caa, 0x4cc4, 0x4ce2, 0x4d02, 0x4d24, 0x4d35, 0x4d4b,
0x4d62, 0x4d7e, 0x4d9f, 0x4dba, 0x4de4, 0x4dfb, 0x4e1b, 0x4e3b,
0x4e6a, 0x4e8d, 0x4eb3, 0x4ece, 0x4eea, 0x4f05, 0x4f1f, 0x4f3a,
// Entry D00 - D3F
0x4f59, 0x4f6b, 0x4f7c, 0x4f8d, 0x4fa0, 0x4fb2, 0x4fc4, 0x4fd5,
0x4fe8, 0x4ffb, 0x500d, 0x5023, 0x5039, 0x5051, 0x5068, 0x507f,
0x5095, 0x50ad, 0x50c5, 0x50dc, 0x50f3, 0x510b, 0x512a, 0x5155,
0x5177, 0x518b, 0x51a1, 0x51bc, 0x51d7, 0x51f2, 0x520d, 0x5223,
0x5239, 0x524a, 0x525c, 0x526d, 0x527f, 0x5291, 0x52a2, 0x52b4,
0x52c5, 0x52d7, 0x52e9, 0x52fc, 0x530e, 0x5321, 0x5333, 0x5344,
0x5356, 0x5367, 0x5379, 0x538a, 0x539b, 0x53ad, 0x53be, 0x53d0,
0x53e1, 0x53f3, 0x5406, 0x5418, 0x542b, 0x543c, 0x544e, 0x545f,
// Entry D40 - D7F
0x5470, 0x5481, 0x5492, 0x54a3, 0x54b5, 0x54c7, 0x54d8, 0x54e9,
0x54f9, 0x550c, 0x5528, 0x553a, 0x554c, 0x5561, 0x5575, 0x558a,
0x559e, 0x55b3, 0x55cf, 0x55ec, 0x5608, 0x5625, 0x5639, 0x564e,
0x5662, 0x5677, 0x5692, 0x56a8, 0x56c5, 0x56e3, 0x56fe, 0x5713,
0x5727, 0x573a, 0x5750, 0x5767, 0x577f, 0x5794, 0x57b0, 0x57cc,
0x57ea, 0x580c, 0x582b, 0x5853, 0x586e, 0x588a, 0x58a5, 0x58c1,
0x58dd, 0x58f8, 0x5914, 0x592f, 0x594b, 0x5967, 0x5984, 0x59a0,
0x59bd, 0x59d9, 0x59f4, 0x5a10, 0x5a2b, 0x5a47, 0x5a62, 0x5a7d,
// Entry D80 - DBF
0x5a99, 0x5ab4, 0x5ad0, 0x5aeb, 0x5b07, 0x5b24, 0x5b40, 0x5b5d,
0x5b78, 0x5b94, 0x5baf, 0x5bca, 0x5be5, 0x5c00, 0x5c1b, 0x5c37,
0x5c53, 0x5c6e, 0x5c89, 0x5ca3, 0x5cc0, 0x5ce6, 0x5d0c, 0x5d32,
0x5d43, 0x5d61, 0x5d85, 0x5da9, 0x5dcc, 0x5df0, 0x5e06, 0x5e1c,
0x5e35, 0x5e55, 0x5e6b, 0x5e80, 0x5ea1, 0x5ec2, 0x5ee3, 0x5f02,
0x5f1c, 0x5f40, 0x5f63, 0x5f7a, 0x5faa, 0x5fda, 0x5ff2, 0x6009,
0x602b, 0x604c, 0x606c, 0x608d, 0x609e, 0x60b0, 0x60c1, 0x60d3,
0x60e5, 0x60f6, 0x6108, 0x6119, 0x612b, 0x613d, 0x6150, 0x6162,
// Entry DC0 - DFF
0x6175, 0x6187, 0x619a, 0x61ac, 0x61bd, 0x61cf, 0x61e0, 0x61f2,
0x6203, 0x6214, 0x6226, 0x6237, 0x6249, 0x625a, 0x626b, 0x627c,
0x628d, 0x629e, 0x62af, 0x62c0, 0x62d2, 0x62e2, 0x62f7, 0x6307,
0x6318, 0x6328, 0x6339, 0x6349, 0x635d, 0x636d, 0x637e, 0x6398,
0x63ad, 0x63c1, 0x63d6, 0x63ea, 0x63ff, 0x6413, 0x6428, 0x6441,
0x6459, 0x6473, 0x6488, 0x649e, 0x64b2, 0x64c5, 0x64d6, 0x64f6,
0x6516, 0x6536, 0x6556, 0x656d, 0x657f, 0x6590, 0x65a1, 0x65b4,
0x65c6, 0x65d8, 0x65e9, 0x65fc, 0x660f, 0x6621, 0x663c, 0x6650,
// Entry E00 - E3F
0x6667, 0x667f, 0x669c, 0x66b3, 0x66c5, 0x66d7, 0x66ef, 0x6708,
0x6720, 0x6739, 0x6755, 0x6772, 0x678e, 0x67ab, 0x67c1, 0x67d7,
0x67ed, 0x6803, 0x6827, 0x684b, 0x686f, 0x688c, 0x68ac, 0x68ce,
0x68f1, 0x6915, 0x6939, 0x6960, 0x6987, 0x69ac, 0x69d1, 0x69f6,
0x6a1b, 0x6a40, 0x6a64, 0x6a88, 0x6aad, 0x6acc, 0x6ae7, 0x6b01,
0x6b1c, 0x6b32, 0x6b49, 0x6b5f, 0x6b75, 0x6b8b, 0x6ba2, 0x6bb8,
0x6bce, 0x6be5, 0x6bfb, 0x6c11, 0x6c28, 0x6c3e, 0x6c63, 0x6c7d,
0x6c96, 0x6cb5, 0x6cd4, 0x6cec, 0x6d04, 0x6d1c, 0x6d34, 0x6d54,
// Entry E40 - E7F
0x6d74, 0x6d9b, 0x6dba, 0x6ddb, 0x6df2, 0x6e08, 0x6e1e, 0x6e36,
0x6e4d, 0x6e64, 0x6e7a, 0x6e92, 0x6eaa, 0x6ec1, 0x6edb, 0x6ef5,
0x6f0f, 0x6f2a, 0x6f41, 0x6f60, 0x6f7a, 0x6f95, 0x6fb0, 0x6fcb,
0x6fe5, 0x7000, 0x701b, 0x7036, 0x7050, 0x706b, 0x7086, 0x70a1,
0x70bc, 0x70d6, 0x70f1, 0x710d, 0x7128, 0x7143, 0x715e, 0x7178,
0x7194, 0x71b0, 0x71cc, 0x71e7, 0x7203, 0x721f, 0x723a, 0x7255,
0x7270, 0x728c, 0x72a7, 0x72c3, 0x72de, 0x72f8, 0x7313, 0x732d,
0x7348, 0x7363, 0x737d, 0x7398, 0x73aa, 0x73bd, 0x73d0, 0x73e3,
// Entry E80 - EBF
0x73f5, 0x7408, 0x741b, 0x742e, 0x7440, 0x7453, 0x7466, 0x7479,
0x748c, 0x749e, 0x74b1, 0x74c5, 0x74d8, 0x74eb, 0x74fe, 0x7510,
0x7524, 0x7538, 0x754c, 0x755f, 0x7573, 0x7587, 0x759a, 0x75ad,
0x75c0, 0x75d4, 0x75e7, 0x75fb, 0x760e, 0x7620, 0x7633, 0x7645,
0x7658, 0x766b, 0x767d, 0x768f, 0x76a4, 0x76be, 0x76d1, 0x76ed,
0x7709, 0x771c, 0x7735, 0x7750, 0x7766, 0x7781, 0x7796, 0x77ac,
0x77c7, 0x77dc, 0x77f1, 0x7806, 0x7820, 0x7834, 0x784d, 0x7862,
0x7877, 0x7891, 0x78a8, 0x78bf, 0x78d6, 0x78ed, 0x7902, 0x791e,
// Entry EC0 - EFF
0x7938, 0x7954, 0x796f, 0x798c, 0x79a7, 0x79c1, 0x79dc, 0x79f9,
0x7a14, 0x7a31, 0x7a4d, 0x7a68, 0x7a84, 0x7a9e, 0x7abf, 0x7ae0,
0x7b00, 0x7b1f, 0x7b3f, 0x7b5a, 0x7b77, 0x7b94, 0x7bb1, 0x7bce,
0x7bf0, 0x7c0b, 0x7c25, 0x7c40, 0x7c5a, 0x7c74, 0x7c8e, 0x7caf,
0x7ccd, 0x7ce7, 0x7d01, 0x7d1d, 0x7d39, 0x7d55, 0x7d71, 0x7d8b,
0x7da7, 0x7dc8, 0x7de7, 0x7e0b, 0x7e22, 0x7e3e, 0x7e5a, 0x7e75,
0x7e90, 0x7eaa, 0x7ec7, 0x7ee1, 0x7efc, 0x7f19, 0x7f36, 0x7f53,
0x7f6b, 0x7f86, 0x7fa3, 0x7fc5, 0x7fe5, 0x800a, 0x8029, 0x8046,
// Entry F00 - F3F
0x8065, 0x8087, 0x80a4, 0x80c3, 0x80dd, 0x80f8, 0x8115, 0x812f,
0x814a, 0x8165, 0x8181, 0x8197, 0x81ae, 0x81c0, 0x81d3, 0x81e6,
0x81fa, 0x820d, 0x821f, 0x8233, 0x8246, 0x8258, 0x826b, 0x827f,
0x8292, 0x82a5, 0x82b7, 0x82cb, 0x82de, 0x82f1, 0x8304, 0x8317,
0x832a, 0x833c, 0x8350, 0x8364, 0x8379, 0x838f, 0x83a4, 0x83b9,
0x83cf, 0x83e5, 0x83fb, 0x8410, 0x8424, 0x8439, 0x844d, 0x8461,
0x8477, 0x848e, 0x84a5, 0x84ba, 0x84cf, 0x84e3, 0x84f8, 0x8510,
0x8525, 0x8539, 0x854e, 0x8564, 0x8579, 0x8590, 0x85a6, 0x85bb,
// Entry F40 - F7F
0x85d0, 0x85e5, 0x85fb, 0x8610, 0x8624, 0x8639, 0x864d, 0x8661,
0x8676, 0x868e, 0x86a4, 0x86bd, 0x86d5, 0x86ed, 0x8708, 0x871d,
0x8732, 0x8749, 0x875e, 0x8774, 0x878b, 0x87a7, 0x87c3, 0x87d9,
0x87f5, 0x8811, 0x8828, 0x883e, 0x885b, 0x8877, 0x8893, 0x88ae,
0x88cc, 0x88ea, 0x8906, 0x891c, 0x8932, 0x894d, 0x8962, 0x897c,
0x8992, 0x89a8, 0x89c0, 0x89d8, 0x89f0, 0x8a08, 0x8a1e, 0x8a3b,
0x8a5e, 0x8a7b, 0x8a98, 0x8ab3, 0x8ad1, 0x8aef, 0x8b0d, 0x8b2a,
0x8b4c, 0x8b68, 0x8b85, 0x8ba8, 0x8bc3, 0x8be6, 0x8c07, 0x8c28,
// Entry F80 - FBF
0x8c4a, 0x8c6e, 0x8c8e, 0x8cac, 0x8cca, 0x8cec, 0x8d09, 0x8d25,
0x8d41, 0x8d5c, 0x8d7c, 0x8d9a, 0x8db8, 0x8dd4, 0x8df2, 0x8e0e,
0x8e2c, 0x8e48, 0x8e66, 0x8e82, 0x8e9e, 0x8eb9, 0x8ed4, 0x8eec,
0x8f09, 0x8f2b, 0x8f46, 0x8f64, 0x8f7d, 0x8f9b, 0x8fbc, 0x8fda,
0x8ffa, 0x9016, 0x9032, 0x904e, 0x906a, 0x9086, 0x90a3, 0x90c0,
0x90df, 0x90fe, 0x911b, 0x9136, 0x914a, 0x915e, 0x9172, 0x9187,
0x919c, 0x91b0, 0x91c4, 0x91d9, 0x91ed, 0x9201, 0x9215, 0x922a,
0x923f, 0x9253, 0x9267, 0x927c, 0x9291, 0x92a6, 0x92bb, 0x92d1,
// Entry FC0 - FFF
0x92e7, 0x92fc, 0x9311, 0x9327, 0x933b, 0x934f, 0x9363, 0x9378,
0x938d, 0x93a1, 0x93b5, 0x93ca, 0x93df, 0x93f4, 0x9409, 0x941f,
0x9435, 0x944a, 0x945f, 0x9475, 0x9489, 0x949d, 0x94b1, 0x94c6,
0x94db, 0x94ef, 0x9503, 0x9518, 0x952c, 0x9540, 0x9554, 0x9569,
0x957e, 0x9592, 0x95a6, 0x95bb, 0x95d0, 0x95e5, 0x95fa, 0x9610,
0x9626, 0x963b, 0x9650, 0x9666, 0x967a, 0x968e, 0x96a2, 0x96b7,
0x96cc, 0x96e0, 0x96f4, 0x9709, 0x971e, 0x9733, 0x9749, 0x975f,
0x9774, 0x9789, 0x979e, 0x97b3, 0x97c9, 0x97df, 0x97f4, 0x9809,
// Entry 1000 - 103F
0x981f, 0x9835, 0x984c, 0x9863, 0x9879, 0x988d, 0x98a1, 0x98b5,
0x98ca, 0x98df, 0x98f3, 0x9907, 0x991c, 0x9930, 0x9944, 0x9958,
0x996d, 0x9982, 0x9996, 0x99aa, 0x99bf, 0x99d3, 0x99e7, 0x99fb,
0x9a10, 0x9a25, 0x9a39, 0x9a4d, 0x9a62, 0x9a76, 0x9a8a, 0x9a9e,
0x9ab3, 0x9ac8, 0x9adc, 0x9af0, 0x9b05, 0x9b19, 0x9b2d, 0x9b41,
0x9b56, 0x9b6b, 0x9b7f, 0x9b93, 0x9ba8, 0x9bbd, 0x9bd2, 0x9be8,
0x9bfe, 0x9c13, 0x9c27, 0x9c3b, 0x9c4f, 0x9c64, 0x9c79, 0x9c8d,
0x9ca1, 0x9cb6, 0x9ccb, 0x9ce0, 0x9cf5, 0x9d0b, 0x9d21, 0x9d36,
// Entry 1040 - 107F
0x9d4b, 0x9d61, 0x9d7c, 0x9d97, 0x9db2, 0x9dce, 0x9dea, 0x9e05,
0x9e20, 0x9e3c, 0x9e50, 0x9e64, 0x9e78, 0x9e8d, 0x9ea2, 0x9eb6,
0x9eca, 0x9edf, 0x9ef4, 0x9f09, 0x9f1f, 0x9f35, 0x9f4a, 0x9f5f,
0x9f74, 0x9f89, 0x9f9f, 0x9fb5, 0x9fca, 0x9fdf, 0x9ff5, 0xa00b,
0xa022, 0xa039, 0xa04f, 0xa063, 0xa077, 0xa08b, 0xa0a0, 0xa0b5,
0xa0c9, 0xa0dd, 0xa0f2, 0xa110, 0xa12e, 0xa14c, 0xa16b, 0xa18a,
0xa1a8, 0xa1c6, 0xa1da, 0xa1ee, 0xa202, 0xa217, 0xa22c, 0xa240,
0xa254, 0xa269, 0xa27e, 0xa293, 0xa2a8, 0xa2be, 0xa2d4, 0xa2e9,
// Entry 1080 - 10BF
0xa2fe, 0xa314, 0xa328, 0xa33c, 0xa350, 0xa365, 0xa37a, 0xa38e,
0xa3a2, 0xa3b7, 0xa3cb, 0xa3df, 0xa3f3, 0xa408, 0xa41d, 0xa431,
0xa445, 0xa45a, 0xa46f, 0xa484, 0xa499, 0xa4af, 0xa4c5, 0xa4da,
0xa4ef, 0xa505, 0xa519, 0xa52d, 0xa541, 0xa556, 0xa56b, 0xa57f,
0xa593, 0xa5a8, 0xa5bc, 0xa5d0, 0xa5e4, 0xa5f9, 0xa60e, 0xa622,
0xa636, 0xa64b, 0xa660, 0xa675, 0xa68b, 0xa6a1, 0xa6b6, 0xa6cb,
0xa6e0, 0xa6f5, 0xa70b, 0xa721, 0xa736, 0xa74b, 0xa762, 0xa777,
0xa78c, 0xa7a1, 0xa7b7, 0xa7cd, 0xa7e2, 0xa7f7, 0xa80d, 0xa822,
// Entry 10C0 - 10FF
0xa837, 0xa84c, 0xa862, 0xa878, 0xa88d, 0xa8a2, 0xa8b8, 0xa8cd,
0xa8e2, 0xa8f7, 0xa90d, 0xa923, 0xa938, 0xa94d, 0xa963, 0xa978,
0xa98d, 0xa9a2, 0xa9b8, 0xa9ce, 0xa9e3, 0xa9f8, 0xaa0e, 0xaa23,
0xaa38, 0xaa4d, 0xaa63, 0xaa79, 0xaa8e, 0xaaa3, 0xaab9, 0xaacd,
0xaae1, 0xaaf5, 0xab0a, 0xab1f, 0xab33, 0xab47, 0xab5c, 0xab70,
0xab84, 0xab98, 0xabad, 0xabc2, 0xabd6, 0xabea, 0xabff, 0xac14,
0xac29, 0xac3e, 0xac71, 0xac95, 0xacb7, 0xaccc, 0xacde, 0xacf0,
0xacfe, 0xad10, 0xad1e, 0xad34, 0xad4a, 0xad66, 0xad78, 0xad8a,
// Entry 1100 - 113F
0xad9e, 0xadb1, 0xadc4, 0xadd6, 0xadea, 0xadfe, 0xae11, 0xae24,
0xae3a, 0xae50, 0xae65, 0xae7a, 0xae8f, 0xaea6, 0xaebc, 0xaed2,
0xaee9, 0xaf05, 0xaf24, 0xaf39, 0xaf4f, 0xaf64, 0xaf83, 0xaf98,
0xafae, 0xafc3, 0xafe2, 0xaff7, 0xb00d, 0xb022, 0xb041, 0xb056,
0xb06c, 0xb081, 0xb09a, 0xb0b3, 0xb0cd, 0xb0ed, 0xb106, 0xb11f,
0xb139, 0xb152, 0xb171, 0xb189, 0xb19a, 0xb1ab, 0xb1bc, 0xb1cd,
0xb1de, 0xb1ef, 0xb201, 0xb213, 0xb225, 0xb237, 0xb249, 0xb25b,
0xb26d, 0xb27f, 0xb291, 0xb2a3, 0xb2b5, 0xb2c7, 0xb2d9, 0xb2eb,
// Entry 1140 - 117F
0xb2fd, 0xb30f, 0xb321, 0xb333, 0xb345, 0xb357, 0xb369, 0xb37b,
0xb38d, 0xb39f, 0xb3b1, 0xb3c4, 0xb3d7, 0xb3e9, 0xb3fb, 0xb40d,
0xb41f, 0xb431, 0xb444, 0xb457, 0xb46a, 0xb47d, 0xb490, 0xb4a3,
0xb4b5, 0xb4c6, 0xb4d8, 0xb4ea, 0xb4fc, 0xb50e, 0xb520, 0xb532,
0xb544, 0xb556, 0xb568, 0xb57a, 0xb58c, 0xb59e, 0xb5b0, 0xb5c2,
0xb5d5, 0xb5e8, 0xb5fb, 0xb60e, 0xb621, 0xb634, 0xb647, 0xb65a,
0xb66d, 0xb680, 0xb693, 0xb6a6, 0xb6b9, 0xb6cb, 0xb6dd, 0xb6ef,
0xb701, 0xb713, 0xb725, 0xb737, 0xb749, 0xb75b, 0xb76d, 0xb77f,
// Entry 1180 - 11BF
0xb791, 0xb7a3, 0xb7bb, 0xb7d3, 0xb7eb, 0xb803, 0xb81b, 0xb833,
0xb84c, 0xb860, 0xb876, 0xb88a, 0xb89f, 0xb8b3, 0xb8c8, 0xb8e4,
0xb901, 0xb91d, 0xb931, 0xb946, 0xb95b, 0xb97a, 0xb98f, 0xb9ae,
0xb9c4, 0xb9e4, 0xb9f9, 0xba18, 0xba2e, 0xba4e, 0xba6c, 0xba81,
0xbaa0, 0xbab6, 0xbad6, 0xbaf4, 0xbb09, 0xbb24, 0xbb43, 0xbb61,
0xbb7f, 0xbba8, 0xbbce, 0xbbf6, 0xbc13, 0xbc38, 0xbc6e, 0xbc91,
0xbcc1, 0xbcde, 0xbd00, 0xbd15, 0xbd2a, 0xbd3f, 0xbd54, 0xbd69,
0xbd80, 0xbd95, 0xbdab, 0xbdc0, 0xbdd6, 0xbdf3, 0xbe11, 0xbe2e,
// Entry 11C0 - 11FF
0xbe43, 0xbe59, 0xbe6f, 0xbe8f, 0xbea5, 0xbec5, 0xbedc, 0xbefd,
0xbf13, 0xbf33, 0xbf4a, 0xbf6b, 0xbf81, 0xbfa1, 0xbfb8, 0xbfd9,
0xbff7, 0xc00b, 0xc029, 0xc045, 0xc05a, 0xc071, 0xc086, 0xc09c,
0xc0b1, 0xc0c7, 0xc0e4, 0xc102, 0xc11f, 0xc134, 0xc14a, 0xc160,
0xc180, 0xc196, 0xc1b6, 0xc1cd, 0xc1ee, 0xc204, 0xc224, 0xc23b,
0xc25c, 0xc272, 0xc292, 0xc2a9, 0xc2ca, 0xc2e9, 0xc2fd, 0xc313,
0xc329, 0xc33f, 0xc355, 0xc36a, 0xc381, 0xc396, 0xc3ac, 0xc3c1,
0xc3d7, 0xc3f4, 0xc409, 0xc41f, 0xc435, 0xc455, 0xc46b, 0xc48b,
// Entry 1200 - 123F
0xc4a2, 0xc4c3, 0xc4d9, 0xc4f9, 0xc510, 0xc531, 0xc547, 0xc567,
0xc57e, 0xc59f, 0xc5be, 0xc5d2, 0xc5e7, 0xc60a, 0xc62d, 0xc650,
0xc673, 0xc688, 0xc69f, 0xc6b4, 0xc6ca, 0xc6df, 0xc6f5, 0xc712,
0xc727, 0xc73d, 0xc753, 0xc773, 0xc789, 0xc7a9, 0xc7c0, 0xc7e1,
0xc7f7, 0xc817, 0xc82e, 0xc84f, 0xc865, 0xc885, 0xc89c, 0xc8bd,
0xc8dc, 0xc8f0, 0xc90c, 0xc921, 0xc938, 0xc94d, 0xc963, 0xc978,
0xc98e, 0xc9ab, 0xc9c0, 0xc9d6, 0xc9ec, 0xca0c, 0xca22, 0xca42,
0xca59, 0xca7a, 0xca90, 0xcab0, 0xcac7, 0xcae8, 0xcafe, 0xcb1e,
// Entry 1240 - 127F
0xcb35, 0xcb56, 0xcb75, 0xcb89, 0xcba7, 0xcbbc, 0xcbdb, 0xcbf6,
0xcc0b, 0xcc22, 0xcc37, 0xcc4d, 0xcc62, 0xcc78, 0xcc95, 0xccaa,
0xccc0, 0xccd6, 0xccf6, 0xcd0c, 0xcd2c, 0xcd43, 0xcd64, 0xcd83,
0xcd97, 0xcdb4, 0xcdc9, 0xcdde, 0xcdf5, 0xce0a, 0xce20, 0xce35,
0xce4b, 0xce68, 0xce7d, 0xce93, 0xcea9, 0xcec9, 0xcedf, 0xceff,
0xcf16, 0xcf37, 0xcf4d, 0xcf6d, 0xcf84, 0xcfa5, 0xcfbb, 0xcfdb,
0xcff2, 0xd013, 0xd027, 0xd045, 0xd060, 0xd075, 0xd08c, 0xd0a1,
0xd0b7, 0xd0cc, 0xd0e2, 0xd0ff, 0xd114, 0xd12a, 0xd140, 0xd160,
// Entry 1280 - 12BF
0xd176, 0xd196, 0xd1ad, 0xd1ce, 0xd1e4, 0xd204, 0xd21b, 0xd23c,
0xd252, 0xd272, 0xd289, 0xd2aa, 0xd2c9, 0xd2dd, 0xd2fc, 0xd311,
0xd32f, 0xd34f, 0xd36d, 0xd38b, 0xd3aa, 0xd3c9, 0xd3e8, 0xd407,
0xd41d, 0xd433, 0xd44a, 0xd460, 0xd477, 0xd48d, 0xd4a4, 0xd4bb,
0xd4dc, 0xd4f3, 0xd514, 0xd52c, 0xd54e, 0xd565, 0xd586, 0xd59e,
0xd5c0, 0xd5d7, 0xd5f8, 0xd610, 0xd632, 0xd647, 0xd65c, 0xd673,
0xd688, 0xd69e, 0xd6b3, 0xd6c9, 0xd6e6, 0xd6fb, 0xd711, 0xd727,
0xd747, 0xd75d, 0xd77d, 0xd794, 0xd7b5, 0xd7cb, 0xd7eb, 0xd802,
// Entry 12C0 - 12FF
0xd823, 0xd839, 0xd859, 0xd870, 0xd891, 0xd8b0, 0xd8c4, 0xd8e3,
0xd901, 0xd91d, 0xd932, 0xd94e, 0xd96d, 0xd984, 0xd999, 0xd9af,
0xd9c4, 0xd9da, 0xd9f9, 0xda0e, 0xda24, 0xda43, 0xda5a, 0xda7b,
0xda8f, 0xdaad, 0xdac8, 0xdadd, 0xdaf4, 0xdb09, 0xdb1f, 0xdb34,
0xdb4a, 0xdb5f, 0xdb75, 0xdb8c, 0xdbad, 0xdbc1, 0xdbd7, 0xdbf4,
0xdc0a, 0xdc27, 0xdc3e, 0xdc5c, 0xdc72, 0xdc89, 0xdc9f, 0xdcb6,
0xdcce, 0xdcf0, 0xdd05, 0xdd1c, 0xdd33, 0xdd4a, 0xdd61, 0xdd77,
0xdd8d, 0xdda3, 0xddb9, 0xddcf, 0xddec, 0xde09, 0xde27, 0xde44,
// Entry 1300 - 133F
0xde62, 0xde7f, 0xde9d, 0xdeb9, 0xded5, 0xdeea, 0xdf01, 0xdf16,
0xdf2c, 0xdf41, 0xdf57, 0xdf6c, 0xdf82, 0xdf96, 0xdfad, 0xdfc4,
0xdfdb, 0xdff2, 0xe011, 0xe030, 0xe04f, 0xe06e, 0xe086, 0xe09c,
0xe0b3, 0xe0c9, 0xe0e0, 0xe0f6, 0xe10d, 0xe122, 0xe138, 0xe155,
0xe172, 0xe18f, 0xe1ac, 0xe1cd, 0xe1ee, 0xe20f, 0xe230, 0xe250,
0xe266, 0xe27d, 0xe293, 0xe2aa, 0xe2c0, 0xe2d7, 0xe2ec, 0xe30a,
0xe328, 0xe347, 0xe365, 0xe384, 0xe3a2, 0xe3c1, 0xe3de, 0xe3fa,
0xe418, 0xe436, 0xe454, 0xe472, 0xe491, 0xe4b0, 0xe4cf, 0xe4ee,
// Entry 1340 - 137F
0xe50d, 0xe52c, 0xe54b, 0xe56a, 0xe589, 0xe5a8, 0xe5c7, 0xe5e6,
0xe602, 0xe61e, 0xe63a, 0xe656, 0xe674, 0xe692, 0xe6b0, 0xe6cf,
0xe6ed, 0xe70b, 0xe728, 0xe745, 0xe762, 0xe780, 0xe79d, 0xe7ba,
0xe7d7, 0xe7f4, 0xe811, 0xe82f, 0xe84c, 0xe869, 0xe887, 0xe8a5,
0xe8c3, 0xe8e2, 0xe900, 0xe91e, 0xe93c, 0xe95a, 0xe978, 0xe997,
0xe9b5, 0xe9d3, 0xe9f1, 0xea0f, 0xea2d, 0xea4c, 0xea6a, 0xea88,
0xeaa5, 0xeac2, 0xeadf, 0xeafd, 0xeb1a, 0xeb37, 0xeb53, 0xeb70,
0xeb8d, 0xebaa, 0xebc8, 0xebe5, 0xec02, 0xec20, 0xec3e, 0xec5c,
// Entry 1380 - 13BF
0xec7b, 0xec99, 0xecb7, 0xecd5, 0xecf3, 0xed11, 0xed30, 0xed4e,
0xed6c, 0xed89, 0xeda6, 0xedc3, 0xede0, 0xedfe, 0xee1b, 0xee38,
0xee55, 0xee72, 0xee8f, 0xeead, 0xeeca, 0xeee7, 0xef04, 0xef21,
0xef3e, 0xef5c, 0xef79, 0xef96, 0xefb3, 0xefcf, 0xefec, 0xf009,
0xf027, 0xf044, 0xf060, 0xf07d, 0xf09b, 0xf0b9, 0xf0d7, 0xf0f6,
0xf114, 0xf132, 0xf14f, 0xf16c, 0xf189, 0xf1a7, 0xf1c4, 0xf1e1,
0xf1ff, 0xf21d, 0xf23b, 0xf25a, 0xf278, 0xf296, 0xf2b4, 0xf2d2,
0xf2f0, 0xf30f, 0xf32d, 0xf34b, 0xf36a, 0xf389, 0xf3a8, 0xf3c8,
// Entry 13C0 - 13FF
0xf3e7, 0xf406, 0xf424, 0xf442, 0xf460, 0xf47f, 0xf49d, 0xf4bb,
0xf4d8, 0xf4f5, 0xf512, 0xf530, 0xf54d, 0xf56a, 0xf586, 0xf5aa,
0xf5c8, 0xf5e6, 0xf604, 0xf623, 0xf641, 0xf65f, 0xf67c, 0xf699,
0xf6b6, 0xf6d4, 0xf6f1, 0xf70e, 0xf72c, 0xf74a, 0xf768, 0xf787,
0xf7a5, 0xf7c3, 0xf7e0, 0xf7fe, 0xf81c, 0xf83a, 0xf859, 0xf877,
0xf895, 0xf8b3, 0xf8d1, 0xf8ef, 0xf90e, 0xf92c, 0xf94a, 0xf969,
0xf988, 0xf9a7, 0xf9c7, 0xf9e6, 0xfa05, 0xfa20, 0xfa3c, 0xfa52,
0xfa69, 0xfa80, 0xfa98, 0xfaaf, 0xfac7, 0xfade, 0xfaf6, 0xfb19,
// Entry 1400 - 143F
0xfb3b, 0xfb5e, 0xfb80, 0xfba3, 0xfbc5, 0xfbe8, 0xfc0e, 0xfc2c,
0xfc3c, 0xfc4e, 0xfc5f, 0xfc71, 0xfc82, 0xfc93, 0xfca4, 0xfcb5,
0xfcc7, 0xfcd8, 0xfcea, 0xfcfb, 0xfd0c, 0xfd20, 0xfd33, 0xfd44,
0xfd55, 0xfd65, 0xfd74, 0xfd88, 0xfd9c, 0xfdb0, 0xfdbf, 0xfdd4,
0xfde5, 0xfdfd, 0xfe0f, 0xfe21, 0xfe3c, 0xfe57, 0xfe65, 0xfe7b,
0xfe8a, 0xfe98, 0xfea6, 0xfec7, 0xfed7, 0xfeeb, 0xfefc, 0xff0d,
0xff1e, 0xff3c, 0xff59, 0xff67, 0xff76, 0xff85, 0xffa2, 0xffb4,
0xffc4, 0xffd7, 0xffe5, 0xfff5, 0x000d, 0x001d, 0x0036, 0x004b,
// Entry 1440 - 147F
0x005f, 0x0080, 0x00a0, 0x00be, 0x00dc, 0x00f1, 0x010b, 0x0119,
0x012d, 0x013d, 0x015b, 0x0177, 0x018c, 0x01a8, 0x01c0, 0x01d5,
0x01f9, 0x0216, 0x0224, 0x0232, 0x024e, 0x026b, 0x0279, 0x029e,
0x02bf, 0x02d4, 0x02e7, 0x02fe, 0x0317, 0x0336, 0x0354, 0x0373,
0x0388, 0x039b, 0x03ab, 0x03c4, 0x03e0, 0x03f0, 0x0400, 0x0414,
0x0425, 0x0437, 0x0448, 0x0463, 0x047d, 0x0496, 0x04a4, 0x04b2,
0x04ca, 0x04e4, 0x04fb, 0x050e, 0x0523, 0x0538, 0x0546, 0x0555,
0x0564, 0x0581, 0x059e, 0x05bb, 0x05d8, 0x05f7, 0x0607, 0x0617,
// Entry 1480 - 14BF
0x0627, 0x0638, 0x0649, 0x065b, 0x066c, 0x067d, 0x068e, 0x069f,
0x06b0, 0x06c1, 0x06d2, 0x06e3, 0x06f4, 0x0705, 0x0716, 0x0727,
0x073b, 0x074f, 0x0762, 0x0777, 0x0790, 0x07a0, 0x07b0, 0x07c0,
0x07d1, 0x07e2, 0x07f4, 0x0805, 0x0816, 0x0827, 0x0838, 0x0849,
0x085a, 0x086b, 0x087c, 0x088d, 0x089e, 0x08af, 0x08c0, 0x08d4,
0x08e8, 0x08fd, 0x091a, 0x0937, 0x0945, 0x0953, 0x0961, 0x0970,
0x097f, 0x098f, 0x099e, 0x09ad, 0x09bc, 0x09cb, 0x09da, 0x09e9,
0x09f8, 0x0a07, 0x0a16, 0x0a25, 0x0a34, 0x0a43, 0x0a55, 0x0a67,
// Entry 14C0 - 14FF
0x0a78, 0x0a89, 0x0a9a, 0x0aac, 0x0abe, 0x0ad1, 0x0ae3, 0x0af5,
0x0b07, 0x0b19, 0x0b2b, 0x0b3d, 0x0b4f, 0x0b61, 0x0b73, 0x0b85,
0x0b9a, 0x0baf, 0x0bbe, 0x0bce, 0x0bdd, 0x0bed, 0x0bfd, 0x0c0c,
0x0c1c, 0x0c2b, 0x0c3b, 0x0c4b, 0x0c5a, 0x0c6b, 0x0c7a, 0x0c8b,
0x0c9b, 0x0caa, 0x0cba, 0x0cc9, 0x0cd9, 0x0ce8, 0x0cf7, 0x0d07,
0x0d16, 0x0d26, 0x0d35, 0x0d44, 0x0d53, 0x0d62, 0x0d71, 0x0d81,
0x0d91, 0x0da0, 0x0daf, 0x0dbe, 0x0dcd, 0x0de8, 0x0e03, 0x0e1d,
0x0e38, 0x0e52, 0x0e6d, 0x0e88, 0x0ea4, 0x0ebe, 0x0ed9, 0x0ef3,
// Entry 1500 - 153F
0x0f0e, 0x0f28, 0x0f43, 0x0f67, 0x0f8b, 0x0fa6, 0x0fbd, 0x0fd4,
0x0fe7, 0x0ff9, 0x100c, 0x101e, 0x1031, 0x1043, 0x1056, 0x1069,
0x107c, 0x108f, 0x10a2, 0x10b4, 0x10c7, 0x10da, 0x10ed, 0x1100,
0x1112, 0x1124, 0x113c, 0x1152, 0x1164, 0x1175, 0x1185, 0x119b,
0x11ad, 0x11bd, 0x11d5, 0x11e6, 0x11f6, 0x120b, 0x121a, 0x122f,
0x1249, 0x125b, 0x126c, 0x1282, 0x1294, 0x12ae, 0x12c6, 0x12d9,
0x12e9, 0x12f8, 0x1307, 0x1318, 0x1328, 0x1338, 0x1347, 0x1358,
0x1369, 0x1379, 0x1393, 0x13ae, 0x13c8, 0x13e2, 0x13fd, 0x1418,
// Entry 1540 - 157F
0x1438, 0x1457, 0x1476, 0x1496, 0x14a5, 0x14b7, 0x14c6, 0x14d9,
0x14e8, 0x14fb, 0x1515, 0x153c, 0x1552, 0x156c, 0x157c, 0x15a1,
0x15c6, 0x15ed, 0x1606, 0x162c, 0x1640, 0x1653, 0x1666, 0x167b,
0x168f, 0x16a3, 0x16b6, 0x16cb, 0x16e0, 0x16f4, 0x1706, 0x1718,
0x172a, 0x173c, 0x174e, 0x1761, 0x1774, 0x1787, 0x179a, 0x17ae,
0x17c1, 0x17d4, 0x17e7, 0x17fa, 0x180d, 0x1820, 0x1833, 0x1847,
0x185a, 0x186d, 0x1881, 0x1894, 0x18a7, 0x18ba, 0x18cd, 0x18e0,
0x18f3, 0x1907, 0x191b, 0x192e, 0x1942, 0x1956, 0x196a, 0x197e,
// Entry 1580 - 15BF
0x1992, 0x19b7, 0x19ce, 0x19e5, 0x19fc, 0x1a13, 0x1a2b, 0x1a43,
0x1a5c, 0x1a74, 0x1a8c, 0x1aa4, 0x1abc, 0x1ad4, 0x1aec, 0x1b04,
0x1b1d, 0x1b35, 0x1b4e, 0x1b66, 0x1b7e, 0x1b96, 0x1baf, 0x1bc8,
0x1be1, 0x1bfa, 0x1c13, 0x1c2a, 0x1c41, 0x1c59, 0x1c71, 0x1c88,
0x1ca1, 0x1cb9, 0x1cd1, 0x1ce9, 0x1d01, 0x1d1a, 0x1d32, 0x1d4a,
0x1d62, 0x1d7a, 0x1d93, 0x1dac, 0x1dc5, 0x1ddd, 0x1df6, 0x1e0f,
0x1e28, 0x1e41, 0x1e5b, 0x1e75, 0x1e8f, 0x1eaa, 0x1ecc, 0x1ef2,
0x1f17, 0x1f37, 0x1f58, 0x1f82, 0x1fa2, 0x1fc8, 0x1fe3, 0x1ffe,
// Entry 15C0 - 15FF
0x201a, 0x2037, 0x2053, 0x2070, 0x208e, 0x20ab, 0x20c8, 0x20e4,
0x2100, 0x211c, 0x2139, 0x2156, 0x2173, 0x218f, 0x21ab, 0x21cc,
0x21ee, 0x2212, 0x2236, 0x2259, 0x227d, 0x22a1, 0x22c6, 0x22e9,
0x230d, 0x2331, 0x2355, 0x2379, 0x239c, 0x23bc, 0x23dd, 0x2401,
0x2422, 0x2446, 0x245b, 0x2470, 0x2486, 0x249c, 0x24b2, 0x24c8,
0x24df, 0x24f5, 0x250b, 0x2522, 0x2538, 0x254e, 0x2564, 0x257a,
0x2590, 0x25a6, 0x25bd, 0x25d4, 0x25ec, 0x2602, 0x2618, 0x262e,
0x2644, 0x2662, 0x2679, 0x2698, 0x26ae, 0x26cc, 0x26e3, 0x2702,
// Entry 1600 - 163F
0x2719, 0x272f, 0x2746, 0x275c, 0x2773, 0x2789, 0x27a5, 0x27c1,
0x27dd, 0x27f9, 0x2815, 0x2831, 0x284d, 0x286a, 0x2886, 0x28a2,
0x28c5, 0x28e8, 0x2905, 0x2925, 0x2945, 0x295c, 0x2973, 0x298b,
0x29a3, 0x29bb, 0x29d3, 0x29eb, 0x2a09, 0x2a27, 0x2a44, 0x2a62,
0x2a85, 0x2aa3, 0x2ac1, 0x2ade, 0x2afc, 0x2b1c, 0x2b3c, 0x2b5f,
0x2b79, 0x2b88, 0x2b98, 0x2ba7, 0x2bb7, 0x2bc7, 0x2bd6, 0x2be6,
0x2bf5, 0x2c05, 0x2c15, 0x2c24, 0x2c34, 0x2c43, 0x2c53, 0x2c62,
0x2c71, 0x2c81, 0x2c90, 0x2ca0, 0x2caf, 0x2cbe, 0x2ccd, 0x2cdc,
// Entry 1640 - 167F
0x2ceb, 0x2cfb, 0x2d0b, 0x2d1a, 0x2d29, 0x2d3a, 0x2d4a, 0x2d5c,
0x2d6e, 0x2d80, 0x2d93, 0x2da6, 0x2db9, 0x2dcc, 0x2dde, 0x2df0,
0x2e09, 0x2e22, 0x2e3b, 0x2e50, 0x2e66, 0x2e81, 0x2e96, 0x2eab,
0x2ec0, 0x2ed5, 0x2eea, 0x2eff, 0x2f13, 0x2f27, 0x2f36, 0x2f44,
0x2f5a, 0x2f6d, 0x2f7d, 0x2f8c, 0x2f9b, 0x2fac, 0x2fbc, 0x2fcc,
0x2fdb, 0x2fec, 0x2ffd, 0x300d, 0x301d, 0x302d, 0x303e, 0x304f,
0x305f, 0x306f, 0x307f, 0x3090, 0x30a0, 0x30b0, 0x30c1, 0x30d1,
0x30e1, 0x30f1, 0x3101, 0x3111, 0x3122, 0x3134, 0x3144, 0x3153,
// Entry 1680 - 16BF
0x3162, 0x3172, 0x3182, 0x3191, 0x31a1, 0x31b0, 0x31c0, 0x31cf,
0x31e0, 0x31f0, 0x3204, 0x3218, 0x322c, 0x3240, 0x3254, 0x326e,
0x3287, 0x32a1, 0x32bb, 0x32d6, 0x32ef, 0x3308, 0x3322, 0x333d,
0x3357, 0x3371, 0x338b, 0x33a4, 0x33bd, 0x33d7, 0x33f2, 0x340c,
0x3425, 0x343f, 0x3458, 0x3472, 0x348d, 0x34a7, 0x34c0, 0x34da,
0x34f3, 0x350d, 0x3527, 0x3541, 0x355a, 0x3573, 0x358c, 0x35a6,
0x35c0, 0x35da, 0x35f3, 0x360c, 0x3625, 0x3640, 0x365b, 0x3675,
0x368f, 0x36aa, 0x36c4, 0x36ea, 0x3703, 0x371c, 0x3734, 0x374d,
// Entry 16C0 - 16FF
0x3765, 0x377e, 0x3796, 0x37af, 0x37c8, 0x37e1, 0x37fb, 0x3814,
0x382d, 0x3847, 0x3861, 0x387a, 0x3894, 0x38af, 0x38c9, 0x38e3,
0x38fd, 0x3917, 0x3931, 0x3948, 0x395f, 0x3975, 0x398a, 0x399f,
0x39b6, 0x39cc, 0x39e2, 0x39f7, 0x3a0e, 0x3a25, 0x3a3b, 0x3a55,
0x3a69, 0x3a7e, 0x3a95, 0x3aab, 0x3ac0, 0x3ad5, 0x3aeb, 0x3b01,
0x3b1c, 0x3b36, 0x3b50, 0x3b6b, 0x3b80, 0x3b9a, 0x3bb3, 0x3bcc,
0x3be6, 0x3c00, 0x3c16, 0x3c2b, 0x3c3f, 0x3c53, 0x3c68, 0x3c7d,
0x3c97, 0x3cb0, 0x3cc9, 0x3ce3, 0x3cf7, 0x3d10, 0x3d28, 0x3d40,
// Entry 1700 - 173F
0x3d59, 0x3d72, 0x3d84, 0x3d96, 0x3da9, 0x3dbd, 0x3dcf, 0x3de1,
0x3df3, 0x3e06, 0x3e18, 0x3e2a, 0x3e3c, 0x3e4f, 0x3e61, 0x3e73,
0x3e86, 0x3e9a, 0x3eac, 0x3ebe, 0x3ed0, 0x3ee2, 0x3ef4, 0x3f05,
0x3f17, 0x3f2c, 0x3f41, 0x3f56, 0x3f6b, 0x3f81, 0x3f91, 0x3fa8,
0x3fbf, 0x3fd7, 0x3fef, 0x4005, 0x401c, 0x4033, 0x4046, 0x405d,
0x4075, 0x408b, 0x40a1, 0x40b8, 0x40cb, 0x40df, 0x40f9, 0x410b,
0x4124, 0x4138, 0x414f, 0x4167, 0x417d, 0x4194, 0x41a6, 0x41b8,
0x41cf, 0x41e7, 0x41fe, 0x4214, 0x422a, 0x4241, 0x4253, 0x4269,
// Entry 1740 - 177F
0x4280, 0x4292, 0x42a5, 0x42b7, 0x42ca, 0x42dc, 0x42f4, 0x430c,
0x4323, 0x433a, 0x434d, 0x435e, 0x4374, 0x4385, 0x4397, 0x43a8,
0x43ba, 0x43cc, 0x43de, 0x43f1, 0x4409, 0x442a, 0x444b, 0x446e,
0x4488, 0x44a9, 0x44c7, 0x44f3, 0x450d, 0x4527, 0x4541, 0x4554,
0x4569, 0x4584, 0x459a, 0x45b5, 0x45ca, 0x45e0, 0x45f6, 0x460d,
0x4622, 0x4638, 0x464d, 0x4669, 0x467f, 0x4694, 0x46aa, 0x46c0,
0x46d6, 0x46f1, 0x470d, 0x4723, 0x4737, 0x474b, 0x4765, 0x477f,
0x4799, 0x47ae, 0x47c3, 0x47e0, 0x4804, 0x481c, 0x4833, 0x484a,
// Entry 1780 - 17BF
0x4863, 0x487b, 0x4893, 0x48aa, 0x48c3, 0x48dc, 0x48f4, 0x490c,
0x4923, 0x493a, 0x4953, 0x496b, 0x4983, 0x499a, 0x49b3, 0x49cc,
0x49e4, 0x49f7, 0x4a0e, 0x4a21, 0x4a33, 0x4a44, 0x4a58, 0x4a7b,
0x4a92, 0x4aa4, 0x4ab9, 0x4ace, 0x4ae6, 0x4af8, 0x4b0b, 0x4b2e,
0x4b46, 0x4b58, 0x4b71, 0x4b85, 0x4b98, 0x4bb3, 0x4bcc, 0x4bec,
0x4c17, 0x4c43, 0x4c5e, 0x4c80, 0x4c9b, 0x4cb8, 0x4cdc, 0x4d07,
0x4d2c, 0x4d53, 0x4d78, 0x4d9f, 0x4dbe, 0x4dd9, 0x4dfd, 0x4e16,
0x4e36, 0x4e56, 0x4e73, 0x4e99, 0x4ebf, 0x4ee5, 0x4efb, 0x4f18,
// Entry 17C0 - 17FF
0x4f35, 0x4f52, 0x4f6f, 0x4f8d, 0x4fab, 0x4fce, 0x4ff1, 0x500d,
0x5021, 0x5034, 0x504d, 0x5075, 0x5091, 0x50aa, 0x50c4, 0x50de,
0x50fd, 0x5113, 0x512a, 0x5145, 0x5160, 0x517b, 0x519d, 0x51ba,
0x51e1, 0x51f8, 0x5210, 0x5223, 0x5237, 0x524a, 0x525f, 0x527b,
0x5290, 0x52ac, 0x52c1, 0x52dd, 0x52f4, 0x5312, 0x532a, 0x5349,
0x535e, 0x5374, 0x5389, 0x53a5, 0x53b7, 0x53d3, 0x53e5, 0x53fc,
0x540f, 0x5421, 0x5438, 0x544a, 0x5461, 0x5474, 0x548c, 0x54ae,
0x54d0, 0x54f2, 0x550b, 0x551d, 0x5534, 0x5546, 0x555d, 0x556f,
// Entry 1800 - 183F
0x5581, 0x5599, 0x55ab, 0x55c5, 0x55d7, 0x55e9, 0x55fb, 0x560d,
0x561f, 0x5636, 0x564d, 0x565f, 0x5671, 0x5686, 0x56a0, 0x56b7,
0x56d3, 0x56eb, 0x5708, 0x5723, 0x5745, 0x5761, 0x5784, 0x579e,
0x57bd, 0x57de, 0x5804, 0x581d, 0x583d, 0x584f, 0x5868, 0x5882,
0x589c, 0x58b4, 0x58cc, 0x58e5, 0x5901, 0x591d, 0x5939, 0x5958,
0x596b, 0x597d, 0x598f, 0x59a3, 0x59b6, 0x59c9, 0x59db, 0x59ef,
0x5a03, 0x5a16, 0x5a24, 0x5a33, 0x5a41, 0x5a59, 0x5a6c, 0x5a82,
0x5a93, 0x5aaf, 0x5acb, 0x5ae7, 0x5b03, 0x5b26, 0x5b42, 0x5b5f,
// Entry 1840 - 187F
0x5b7c, 0x5b99, 0x5bba, 0x5be1, 0x5c08, 0x5c30, 0x5c58, 0x5c81,
0x5cb6, 0x5ceb, 0x5d12, 0x5d38, 0x5d63, 0x5d8e, 0x5dbb, 0x5de8,
0x5e13, 0x5e3e, 0x5e6b, 0x5e98, 0x5ec3, 0x5ed9, 0x5ef0, 0x5f04,
0x5f1b, 0x5f33, 0x5f4b, 0x5f5d, 0x5f6f, 0x5f81, 0x5f94, 0x5fa6,
0x5fb8, 0x5fcb, 0x5fde, 0x5ff1, 0x6004, 0x6018, 0x602b, 0x603e,
0x6051, 0x6065, 0x6078, 0x608b, 0x609e, 0x60b1, 0x60c4, 0x60d7,
0x60ea, 0x60fd, 0x6110, 0x6123, 0x6136, 0x6149, 0x615c, 0x616f,
0x6182, 0x61a4, 0x61c5, 0x61e5, 0x6202, 0x621e, 0x623d, 0x625a,
// Entry 1880 - 18BF
0x6276, 0x6295, 0x62ab, 0x62c0, 0x62e4, 0x6308, 0x631c, 0x6330,
0x6344, 0x6357, 0x636a, 0x637f, 0x6393, 0x63a7, 0x63ba, 0x63cf,
0x63e4, 0x63f8, 0x640a, 0x641e, 0x6432, 0x6446, 0x645e, 0x6476,
0x6484, 0x649d, 0x64ac, 0x64c6, 0x64e0, 0x64ef, 0x6503, 0x6512,
0x652c, 0x653b, 0x6555, 0x6564, 0x657e, 0x6594, 0x65a3, 0x65bd,
0x65cc, 0x65db, 0x65ea, 0x6604, 0x6613, 0x662d, 0x6645, 0x665d,
0x666c, 0x6686, 0x66a0, 0x66af, 0x66c9, 0x66d9, 0x66e8, 0x6702,
0x6712, 0x6721, 0x6731, 0x6741, 0x674f, 0x675d, 0x676d, 0x677f,
// Entry 18C0 - 18FF
0x6798, 0x67ab, 0x67bd, 0x67d4, 0x67e6, 0x67fd, 0x680f, 0x6833,
0x684a, 0x6860, 0x686e, 0x687e, 0x6899, 0x68b6, 0x68ce, 0x68e9,
0x68f9, 0x690a, 0x691b, 0x692b, 0x693c, 0x694d, 0x695d, 0x696e,
0x697e, 0x698f, 0x699f, 0x69b0, 0x69c0, 0x69d0, 0x69e0, 0x69f1,
0x6a02, 0x6a12, 0x6a23, 0x6a33, 0x6a44, 0x6a54, 0x6a65, 0x6a76,
0x6a88, 0x6a99, 0x6aa9, 0x6ab9, 0x6ac9, 0x6ad9, 0x6aea, 0x6afa,
0x6b0a, 0x6b1b, 0x6b2b, 0x6b3a, 0x6b54, 0x6b6e, 0x6b82, 0x6b95,
0x6ba8, 0x6bbc, 0x6bcf, 0x6be3, 0x6bf6, 0x6c0d, 0x6c24, 0x6c3b,
// Entry 1900 - 193F
0x6c52, 0x6c69, 0x6c80, 0x6c97, 0x6cb4, 0x6cce, 0x6cdd, 0x6cee,
0x6d07, 0x6d2c, 0x6d45, 0x6d65, 0x6d7e, 0x6d8f, 0x6d9f, 0x6daf,
0x6dc1, 0x6dd2, 0x6de3, 0x6df3, 0x6e05, 0x6e17, 0x6e28, 0x6e39,
0x6e4b, 0x6e5c, 0x6e6f, 0x6e81, 0x6e93, 0x6ea7, 0x6eba, 0x6ecd,
0x6edf, 0x6ef3, 0x6f07, 0x6f1a, 0x6f2c, 0x6f3e, 0x6f50, 0x6f63,
0x6f75, 0x6f88, 0x6f9b, 0x6fae, 0x6fc1, 0x6fd4, 0x6fe6, 0x6ff8,
0x700a, 0x701d, 0x702f, 0x7041, 0x7053, 0x7065, 0x7078, 0x708a,
0x709c, 0x70ae, 0x70c1, 0x70d3, 0x70e6, 0x70f8, 0x710b, 0x711d,
// Entry 1940 - 197F
0x712f, 0x7141, 0x7154, 0x716d, 0x7189, 0x7197, 0x71a8, 0x71b5,
0x71d0, 0x71f2, 0x7212, 0x7236, 0x7254, 0x7271, 0x728e, 0x72b3,
0x72d7, 0x72f5, 0x7317, 0x7332, 0x734b, 0x736e, 0x7392, 0x73b6,
0x73da, 0x73fd, 0x7421, 0x7445, 0x7469, 0x748c, 0x74b0, 0x74d4,
0x74f8, 0x751c, 0x753f, 0x7563, 0x7588, 0x75ac, 0x75d0, 0x75f4,
0x7617, 0x763c, 0x7661, 0x7686, 0x76aa, 0x76cf, 0x76f4, 0x7718,
0x773c, 0x7760, 0x7785, 0x77a9, 0x77ce, 0x77f2, 0x7815, 0x7839,
0x785c, 0x7880, 0x78a4, 0x78c7, 0x78ea, 0x7910, 0x793b, 0x795f,
// Entry 1980 - 19BF
0x7983, 0x79ad, 0x79d9, 0x79fa, 0x7a1e, 0x7a41, 0x7a62, 0x7a89,
0x7aaf, 0x7ad5, 0x7afb, 0x7b0e, 0x7b1e, 0x7b30, 0x7b44, 0x7b69,
0x7b9d, 0x7bc6, 0x7bf7, 0x7c0e, 0x7c49, 0x7c62, 0x7c7b, 0x7c96,
0x7caa, 0x7cc3, 0x7cde, 0x7d0e, 0x7d39, 0x7d53, 0x7d6c, 0x7d8e,
0x7da9, 0x7dcd, 0x7df0, 0x7e15, 0x7e35, 0x7e55, 0x7e74, 0x7e9d,
0x7eae, 0x7ecf, 0x7ee7, 0x7f06, 0x7f28, 0x7f3f, 0x7f5e, 0x7f75,
0x7f8b, 0x7fa1, 0x7fb4, 0x7fc9, 0x7fe5, 0x800c, 0x8028, 0x8045,
0x8061, 0x8084, 0x80a0, 0x80bc, 0x80da, 0x80f6, 0x8116, 0x8131,
// Entry 19C0 - 19FF
0x814d, 0x8169, 0x8191, 0x81ad, 0x81d2, 0x81ee, 0x820f, 0x822c,
0x824e, 0x8277, 0x8293, 0x82b0, 0x82cd, 0x82ed, 0x8309, 0x832e,
0x8351, 0x836d, 0x8389, 0x83a6, 0x83cf, 0x83f3, 0x840f, 0x842b,
0x8447, 0x8465, 0x848a, 0x849a, 0x84ba, 0x84da, 0x84f7, 0x8515,
0x8533, 0x8553, 0x856c, 0x8586, 0x859f, 0x85bf, 0x85d8, 0x85f1,
0x8613, 0x862c, 0x8645, 0x865e, 0x8677, 0x8690, 0x86a9, 0x86c2,
0x86db, 0x86fd, 0x8716, 0x8730, 0x8749, 0x8762, 0x877b, 0x8794,
0x87ad, 0x87c4, 0x87e2, 0x87fd, 0x881c, 0x8833, 0x884a, 0x8861,
// Entry 1A00 - 1A3F
0x887c, 0x8898, 0x88bb, 0x88d2, 0x88f0, 0x8907, 0x891e, 0x8937,
0x894e, 0x896a, 0x898a, 0x89ad, 0x89c4, 0x89db, 0x89f2, 0x8a12,
0x8a30, 0x8a47, 0x8a60, 0x8a7a, 0x8a9b, 0x8ab6, 0x8ad5, 0x8aee,
0x8b0c, 0x8b2a, 0x8b48, 0x8b66, 0x8b87, 0x8ba9, 0x8bc9, 0x8be9,
0x8c09, 0x8c1e, 0x8c44, 0x8c6a, 0x8c90, 0x8cb6, 0x8cdc, 0x8d02,
0x8d28, 0x8d5b, 0x8d81, 0x8da7, 0x8dcd, 0x8de8, 0x8e03, 0x8e1f,
0x8e47, 0x8e6f, 0x8e92, 0x8eb2, 0x8eda, 0x8f00, 0x8f26, 0x8f4c,
0x8f72, 0x8f98, 0x8fbe, 0x8fe4, 0x900a, 0x9030, 0x9056, 0x907c,
// Entry 1A40 - 1A7F
0x90a2, 0x90ca, 0x90f0, 0x9116, 0x913c, 0x9164, 0x9190, 0x91b7,
0x91df, 0x920c, 0x9242, 0x926e, 0x9296, 0x92c3, 0x92ed, 0x9315,
0x933f, 0x9361, 0x9378, 0x9399, 0x93b2, 0x93d7, 0x93ee, 0x9419,
0x9437, 0x9455, 0x9478, 0x9492, 0x94b1, 0x94dc, 0x9505, 0x9530,
0x9559, 0x9578, 0x9599, 0x95c5, 0x95eb, 0x9616, 0x9635, 0x9653,
0x966c, 0x968d, 0x96a6, 0x96cf, 0x96ea, 0x9707, 0x9726, 0x9747,
0x9765, 0x977c, 0x97a7, 0x97c8, 0x97e1, 0x97fc, 0x9819, 0x9836,
0x984b, 0x9864, 0x987a, 0x9890, 0x98a6, 0x98bc, 0x98d7, 0x98f2,
// Entry 1A80 - 1ABF
0x9916, 0x992c, 0x9942, 0x9963, 0x9979, 0x998f, 0x99a1, 0x99b3,
0x99c5, 0x99f8, 0x9a17, 0x9a36, 0x9a55, 0x9a7b, 0x9aa1, 0x9ac1,
0x9adf, 0x9b05, 0x9b23, 0x9b41, 0x9b67, 0x9b8d, 0x9bab, 0x9bd1,
0x9bf7, 0x9c1d, 0x9c3b, 0x9c5e, 0x9c7c, 0x9c9e, 0x9cbc, 0x9cdd,
0x9cff, 0x9d1d, 0x9d54, 0x9d93, 0x9db1, 0x9dd1, 0x9e10, 0x9e2e,
0x9e5b, 0x9e88, 0x9eb5, 0x9ecc, 0x9ee8, 0x9f03, 0x9f1b, 0x9f3f,
0x9f57, 0x9f6e, 0x9f93, 0x9fb2, 0x9fd0, 0xa002, 0xa028, 0xa04c,
0xa071, 0xa094, 0xa0b9, 0xa0dc, 0xa102, 0xa126, 0xa153, 0xa17e,
// Entry 1AC0 - 1AFF
0xa1a3, 0xa1c6, 0xa1eb, 0xa20e, 0xa234, 0xa258, 0xa27b, 0xa29c,
0xa2c8, 0xa2f2, 0xa31e, 0xa348, 0xa374, 0xa39e, 0xa3ca, 0xa3f4,
0xa41b, 0xa440, 0xa46d, 0xa498, 0xa4bd, 0xa4e0, 0xa502, 0xa522,
0xa547, 0xa56a, 0xa58f, 0xa5b2, 0xa5d7, 0xa5fa, 0xa61d, 0xa63e,
0xa665, 0xa68a, 0xa6b1, 0xa6d6, 0xa705, 0xa732, 0xa753, 0xa772,
0xa797, 0xa7ba, 0xa7e0, 0xa804, 0xa829, 0xa84c, 0xa87c, 0xa8aa,
0xa8d0, 0xa8f4, 0xa920, 0xa94a, 0xa96b, 0xa98a, 0xa9af, 0xa9d2,
0xa9f7, 0xaa1a, 0xaa3f, 0xaa62, 0xaa87, 0xaaaa, 0xaad0, 0xaaf4,
// Entry 1B00 - 1B3F
0xab20, 0xab4a, 0xab75, 0xab9e, 0xabcd, 0xabfa, 0xac26, 0xac50,
0xac7c, 0xaca6, 0xacc7, 0xace6, 0xad0b, 0xad2e, 0xad53, 0xad76,
0xad9b, 0xadbe, 0xadee, 0xae1c, 0xae42, 0xae66, 0xae8b, 0xaeae,
0xaed3, 0xaef6, 0xaf25, 0xaf52, 0xaf81, 0xafae, 0xafe1, 0xb012,
0xb037, 0xb05a, 0xb07f, 0xb0a2, 0xb0c8, 0xb0ec, 0xb118, 0xb142,
0xb16d, 0xb196, 0xb1bd, 0xb1e2, 0xb20e, 0xb238, 0xb263, 0xb28c,
0xb2bc, 0xb2ea, 0xb30b, 0xb32a, 0xb34f, 0xb372, 0xb393, 0xb3b2,
0xb3d3, 0xb3f2, 0xb417, 0xb43a, 0xb45f, 0xb482, 0xb4a7, 0xb4ca,
// Entry 1B40 - 1B7F
0xb4ef, 0xb512, 0xb537, 0xb55a, 0xb57f, 0xb5a2, 0xb5c8, 0xb5ec,
0xb611, 0xb634, 0xb65a, 0xb67e, 0xb6a2, 0xb6c5, 0xb6e9, 0xb70d,
0xb736, 0xb75e, 0xb78c, 0xb7b6, 0xb7d2, 0xb7ea, 0xb80f, 0xb832,
0xb858, 0xb87c, 0xb8ac, 0xb8da, 0xb90a, 0xb938, 0xb96d, 0xb9a0,
0xb9d0, 0xb9fe, 0xba32, 0xba64, 0xba8f, 0xbab8, 0xbae3, 0xbb0c,
0xbb3c, 0xbb6a, 0xbb95, 0xbbbe, 0xbbed, 0xbc1a, 0xbc3f, 0xbc62,
0xbc88, 0xbcac, 0xbccd, 0xbcec, 0xbd1c, 0xbd4a, 0xbd7a, 0xbda8,
0xbddd, 0xbe10, 0xbe40, 0xbe6e, 0xbea2, 0xbed4, 0xbefa, 0xbf1e,
// Entry 1B80 - 1BBF
0xbf43, 0xbf66, 0xbf8b, 0xbfae, 0xbfd4, 0xbff8, 0xc028, 0xc056,
0xc086, 0xc0b4, 0xc0e9, 0xc11c, 0xc14c, 0xc17a, 0xc1ae, 0xc1e0,
0xc20a, 0xc232, 0xc25c, 0xc284, 0xc2b3, 0xc2e0, 0xc30a, 0xc332,
0xc360, 0xc38c, 0xc3b1, 0xc3d4, 0xc3fa, 0xc41e, 0xc448, 0xc470,
0xc49a, 0xc4c2, 0xc4f1, 0xc51e, 0xc548, 0xc570, 0xc59e, 0xc5ca,
0xc5eb, 0xc60a, 0xc62f, 0xc652, 0xc678, 0xc69c, 0xc6bd, 0xc6dc,
0xc700, 0xc722, 0xc745, 0xc766, 0xc786, 0xc7a4, 0xc7c7, 0xc7ea,
0xc817, 0xc844, 0xc870, 0xc89c, 0xc8cf, 0xc902, 0xc927, 0xc94c,
// Entry 1BC0 - 1BFF
0xc97b, 0xc9aa, 0xc9d8, 0xca06, 0xca3b, 0xca70, 0xca95, 0xcaba,
0xcae9, 0xcb18, 0xcb46, 0xcb74, 0xcb9b, 0xcbc2, 0xcbf3, 0xcc24,
0xcc54, 0xcc84, 0xcca5, 0xccc6, 0xccf1, 0xcd1c, 0xcd46, 0xcd70,
0xcda1, 0xcdd2, 0xcdf5, 0xce18, 0xce45, 0xce72, 0xce9e, 0xceca,
0xcefd, 0xcf30, 0xcf52, 0xcf74, 0xcfa0, 0xcfcc, 0xcff7, 0xd022,
0xd054, 0xd086, 0xd0aa, 0xd0ce, 0xd0fc, 0xd12a, 0xd157, 0xd184,
0xd1b8, 0xd1ec, 0xd211, 0xd236, 0xd265, 0xd294, 0xd2c2, 0xd2f0,
0xd317, 0xd33e, 0xd36f, 0xd3a0, 0xd3d0, 0xd400, 0xd425, 0xd44a,
// Entry 1C00 - 1C3F
0xd479, 0xd4a8, 0xd4d6, 0xd504, 0xd539, 0xd56e, 0xd595, 0xd5c6,
0xd5f6, 0xd62d, 0xd650, 0xd673, 0xd6a0, 0xd6cd, 0xd6f9, 0xd725,
0xd758, 0xd78b, 0xd7b0, 0xd7d5, 0xd804, 0xd833, 0xd861, 0xd88f,
0xd8c4, 0xd8f9, 0xd91c, 0xd93e, 0xd963, 0xd987, 0xd9a8, 0xd9c8,
0xd9ea, 0xda0b, 0xda30, 0xda54, 0xda79, 0xda9d, 0xdac0, 0xdae2,
0xdb17, 0xdb4c, 0xdb8b, 0xdbca, 0xdc08, 0xdc46, 0xdc8b, 0xdcd0,
0xdd08, 0xdd40, 0xdd82, 0xddc4, 0xde05, 0xde46, 0xde8e, 0xded6,
0xdf09, 0xdf3c, 0xdf79, 0xdfb6, 0xdff2, 0xe02e, 0xe071, 0xe0b4,
// Entry 1C40 - 1C7F
0xe0ea, 0xe120, 0xe160, 0xe1a0, 0xe1df, 0xe21e, 0xe264, 0xe2aa,
0xe2df, 0xe314, 0xe353, 0xe392, 0xe3d0, 0xe40e, 0xe453, 0xe498,
0xe4d0, 0xe508, 0xe54a, 0xe58c, 0xe5cd, 0xe60e, 0xe656, 0xe69e,
0xe6c2, 0xe6e6, 0xe71b, 0xe746, 0xe77a, 0xe7a3, 0xe7de, 0xe804,
0xe82a, 0xe84f, 0xe873, 0xe8a1, 0xe8ae, 0xe8c2, 0xe8cd, 0xe8de,
0xe8fd, 0xe930, 0xe959, 0xe98b, 0xe9b2, 0xe9eb, 0xea12, 0xea38,
0xea5b, 0xea7d, 0xeaa9, 0xeabe, 0xead2, 0xeaed, 0xeb10, 0xeb33,
0xeb63, 0xeb92, 0xebba, 0xebf0, 0xec15, 0xec3a, 0xec5e, 0xec81,
// Entry 1C80 - 1CBF
0xec96, 0xecaa, 0xecc5, 0xeceb, 0xed11, 0xed44, 0xed76, 0xed97,
0xedb8, 0xede3, 0xee1c, 0xee44, 0xee6c, 0xee93, 0xeeb9, 0xeedc,
0xeef5, 0xef0d, 0xef18, 0xef4d, 0xef78, 0xefac, 0xefd5, 0xf010,
0xf037, 0xf05d, 0xf082, 0xf0a6, 0xf0d4, 0xf0de, 0xf0e9, 0xf0f0,
0xf0f7, 0xf0ff, 0xf107, 0xf119, 0xf12a, 0xf13a, 0xf146, 0xf157,
0xf161, 0xf16b, 0xf17b, 0xf190, 0xf1a1, 0xf1b3, 0xf1c5, 0xf1cb,
0xf1de, 0xf1e9, 0xf1f0, 0xf1f7, 0xf205, 0xf219, 0xf228, 0xf242,
0xf25d, 0xf278, 0xf29d, 0xf2b7, 0xf2d2, 0xf2ed, 0xf312, 0xf318,
// Entry 1CC0 - 1CFF
0xf325, 0xf32b, 0xf33c, 0xf34a, 0xf358, 0xf36b, 0xf37c, 0xf38a,
0xf39d, 0xf3b4, 0xf3cb, 0xf3e5, 0xf3fb, 0xf411, 0xf426, 0xf434,
0xf449, 0xf44e, 0xf45a, 0xf466, 0xf474, 0xf489, 0xf49e, 0xf4a3,
0xf4cc, 0xf4f6, 0xf504, 0xf51b, 0xf526, 0xf52e, 0xf536, 0xf543,
0xf558, 0xf560, 0xf56d, 0xf57b, 0xf599, 0xf5b8, 0xf5cc, 0xf5e5,
0xf5fe, 0xf60e, 0xf623, 0xf639, 0xf650, 0xf65c, 0xf66e, 0xf676,
0xf696, 0xf6ab, 0xf6b5, 0xf6c6, 0xf6dd, 0xf6f2, 0xf701, 0xf715,
0xf729, 0xf73c, 0xf749, 0xf755, 0xf75d, 0xf76f, 0xf788, 0xf793,
// Entry 1D00 - 1D3F
0xf7a7, 0xf7b6, 0xf7c9, 0xf7d7, 0xf7ec, 0xf801, 0xf815, 0xf82c,
0xf846, 0xf861, 0xf87c, 0xf898, 0xf8ad, 0xf8c1, 0xf8d1, 0xf8f1,
0xf901, 0xf911, 0xf920, 0xf931, 0xf942, 0xf952, 0xf967, 0xf978,
0xf98f, 0xf9ab, 0xf9c8, 0xf9e8, 0xf9f6, 0xfa03, 0xfa10, 0xfa1f,
0xfa2d, 0xfa3b, 0xfa48, 0xfa57, 0xfa66, 0xfa74, 0xfa87, 0xfa96,
0xfaab, 0xfac5, 0xfae0, 0xfafe, 0xfb1c, 0xfb3a, 0xfb58, 0xfb7a,
0xfb98, 0xfbb6, 0xfbd4, 0xfbf2, 0xfc10, 0xfc2e, 0xfc4c, 0xfc6a,
0xfc7c, 0xfc86, 0xfc93, 0xfca4, 0xfcad, 0xfcb6, 0xfcc0, 0xfccb,
// Entry 1D40 - 1D7F
0xfcd5, 0xfcdd, 0xfcec, 0xfcf5, 0xfcfe, 0xfd06, 0xfd11, 0xfd1d,
0xfd2e, 0xfd37, 0xfd43, 0xfd4f, 0xfd5b, 0xfd64, 0xfd77, 0xfd84,
0xfd8e, 0xfd9f, 0xfdb0, 0xfdc0, 0xfdca, 0xfdd4, 0xfddd, 0xfde9,
0xfdf1, 0xfe01, 0xfe1d, 0xfe3a, 0xfe5e, 0xfe83, 0xfea6, 0xfec5,
0xfedf, 0xfefa, 0xff10, 0xff30, 0xff54, 0xff6e, 0xff87, 0xffa1,
0xffbb, 0xffd6, 0xfffa, 0x001a, 0x0034, 0x004e, 0x007a, 0x009b,
0x00c3, 0x00db, 0x00f4, 0x010f, 0x0130, 0x0155, 0x0185, 0x01b4,
0x01ce, 0x01e9, 0x0201, 0x020b, 0x0223, 0x023a, 0x0248, 0x025a,
// Entry 1D80 - 1DBF
0x0261, 0x0269, 0x0277, 0x027e, 0x028f, 0x029d, 0x02ad, 0x02c3,
0x02da, 0x02e9, 0x0304, 0x0314, 0x032a, 0x033a, 0x0348, 0x0356,
0x036d, 0x0378, 0x0391, 0x03a1, 0x03b8, 0x03cf, 0x03df, 0x03f5,
0x040c, 0x041d, 0x0425, 0x0431, 0x043f, 0x044e, 0x0456, 0x046d,
0x0477, 0x047f, 0x0490, 0x04a6, 0x04c4, 0x04cf, 0x04dc, 0x04ec,
0x0502, 0x0512, 0x0520, 0x0530, 0x0540, 0x0550, 0x0560, 0x056e,
0x0579, 0x0583, 0x058f, 0x059b, 0x05ad, 0x05be, 0x05cc, 0x05e2,
0x05fb, 0x0616, 0x062e, 0x064b, 0x0666, 0x0681, 0x069e, 0x06b9,
// Entry 1DC0 - 1DFF
0x06d7, 0x06f3, 0x070f, 0x072b, 0x0747, 0x0754, 0x0764, 0x076c,
0x0778, 0x0786, 0x07a1, 0x07bc, 0x07d5, 0x07ee, 0x0807, 0x0821,
0x083a, 0x0854, 0x0870, 0x088b, 0x08a4, 0x08bf, 0x08d9, 0x08f6,
0x0912, 0x092f, 0x0945, 0x0956, 0x0967, 0x097a, 0x098c, 0x099e,
0x09af, 0x09c2, 0x09d5, 0x09e7, 0x09f8, 0x0a0c, 0x0a20, 0x0a33,
0x0a4c, 0x0a66, 0x0a80, 0x0a97, 0x0aae, 0x0ac7, 0x0adf, 0x0af7,
0x0b0e, 0x0b27, 0x0b40, 0x0b58, 0x0b6f, 0x0b89, 0x0ba3, 0x0bbc,
0x0bdb, 0x0bfb, 0x0c1b, 0x0c39, 0x0c54, 0x0c6e, 0x0c90, 0x0cad,
// Entry 1E00 - 1E3F
0x0cc8, 0x0ce6, 0x0d02, 0x0d24, 0x0d3f, 0x0d4f, 0x0d61, 0x0d70,
0x0d7d, 0x0d8d, 0x0d9c, 0x0dac, 0x0db9, 0x0dc9, 0x0dd9, 0x0de9,
0x0df9, 0x0e14, 0x0e30, 0x0e44, 0x0e59, 0x0e73, 0x0e8b, 0x0ea6,
0x0ec0, 0x0ed9, 0x0ef3, 0x0f0b, 0x0f21, 0x0f3a, 0x0f52, 0x0f69,
0x0f82, 0x0f9c, 0x0fb5, 0x0fcf, 0x0fe4, 0x1000, 0x1016, 0x1036,
0x1057, 0x1079, 0x109c, 0x10c2, 0x10e7, 0x1109, 0x1127, 0x1143,
0x1176, 0x1195, 0x11b0, 0x11d3, 0x11f8, 0x121c, 0x123f, 0x1263,
0x1289, 0x12af, 0x12d4, 0x12f9, 0x1323, 0x1348, 0x135f, 0x1374,
// Entry 1E40 - 1E7F
0x138c, 0x13a3, 0x13cc, 0x13f5, 0x1417, 0x143a, 0x145d, 0x1473,
0x1487, 0x149e, 0x14b4, 0x14cb, 0x14df, 0x14f6, 0x150d, 0x1524,
0x153b, 0x1551, 0x1568, 0x1580, 0x1599, 0x15b9, 0x15db, 0x15f1,
0x1605, 0x161c, 0x1632, 0x1648, 0x165f, 0x1674, 0x1687, 0x169d,
0x16b2, 0x16ce, 0x16ed, 0x1720, 0x1751, 0x176b, 0x1791, 0x17b1,
0x17cb, 0x17e5, 0x17f8, 0x1815, 0x183f, 0x1856, 0x187a, 0x189f,
0x18c4, 0x18ef, 0x191b, 0x1947, 0x1962, 0x197e, 0x199a, 0x19a1,
0x19ab, 0x19bf, 0x19cb, 0x19df, 0x19e8, 0x19f1, 0x19f6, 0x1a00,
// Entry 1E80 - 1EBF
0x1a11, 0x1a21, 0x1a33, 0x1a4d, 0x1a65, 0x1a71, 0x1a7e, 0x1a8d,
0x1a9c, 0x1aa6, 0x1ab8, 0x1ac0, 0x1ace, 0x1ad7, 0x1ae8, 0x1af5,
0x1b04, 0x1b0f, 0x1b18, 0x1b23, 0x1b32, 0x1b3a, 0x1b45, 0x1b4a,
0x1b58, 0x1b67, 0x1b6e, 0x1b7d, 0x1b88, 0x1b97, 0x1ba2, 0x1bac,
0x1bb8, 0x1bbd, 0x1bc5, 0x1bd4, 0x1be3, 0x1bf3, 0x1c03, 0x1c12,
0x1c24, 0x1c3e, 0x1c5c, 0x1c65, 0x1c6c, 0x1c71, 0x1c7b, 0x1c84,
0x1c8a, 0x1c9e, 0x1ca8, 0x1cb6, 0x1cc4, 0x1cd3, 0x1cdc, 0x1cea,
0x1cf3, 0x1cfe, 0x1d15, 0x1d30, 0x1d46, 0x1d6d, 0x1d98, 0x1da7,
// Entry 1EC0 - 1EFF
0x1dba, 0x1dd2, 0x1dde, 0x1dea, 0x1df7, 0x1e12, 0x1e24, 0x1e38,
0x1e4e, 0x1e74, 0x1e96, 0x1ea2, 0x1eae, 0x1ebe, 0x1ecb, 0x1ed9,
0x1ee2, 0x1ef0, 0x1efb, 0x1f09, 0x1f1f, 0x1f2a, 0x1f3d, 0x1f49,
0x1f55, 0x1f65, 0x1f7b, 0x1f90, 0x1fa8, 0x1fbf, 0x1fd9, 0x1ff3,
0x2010, 0x201e, 0x202f, 0x2036, 0x2047, 0x2054, 0x2064, 0x2082,
0x20a3, 0x20bd, 0x20da, 0x20fd, 0x2123, 0x213c, 0x2155, 0x2177,
0x2199, 0x21a1, 0x21a9, 0x21bd, 0x21d1, 0x21ea, 0x2203, 0x2213,
0x2223, 0x222c, 0x2237, 0x2246, 0x2257, 0x226c, 0x2283, 0x22a3,
// Entry 1F00 - 1F3F
0x22c5, 0x22e0, 0x22fd, 0x2305, 0x231c, 0x232a, 0x2339, 0x234b,
0x2366, 0x2384, 0x238e, 0x2398, 0x23a4, 0x23b1, 0x23be, 0x23d4,
0x23e8, 0x23fd, 0x2416, 0x2424, 0x2430, 0x243c, 0x2449, 0x2456,
0x246a, 0x2474, 0x247d, 0x2486, 0x248d, 0x2496, 0x249c, 0x24a0,
0x24a6, 0x24c9, 0x24f3, 0x2501, 0x2509, 0x2517, 0x2549, 0x2560,
0x2577, 0x2589, 0x25a4, 0x25c2, 0x25e9, 0x25f4, 0x25fc, 0x2604,
0x261e, 0x2629, 0x262c, 0x2630, 0x2633, 0x2647, 0x2655, 0x2666,
0x2676, 0x2688, 0x2693, 0x26a3, 0x26af, 0x26bc, 0x26ca, 0x26d0,
// Entry 1F40 - 1F7F
0x26f5, 0x271b, 0x2732, 0x274a, 0x275f, 0x276f, 0x2780, 0x278d,
0x279c, 0x27af, 0x27bb, 0x27c4, 0x27d9, 0x27eb, 0x2800, 0x2813,
0x2829, 0x284b, 0x286d, 0x2882, 0x289a, 0x28ae, 0x28c2, 0x28db,
0x28f4, 0x2913, 0x2935, 0x2954, 0x2976, 0x2995, 0x29b7, 0x29d5,
0x29f3, 0x2a09, 0x2a2c, 0x2a4e, 0x2a7a, 0x2a8b, 0x2aa6, 0x2ac0,
0x2adc, 0x2b02, 0x2b3a, 0x2b78, 0x2b91, 0x2ba8, 0x2bc5, 0x2bdd,
0x2c03, 0x2c27, 0x2c5d, 0x2c99, 0x2cae, 0x2cc9, 0x2ce2, 0x2cef,
0x2cfd, 0x2d02, 0x2d0e, 0x2d1c, 0x2d26, 0x2d31, 0x2d3a, 0x2d46,
// Entry 1F80 - 1FBF
0x2d53, 0x2d5d, 0x2d68, 0x2d79, 0x2d89, 0x2d97, 0x2da4, 0x2db5,
0x2dc3, 0x2dc6, 0x2dcd, 0x2dd3, 0x2de5, 0x2df7, 0x2e06, 0x2e1c,
0x2e2b, 0x2e30, 0x2e39, 0x2e48, 0x2e58, 0x2e6a, 0x2e7d, 0x2e8e,
0x2ea2, 0x2ea7, 0x2eac, 0x2ed4, 0x2ede, 0x2ef0, 0x2f04, 0x2f0c,
0x2f27, 0x2f43, 0x2f54, 0x2f60, 0x2f6c, 0x2f7e, 0x2f86, 0x2f92,
0x2fa2, 0x2faf, 0x2fb4, 0x2fbf, 0x2fca, 0x2fe6, 0x3007, 0x3027,
0x3048, 0x306a, 0x3088, 0x30a9, 0x30cb, 0x30eb, 0x310a, 0x312d,
0x314d, 0x3171, 0x3195, 0x31bc, 0x31e0, 0x3205, 0x322f, 0x325a,
// Entry 1FC0 - 1FFF
0x3280, 0x32a8, 0x32c9, 0x32ee, 0x330e, 0x3331, 0x3353, 0x337b,
0x33a0, 0x33bf, 0x33e2, 0x3400, 0x3421, 0x3445, 0x346f, 0x3493,
0x34b7, 0x34dd, 0x34ff, 0x3524, 0x3545, 0x3565, 0x3586, 0x35a6,
0x35cd, 0x35f0, 0x3614, 0x3637, 0x365d, 0x3682, 0x36a7, 0x36cc,
0x36f8, 0x3717, 0x3736, 0x3751, 0x3772, 0x379a, 0x37be, 0x37e1,
0x3807, 0x382b, 0x3845, 0x385e, 0x3879, 0x389d, 0x38c3, 0x38e6,
0x390a, 0x3925, 0x3933, 0x395a, 0x396d, 0x3978, 0x3995, 0x39a5,
0x39c0, 0x39de, 0x39ed, 0x39ff, 0x3a25, 0x3a31, 0x3a47, 0x3a52,
// Entry 2000 - 203F
0x3a73, 0x3a88, 0x3aaa, 0x3ab5, 0x3ac6, 0x3ad7, 0x3af8, 0x3b19,
0x3b38, 0x3b55, 0x3b73, 0x3b8b, 0x3ba5, 0x3bc1, 0x3bce, 0x3bd7,
0x3bea, 0x3bfd, 0x3c18, 0x3c32, 0x3c4d, 0x3c69, 0x3c84, 0x3ca0,
0x3cc0, 0x3cdd, 0x3cfd, 0x3d1e, 0x3d3c, 0x3d5d, 0x3d7a, 0x3d99,
0x3db6, 0x3dcd, 0x3deb, 0x3e0b, 0x3e29, 0x3e3b, 0x3e54, 0x3e83,
0x3eb2, 0x3ebf, 0x3ecf, 0x3ee1, 0x3ef6, 0x3f23, 0x3f38, 0x3f4e,
0x3f65, 0x3f7b, 0x3f91, 0x3fa7, 0x3fbd, 0x3fea, 0x401a, 0x4045,
0x407b, 0x40af, 0x40dc, 0x4114, 0x414a, 0x4172, 0x41a6, 0x41d8,
// Entry 2040 - 207F
0x4202, 0x422a, 0x4256, 0x4285, 0x4290, 0x429d, 0x42a9, 0x42c0,
0x42ce, 0x42e6, 0x42fe, 0x431b, 0x4338, 0x4352, 0x4362, 0x4374,
0x4386, 0x4392, 0x4396, 0x43a5, 0x43b7, 0x43c8, 0x43dc, 0x43f6,
0x4413, 0x4422, 0x443a, 0x4446, 0x444e, 0x4458, 0x446f, 0x4486,
0x44aa, 0x44cd, 0x44ee, 0x4511, 0x4547, 0x457c, 0x45b2, 0x45bd,
0x45c6, 0x45d1, 0x45ec, 0x460f, 0x4633, 0x4654, 0x4677, 0x468a,
0x469f, 0x46b6, 0x46c2, 0x46d5, 0x46e4, 0x46f6, 0x4709, 0x4718,
0x4733, 0x474b, 0x4761, 0x477f, 0x4791, 0x47a7, 0x47b6, 0x47ca,
// Entry 2080 - 20BF
0x47ea, 0x47fe, 0x481c, 0x4830, 0x484a, 0x485e, 0x4871, 0x488c,
0x48a9, 0x48c6, 0x48e5, 0x4903, 0x4922, 0x493d, 0x4961, 0x4972,
0x498a, 0x499f, 0x49b0, 0x49c9, 0x49e3, 0x49fe, 0x4a17, 0x4a27,
0x4a38, 0x4a44, 0x4a4c, 0x4a5e, 0x4a78, 0x4a96, 0x4ac1, 0x4af1,
0x4b14, 0x4b1c, 0x4b25, 0x4b2d, 0x4b3e, 0x4b4d, 0x4b58, 0x4b76,
0x4b89, 0x4b91, 0x4bac, 0x4bc0, 0x4bd1, 0x4be2, 0x4bf5, 0x4c07,
0x4c19, 0x4c2a, 0x4c3d, 0x4c50, 0x4c62, 0x4c74, 0x4c89, 0x4c9e,
0x4cb5, 0x4ccc, 0x4ce2, 0x4cf8, 0x4d10, 0x4d27, 0x4d3e, 0x4d53,
// Entry 20C0 - 20FF
0x4d6a, 0x4d81, 0x4d9a, 0x4db2, 0x4dca, 0x4de1, 0x4dfa, 0x4e13,
0x4e2b, 0x4e43, 0x4e5e, 0x4e79, 0x4e96, 0x4eb3, 0x4ecf, 0x4eeb,
0x4f09, 0x4f26, 0x4f43, 0x4f5e, 0x4f71, 0x4f84, 0x4f99, 0x4fad,
0x4fc1, 0x4fd4, 0x4fe9, 0x4ffe, 0x5012, 0x5026, 0x503d, 0x5054,
0x506d, 0x5086, 0x509e, 0x50b6, 0x50d0, 0x50e9, 0x5102, 0x5119,
0x513b, 0x515d, 0x517f, 0x51a1, 0x51c3, 0x51e5, 0x5207, 0x5229,
0x524b, 0x526d, 0x528f, 0x52b1, 0x52d3, 0x52f5, 0x5317, 0x5339,
0x535b, 0x537d, 0x539f, 0x53c1, 0x53e3, 0x5405, 0x5427, 0x5449,
// Entry 2100 - 213F
0x546b, 0x548d, 0x54ab, 0x54c9, 0x54e7, 0x5505, 0x5523, 0x5541,
0x555f, 0x557d, 0x559b, 0x55b9, 0x55d7, 0x55f5, 0x5613, 0x5631,
0x564f, 0x566d, 0x568b, 0x56a9, 0x56c7, 0x56e5, 0x5703, 0x5721,
0x573f, 0x575d, 0x577b, 0x5799, 0x57b5, 0x57d1, 0x57ed, 0x5809,
0x5825, 0x5841, 0x585d, 0x5879, 0x5895, 0x58b1, 0x58cd, 0x58e9,
0x5905, 0x5921, 0x593d, 0x5959, 0x5975, 0x5991, 0x59ad, 0x59c9,
0x59e5, 0x5a01, 0x5a1d, 0x5a39, 0x5a55, 0x5a71, 0x5a83, 0x5aa1,
0x5abf, 0x5adf, 0x5aff, 0x5b1e, 0x5b3d, 0x5b5e, 0x5b7e, 0x5b9e,
// Entry 2140 - 217F
0x5bbc, 0x5bd4, 0x5bec, 0x5c06, 0x5c1f, 0x5c38, 0x5c50, 0x5c6a,
0x5c84, 0x5c9d, 0x5cb6, 0x5cd1, 0x5cee, 0x5d0b, 0x5d26, 0x5d41,
0x5d6a, 0x5d93, 0x5dba, 0x5de1, 0x5e0d, 0x5e39, 0x5e63, 0x5e8d,
0x5eae, 0x5ed5, 0x5efc, 0x5f1d, 0x5f3d, 0x5f63, 0x5f89, 0x5fa9,
0x5fc8, 0x5fed, 0x6012, 0x6031, 0x604f, 0x6073, 0x6097, 0x60b5,
0x60da, 0x6105, 0x612f, 0x6159, 0x6184, 0x61ae, 0x61d8, 0x61fd,
0x6221, 0x624b, 0x6274, 0x629d, 0x62c7, 0x62f0, 0x6319, 0x633d,
0x6363, 0x638f, 0x63bb, 0x63e7, 0x6413, 0x643f, 0x646b, 0x6491,
// Entry 2180 - 21BF
0x64b5, 0x64df, 0x6509, 0x6533, 0x655d, 0x6587, 0x65b1, 0x65d5,
0x65ff, 0x662f, 0x665f, 0x668f, 0x66be, 0x66ed, 0x671d, 0x674c,
0x677b, 0x67aa, 0x67d9, 0x6808, 0x6837, 0x6867, 0x6897, 0x68c1,
0x68ea, 0x6913, 0x693a, 0x6961, 0x697f, 0x699b, 0x69c4, 0x69ed,
0x6a0f, 0x6a37, 0x6a5f, 0x6a80, 0x6aa7, 0x6ace, 0x6aee, 0x6b14,
0x6b3a, 0x6b59, 0x6b86, 0x6bb3, 0x6bd9, 0x6c05, 0x6c31, 0x6c56,
0x6c84, 0x6cb2, 0x6cd9, 0x6d05, 0x6d31, 0x6d56, 0x6d88, 0x6dba,
0x6de5, 0x6e0a, 0x6e2e, 0x6e50, 0x6e73, 0x6ea8, 0x6edd, 0x6efe,
// Entry 21C0 - 21FF
0x6f15, 0x6f2a, 0x6f42, 0x6f59, 0x6f70, 0x6f85, 0x6f9d, 0x6fb4,
0x6fdb, 0x6fff, 0x7026, 0x704a, 0x705a, 0x7070, 0x7087, 0x70a0,
0x70b0, 0x70c8, 0x70e2, 0x70fb, 0x7105, 0x711d, 0x7136, 0x714d,
0x715c, 0x7174, 0x718a, 0x719f, 0x71af, 0x71ba, 0x71c6, 0x71d0,
0x71e6, 0x71fc, 0x720f, 0x7223, 0x7236, 0x7268, 0x728b, 0x72bd,
0x72f0, 0x7304, 0x7327, 0x735a, 0x7366, 0x7372, 0x7393, 0x73bd,
0x73d8, 0x73f1, 0x7417, 0x7441, 0x746b, 0x748f, 0x74a1, 0x74b3,
0x74c2, 0x74d1, 0x74e9, 0x7501, 0x7514, 0x7527, 0x7541, 0x755b,
// Entry 2200 - 223F
0x757b, 0x759b, 0x75b8, 0x75d5, 0x75f8, 0x761b, 0x7637, 0x7653,
0x766f, 0x768b, 0x76ad, 0x76cf, 0x76eb, 0x7707, 0x7729, 0x774b,
0x7766, 0x7781, 0x778e, 0x779b, 0x77c7, 0x77ce, 0x77d5, 0x77e1,
0x77ee, 0x7807, 0x780f, 0x781b, 0x7836, 0x7852, 0x786e, 0x788a,
0x78b0, 0x78dd, 0x78f3, 0x790a, 0x7918, 0x792c, 0x794b, 0x796a,
0x798a, 0x79ab, 0x79cc, 0x79ec, 0x79fd, 0x7a0e, 0x7a28, 0x7a41,
0x7a5a, 0x7a74, 0x7a80, 0x7a9b, 0x7ab7, 0x7ae1, 0x7b0c, 0x7b35,
0x7b58, 0x7b81, 0x7bab, 0x7bb7, 0x7bdc, 0x7c01, 0x7c27, 0x7c4d,
// Entry 2240 - 227F
0x7c72, 0x7c97, 0x7cbd, 0x7ce3, 0x7cf6, 0x7d0a, 0x7d1d, 0x7d30,
0x7d43, 0x7d5c, 0x7d75, 0x7d89, 0x7d9c, 0x7da1, 0x7da9, 0x7db0,
0x7db5, 0x7dbf, 0x7dc9, 0x7dd2, 0x7dde, 0x7de1, 0x7def, 0x7dfe,
0x7e09, 0x7e13, 0x7e22, 0x7e31, 0x7e3b, 0x7e50, 0x7e61, 0x7e68,
0x7e80, 0x7e8c, 0x7e9d, 0x7eae, 0x7eb6, 0x7eda, 0x7ef3, 0x7f0d,
0x7f26, 0x7f3d, 0x7f57, 0x7f70, 0x7f84, 0x7f90, 0x7fa0, 0x7fae,
0x7fb6, 0x7fba, 0x7fc8, 0x7fcf, 0x7fe0, 0x7ff2, 0x8003, 0x800f,
0x8019, 0x802a, 0x8036, 0x803e, 0x8050, 0x8060, 0x8070, 0x8083,
// Entry 2280 - 22BF
0x8093, 0x80a4, 0x80b8, 0x80c9, 0x80d8, 0x80eb, 0x80fd, 0x810f,
0x8122, 0x8134, 0x8145, 0x814c, 0x8157, 0x815c, 0x8165, 0x816c,
0x8172, 0x8178, 0x817f, 0x8184, 0x8189, 0x818f, 0x8195, 0x819b,
0x819e, 0x81a3, 0x81a8, 0x81b0, 0x81bb, 0x81c4, 0x81cc, 0x81d2,
0x81e2, 0x81f3, 0x8203, 0x8215, 0x8227, 0x8237, 0x8247, 0x8258,
0x8268, 0x827a, 0x828c, 0x829c, 0x82ac, 0x82bc, 0x82ce, 0x82dd,
0x82ed, 0x82fd, 0x830f, 0x831e, 0x8329, 0x8335, 0x8340, 0x8353,
0x8369, 0x8378, 0x838a, 0x839a, 0x83ab, 0x83bc, 0x83d6, 0x83fa,
// Entry 22C0 - 22FF
0x841e, 0x8442, 0x8466, 0x848a, 0x84ae, 0x84d2, 0x84f8, 0x8518,
0x852d, 0x854c, 0x8560, 0x8571, 0x857b, 0x8585, 0x858f, 0x8599,
0x85a3, 0x85ad, 0x85c8, 0x85e2, 0x8603, 0x8623, 0x8634, 0x8644,
0x865b, 0x8670, 0x8686, 0x869c, 0x86a6, 0x86b0, 0x86bf, 0x86c5,
0x86d3, 0x86e7, 0x86ed, 0x86f4, 0x86fa, 0x86fe, 0x870d, 0x8718,
0x8724, 0x8737, 0x8753, 0x876e, 0x877a, 0x878b, 0x879e, 0x87af,
0x87cf, 0x87e3, 0x87f8, 0x8821, 0x883f, 0x885f, 0x8872, 0x8885,
0x889e, 0x88ad, 0x88bb, 0x88d7, 0x88dd, 0x88e8, 0x88ee, 0x88f3,
// Entry 2300 - 233F
0x88f9, 0x88fd, 0x8902, 0x8908, 0x8919, 0x8920, 0x892b, 0x8933,
0x8941, 0x894c, 0x8954, 0x895f, 0x8971, 0x8984, 0x8996, 0x89a9,
0x89bd, 0x89cd, 0x89d1, 0x89de, 0x89f4, 0x8a0c, 0x8a24, 0x8a3b,
0x8a49, 0x8a55, 0x8a5e, 0x8a62, 0x8a6d, 0x8a84, 0x8a9a, 0x8aa0,
0x8aa8, 0x8aca, 0x8ae8, 0x8b06, 0x8b1b, 0x8b30, 0x8b3f, 0x8b61,
0x8b72, 0x8b81, 0x8bb1, 0x8bbc, 0x8bd3, 0x8bea, 0x8c08, 0x8c33,
0x8c3c, 0x8c5d, 0x8c7d, 0x8c8f, 0x8ca4, 0x8cb1, 0x8cb7, 0x8cbd,
0x8cca, 0x8cda, 0x8ceb, 0x8d04, 0x8d0c, 0x8d1e, 0x8d26, 0x8d32,
// Entry 2340 - 237F
0x8d37, 0x8d3f, 0x8d52, 0x8d57, 0x8d60, 0x8d70, 0x8d74, 0x8d88,
0x8da2, 0x8dab, 0x8dbe, 0x8dec, 0x8e01, 0x8e15, 0x8e23, 0x8e37,
0x8e45, 0x8e5b, 0x8e72, 0x8e7c, 0x8e84, 0x8e8c, 0x8e97, 0x8ea2,
0x8eae, 0x8eba, 0x8ecc, 0x8ed2, 0x8ee4, 0x8eed, 0x8ef6, 0x8f00,
0x8f10, 0x8f20, 0x8f36, 0x8f3e, 0x8f4c, 0x8f60, 0x8f71, 0x8f82,
0x8f99, 0x8fa4, 0x8fbe, 0x8fd2, 0x8fdf, 0x8fec, 0x9009, 0x9025,
0x9047, 0x9060, 0x9077, 0x908e, 0x9096, 0x90b0, 0x90c2, 0x90d8,
0x90ef, 0x9102, 0x911b, 0x9128, 0x913b, 0x9149, 0x915d, 0x9172,
// Entry 2380 - 23BF
0x918a, 0x91a5, 0x91bb, 0x91df, 0x9209, 0x9222, 0x923a, 0x9252,
0x9276, 0x9294, 0x92b9, 0x92c7, 0x92d5, 0x92fb, 0x9321, 0x9348,
0x9351, 0x936b, 0x9382, 0x9389, 0x9396, 0x93ad, 0x93d5, 0x9403,
0x940d, 0x9422, 0x943d, 0x9463, 0x9489, 0x94aa, 0x94cb, 0x94e7,
0x9503, 0x9522, 0x953d, 0x955a, 0x956c, 0x957f, 0x9591, 0x95c2,
0x95ec, 0x961d, 0x9647, 0x9675, 0x96a3, 0x96c6, 0x96e5, 0x970a,
0x971b, 0x973b, 0x9747, 0x9762, 0x9782, 0x97a3, 0x97cd, 0x97f8,
0x9823, 0x984f, 0x9880, 0x98b2, 0x98dc, 0x9907, 0x9931, 0x995c,
// Entry 23C0 - 23FF
0x997e, 0x99a1, 0x99c3, 0x99e5, 0x9a09, 0x9a2c, 0x9a4f, 0x9a71,
0x9a95, 0x9ab9, 0x9adc, 0x9aff, 0x9b23, 0x9b47, 0x9b6d, 0x9b92,
0x9bb7, 0x9bdb, 0x9c01, 0x9c27, 0x9c4c, 0x9c71, 0x9c9e, 0x9ccb,
0x9cfa, 0x9d28, 0x9d56, 0x9d83, 0x9db2, 0x9de1, 0x9e0f, 0x9e3d,
0x9e5f, 0x9e6e, 0x9e7e, 0x9e91, 0x9ea7, 0x9ebd, 0x9ed3, 0x9ef2,
0x9f15, 0x9f35, 0x9f5b, 0x9f82, 0x9faf, 0x9fc5, 0x9fed, 0xa018,
0xa032, 0xa063, 0xa092, 0xa0ae, 0xa0da, 0xa0fd, 0xa11f, 0xa14a,
0xa176, 0xa1a7, 0xa1d8, 0xa20b, 0xa215, 0xa248, 0xa26c, 0xa28c,
// Entry 2400 - 243F
0xa2ac, 0xa2cc, 0xa2ec, 0xa312, 0xa338, 0xa35e, 0xa37e, 0xa3a5,
0xa3c2, 0xa3e5, 0xa403, 0xa414, 0xa42b, 0xa459, 0xa466, 0xa471,
0xa47e, 0xa499, 0xa4b5, 0xa4c7, 0xa4e7, 0xa501, 0xa524, 0xa540,
0xa54d, 0xa56a, 0xa57d, 0xa58f, 0xa5ad, 0xa5b9, 0xa5d3, 0xa5ee,
0xa608, 0xa617, 0xa627, 0xa636, 0xa643, 0xa652, 0xa671, 0xa684,
0xa691, 0xa6a0, 0xa6ae, 0xa6c7, 0xa6e9, 0xa704, 0xa733, 0xa763,
0xa783, 0xa7a4, 0xa7ca, 0xa7f1, 0xa810, 0xa830, 0xa856, 0xa87d,
0xa8ab, 0xa8da, 0xa901, 0xa929, 0xa940, 0xa959, 0xa97a, 0xa997,
// Entry 2440 - 247F
0xa9b4, 0xa9c8, 0xa9dd, 0xa9f2, 0xaa0d, 0xaa29, 0xaa45, 0xaa62,
0xaa80, 0xaaa4, 0xaac9, 0xaae7, 0xaafc, 0xab12, 0xab28, 0xab3f,
0xab55, 0xab6c, 0xab83, 0xab9b, 0xabb1, 0xabc8, 0xabdf, 0xabf7,
0xac0e, 0xac26, 0xac3e, 0xac57, 0xac6d, 0xac84, 0xac9b, 0xacb3,
0xacca, 0xace2, 0xacfa, 0xad13, 0xad2a, 0xad42, 0xad5a, 0xad73,
0xad8b, 0xada4, 0xadbd, 0xadd7, 0xaded, 0xae04, 0xae1b, 0xae33,
0xae4a, 0xae62, 0xae7a, 0xae93, 0xaeaa, 0xaec2, 0xaeda, 0xaef3,
0xaf0b, 0xaf24, 0xaf3d, 0xaf57, 0xaf6e, 0xaf86, 0xaf9e, 0xafb7,
// Entry 2480 - 24BF
0xafcf, 0xafe8, 0xb001, 0xb01b, 0xb033, 0xb04c, 0xb065, 0xb07f,
0xb098, 0xb0b2, 0xb0cc, 0xb0e7, 0xb0fd, 0xb114, 0xb12b, 0xb143,
0xb15a, 0xb172, 0xb18a, 0xb1a3, 0xb1ba, 0xb1d2, 0xb1ea, 0xb203,
0xb21b, 0xb234, 0xb24d, 0xb267, 0xb27e, 0xb296, 0xb2ae, 0xb2c7,
0xb2df, 0xb2f8, 0xb311, 0xb32b, 0xb343, 0xb35c, 0xb375, 0xb38f,
0xb3a8, 0xb3c2, 0xb3dc, 0xb3f7, 0xb40e, 0xb426, 0xb43e, 0xb457,
0xb46f, 0xb488, 0xb4a1, 0xb4bb, 0xb4d3, 0xb4ec, 0xb505, 0xb51f,
0xb538, 0xb552, 0xb56c, 0xb587, 0xb59f, 0xb5b8, 0xb5d1, 0xb5eb,
// Entry 24C0 - 24FF
0xb604, 0xb61e, 0xb638, 0xb653, 0xb66c, 0xb686, 0xb6a0, 0xb6bb,
0xb6d5, 0xb6f0, 0xb70b, 0xb727, 0xb73d, 0xb754, 0xb76b, 0xb783,
0xb79a, 0xb7b2, 0xb7ca, 0xb7e3, 0xb7fa, 0xb812, 0xb82a, 0xb843,
0xb85b, 0xb874, 0xb88d, 0xb8a7, 0xb8be, 0xb8d6, 0xb8ee, 0xb907,
0xb91f, 0xb938, 0xb951, 0xb96b, 0xb983, 0xb99c, 0xb9b5, 0xb9cf,
0xb9e8, 0xba02, 0xba1c, 0xba37, 0xba4e, 0xba66, 0xba7e, 0xba97,
0xbaaf, 0xbac8, 0xbae1, 0xbafb, 0xbb13, 0xbb2c, 0xbb45, 0xbb5f,
0xbb78, 0xbb92, 0xbbac, 0xbbc7, 0xbbdf, 0xbbf8, 0xbc11, 0xbc2b,
// Entry 2500 - 253F
0xbc44, 0xbc5e, 0xbc78, 0xbc93, 0xbcac, 0xbcc6, 0xbce0, 0xbcfb,
0xbd15, 0xbd30, 0xbd4b, 0xbd67, 0xbd7e, 0xbd96, 0xbdae, 0xbdc7,
0xbddf, 0xbdf8, 0xbe11, 0xbe2b, 0xbe43, 0xbe5c, 0xbe75, 0xbe8f,
0xbea8, 0xbec2, 0xbedc, 0xbef7, 0xbf0f, 0xbf28, 0xbf41, 0xbf5b,
0xbf74, 0xbf8e, 0xbfa8, 0xbfc3, 0xbfdc, 0xbff6, 0xc010, 0xc02b,
0xc045, 0xc060, 0xc07b, 0xc097, 0xc0af, 0xc0c8, 0xc0e1, 0xc0fb,
0xc114, 0xc12e, 0xc148, 0xc163, 0xc17c, 0xc196, 0xc1b0, 0xc1cb,
0xc1e5, 0xc200, 0xc21b, 0xc237, 0xc250, 0xc26a, 0xc284, 0xc29f,
// Entry 2540 - 257F
0xc2b9, 0xc2d4, 0xc2ef, 0xc30b, 0xc325, 0xc340, 0xc35b, 0xc377,
0xc392, 0xc3ae, 0xc3ca, 0xc3e7, 0xc417, 0xc44e, 0xc479, 0xc4a5,
0xc4d1, 0xc4f5, 0xc514, 0xc534, 0xc55a, 0xc57e, 0xc592, 0xc5a8,
0xc5c3, 0xc5df, 0xc5fa, 0xc616, 0xc63d, 0xc65e, 0xc672, 0xc688,
0xc6b7, 0xc6ed, 0xc712, 0xc74c, 0xc78d, 0xc7a1, 0xc7b6, 0xc7d1,
0xc7ed, 0xc80d, 0xc82e, 0xc857, 0xc881, 0xc8a0, 0xc8bf, 0xc8d9,
0xc8f3, 0xc90d, 0xc927, 0xc94c, 0xc971, 0xc996, 0xc9bb, 0xc9e4,
0xca0d, 0xca37, 0xca61, 0xca8b, 0xcab4, 0xcade, 0xcb08, 0xcb2a,
// Entry 2580 - 25BF
0xcb58, 0xcb88, 0xcbb7, 0xcbe7, 0xcc05, 0xcc26, 0xcc41, 0xcc5f,
0xcc81, 0xcca6, 0xccce, 0xccf9, 0xcd1a, 0xcd37, 0xcd63, 0xcd8f,
0xcdbb, 0xcddb, 0xcdfa, 0xce14, 0xce39, 0xce63, 0xce87, 0xceab,
0xcecf, 0xcef3, 0xcf15, 0xcf3a, 0xcf60, 0xcf83, 0xcfa8, 0xcfce,
0xcff4, 0xd01c, 0xd043, 0xd06b, 0xd090, 0xd0b7, 0xd0de, 0xd106,
0xd12e, 0xd158, 0xd181, 0xd1ab, 0xd1d2, 0xd1fb, 0xd240, 0xd285,
0xd2cc, 0xd315, 0xd359, 0xd3a1, 0xd3e5, 0xd42d, 0xd45b, 0xd48b,
0xd4ba, 0xd4eb, 0xd532, 0xd579, 0xd59d, 0xd5bf, 0xd5e4, 0xd608,
// Entry 25C0 - 25FF
0xd62d, 0xd653, 0xd672, 0xd693, 0xd6b6, 0xd6d3, 0xd6f1, 0xd70f,
0xd71d, 0xd72c, 0xd738, 0xd746, 0xd763, 0xd772, 0xd787, 0xd79f,
0xd7b8, 0xd7ce, 0xd7e5, 0xd802, 0xd820, 0xd83f, 0xd85f, 0xd880,
0xd8a2, 0xd8cd, 0xd8fc, 0xd92a, 0xd956, 0xd971, 0xd98d, 0xd9a7,
0xd9c5, 0xd9e9, 0xda0b, 0xda2c, 0xda4e, 0xda5a, 0xda6e, 0xda89,
0xdaa8, 0xdac5, 0xdad8, 0xdae3, 0xdaff, 0xdb19, 0xdb25, 0xdb33,
0xdb46, 0xdb62, 0xdb7a, 0xdb94, 0xdbd6, 0xdc17, 0xdc5b, 0xdc9e,
0xdce0, 0xdd21, 0xdd65, 0xdda8, 0xddba, 0xddd0, 0xddf1, 0xde11,
// Entry 2600 - 263F
0xde30, 0xde4a, 0xde5e, 0xde6e, 0xde85, 0xde9a, 0xdedf, 0xdef9,
0xdf24, 0xdf3b, 0xdf4f, 0xdf5d, 0xdf6e, 0xdf82, 0xdfa7, 0xdfd6,
0xdff3, 0xe011, 0xe021, 0xe035, 0xe043, 0xe055, 0xe06c, 0xe082,
0xe08f, 0xe0ad, 0xe0cf, 0xe0f0, 0xe112, 0xe12d, 0xe149, 0xe155,
0xe16f, 0xe18a, 0xe199, 0xe1a8, 0xe1b9, 0xe1cb, 0xe1e3, 0xe1fc,
0xe20f, 0xe220, 0xe242, 0xe257, 0xe274, 0xe280, 0xe28f, 0xe2af,
0xe2e0, 0xe301, 0xe30d, 0xe31a, 0xe345, 0xe371, 0xe38e, 0xe39b,
0xe3b7, 0xe3d3, 0xe3ec, 0xe405, 0xe41f, 0xe439, 0xe452, 0xe46b,
// Entry 2640 - 267F
0xe477, 0xe48f, 0xe4a3, 0xe4c9, 0xe4d4, 0xe4e7, 0xe4f2, 0xe4fd,
0xe51f, 0xe542, 0xe546, 0xe54a, 0xe564, 0xe57f, 0xe59b, 0xe5b8,
0xe5d6, 0xe5f8, 0xe613, 0xe62b, 0xe642, 0xe656, 0xe664, 0xe67b,
0xe696, 0xe6aa, 0xe6c5, 0xe6e0, 0xe6f4, 0xe70d, 0xe73f, 0xe772,
0xe799, 0xe7b9, 0xe7d5, 0xe7fc, 0xe814, 0xe82e, 0xe841, 0xe856,
0xe86c, 0xe870, 0xe88c, 0xe8a9, 0xe8c1, 0xe8dd, 0xe8fe, 0xe924,
0xe93e, 0xe956, 0xe970, 0xe98c, 0xe9a9, 0xe9c4, 0xe9dd, 0xe9f9,
0xea14, 0xea31, 0xea4f, 0xea66, 0xea88, 0xeaa9, 0xeace, 0xeadb,
// Entry 2680 - 26BF
0xeb02, 0xeb2a, 0xeb5c, 0xeb80, 0xeb95, 0xebaa, 0xebc0, 0xebdf,
0xebef, 0xec09, 0xec2a, 0xec43, 0xec58, 0xec6d, 0xec7f, 0xec98,
0xecb5, 0xecca, 0xece2, 0xecfa, 0xed1c, 0xed3e, 0xed60, 0xed90,
0xeda8, 0xedc7, 0xede1, 0xedf4, 0xee1e, 0xee38, 0xee51, 0xee63,
0xee74, 0xee90, 0xeeab, 0xeebb, 0xeecc, 0xeeee, 0xef0a, 0xef25,
0xef45, 0xef64, 0xef83, 0xef9c, 0xefbc, 0xefd3, 0xeff1, 0xf010,
0xf031, 0xf051, 0xf06b, 0xf083, 0xf0b4, 0xf0e5, 0xf102, 0xf121,
0xf136, 0xf14e, 0xf162, 0xf188, 0xf1a7, 0xf1c2, 0xf1dd, 0xf1fd,
// Entry 26C0 - 26FF
0xf20f, 0xf22b, 0xf249, 0xf27b, 0xf29a, 0xf2b6, 0xf2d5, 0xf2f7,
0xf31c, 0xf339, 0xf359, 0xf386, 0xf3b6, 0xf3e2, 0xf411, 0xf443,
0xf477, 0xf48f, 0xf4aa, 0xf4d0, 0xf4f9, 0xf516, 0xf536, 0xf56a,
0xf59e, 0xf5be, 0xf5e1, 0xf60b, 0xf635, 0xf669, 0xf69d, 0xf6e1,
0xf725, 0xf742, 0xf762, 0xf78f, 0xf7bf, 0xf7e0, 0xf804, 0xf82d,
0xf859, 0xf86d, 0xf884, 0xf8ad, 0xf8d9, 0xf8f0, 0xf90a, 0xf92f,
0xf951, 0xf96e, 0xf987, 0xf9a3, 0xf9d0, 0xfa00, 0xfa0c, 0xfa17,
0xfa2f, 0xfa46, 0xfa62, 0xfa88, 0xfaae, 0xfad5, 0xfafc, 0xfb16,
// Entry 2700 - 273F
0xfb30, 0xfb4b, 0xfb66, 0xfb84, 0xfba2, 0xfbc4, 0xfbe6, 0xfbf5,
0xfc04, 0xfc13, 0xfc24, 0xfc3f, 0xfc5c, 0xfc81, 0xfca8, 0xfccc,
0xfcf2, 0xfd0d, 0xfd2a, 0xfd48, 0xfd68, 0xfd87, 0xfda8, 0xfdc4,
0xfde2, 0xfdff, 0xfe1d, 0xfe2a, 0xfe39, 0xfe52, 0xfe6d, 0xfe82,
0xfe97, 0xfeaa, 0xfec1, 0xfed7, 0xff05, 0xff21, 0xff37, 0xff4f,
0xff56, 0xff60, 0xff6f, 0xff7e, 0xff8b, 0xff9f, 0xffc2, 0xffe4,
0x0006, 0x002f, 0x005c, 0x0078, 0x0093, 0x00b6, 0x00c6, 0x00d4,
0x00ea, 0x0109, 0x0135, 0x0154, 0x0173, 0x018e, 0x01ad, 0x01c9,
// Entry 2740 - 277F
0x01ec, 0x0216, 0x022b, 0x0242, 0x025c, 0x0285, 0x02b1, 0x02cf,
0x02f1, 0x0308, 0x031a, 0x0332, 0x0348, 0x035e, 0x0374, 0x038a,
0x03a0, 0x03b5, 0x03c8, 0x03dd, 0x03f3, 0x0409, 0x041f, 0x0435,
0x044b, 0x045e, 0x0481, 0x04a2, 0x04c4, 0x04e4, 0x04fe, 0x051b,
0x0546, 0x0570, 0x058c, 0x05a9, 0x05c4, 0x05e2, 0x05ef, 0x0601,
0x0613, 0x062a, 0x0641, 0x064f, 0x065d, 0x066a, 0x0677, 0x068f,
0x06a1, 0x06b5, 0x06c9, 0x06dd, 0x06f1, 0x0704, 0x0717, 0x072a,
0x0742, 0x075a, 0x0770, 0x0786, 0x07a2, 0x07b8, 0x07d4, 0x07f1,
// Entry 2780 - 27BF
0x0820, 0x0856, 0x0879, 0x089f, 0x08bf, 0x08ed, 0x0922, 0x0946,
0x097f, 0x09bf, 0x09d8, 0x09f9, 0x0a1a, 0x0a46, 0x0a73, 0x0a98,
0x0ab9, 0x0ad2, 0x0aec, 0x0b19, 0x0b47, 0x0b6b, 0x0b90, 0x0bbc,
0x0be9, 0x0c0f, 0x0c28, 0x0c45, 0x0c56, 0x0c66, 0x0c76, 0x0c93,
0x0cb0, 0x0cc2, 0x0cdd, 0x0cfc, 0x0d08, 0x0d1d, 0x0d41, 0x0d69,
0x0d91, 0x0dbd, 0x0dea, 0x0e1d, 0x0e3c, 0x0e59, 0x0e79, 0x0e98,
0x0eb8, 0x0ed5, 0x0ef5, 0x0f15, 0x0f35, 0x0f55, 0x0f7b, 0x0f9f,
0x0fc6, 0x0fec, 0x1017, 0x1046, 0x106c, 0x1090, 0x10b7, 0x10dd,
// Entry 27C0 - 27FF
0x1104, 0x112b, 0x1152, 0x1179, 0x11b6, 0x11f1, 0x122f, 0x126c,
0x127e, 0x128e, 0x12d3, 0x131d, 0x1362, 0x13ac, 0x13d3, 0x13f8,
0x1420, 0x1447, 0x146a, 0x148b, 0x14af, 0x14d2, 0x1504, 0x1537,
0x1568, 0x1598, 0x15a3, 0x15af, 0x15bb, 0x15c8, 0x15f1, 0x1607,
0x1626, 0x1643, 0x1676, 0x16a9, 0x16dd, 0x1711, 0x1736, 0x1759,
0x177f, 0x17a4, 0x17db, 0x1813, 0x1848, 0x187e, 0x18b3, 0x18e9,
0x1920, 0x1958, 0x1982, 0x19ad, 0x19d5, 0x19fe, 0x1a26, 0x1a4f,
0x1a79, 0x1aa4, 0x1aba, 0x1ad1, 0x1ae5, 0x1afa, 0x1b0e, 0x1b23,
// Entry 2800 - 283F
0x1b39, 0x1b50, 0x1b80, 0x1b9f, 0x1bb8, 0x1bdb, 0x1bf4, 0x1c0b,
0x1c14, 0x1c22, 0x1c36, 0x1c4b, 0x1c60, 0x1c78, 0x1c85, 0x1cae,
0x1cd9, 0x1d04, 0x1d30, 0x1d40, 0x1d55, 0x1d6d, 0x1d8a, 0x1daf,
0x1dc6, 0x1de5, 0x1dfe, 0x1e0e, 0x1e18, 0x1e26, 0x1e36, 0x1e45,
0x1e54, 0x1e5e, 0x1e68, 0x1e6f, 0x1e75, 0x1e7b, 0x1e81, 0x1e92,
0x1ea8, 0x1ebc, 0x1ec2, 0x1ec7, 0x1ecb, 0x1ed1, 0x1ed8, 0x1edf,
0x1ee7, 0x1eef, 0x1f03, 0x1f18, 0x1f31, 0x1f4b, 0x1f7e, 0x1faf,
0x1fe3, 0x2016, 0x2023, 0x2030, 0x2035, 0x205a, 0x207c, 0x20a0,
// Entry 2840 - 287F
0x20c4, 0x20e8, 0x210d, 0x212c, 0x2139, 0x2149, 0x2157, 0x2164,
0x2178, 0x2192, 0x21af, 0x21cd, 0x21eb, 0x220c, 0x222b, 0x224a,
0x226b, 0x228a, 0x22aa, 0x22c8, 0x22ee, 0x2309, 0x2329, 0x2347,
0x2368, 0x2389, 0x23a8, 0x23c5, 0x23e5, 0x2404, 0x2423, 0x2443,
0x2460, 0x247f, 0x249d, 0x24ba, 0x24d6, 0x24f4, 0x2511, 0x2531,
0x254e, 0x256c, 0x258a, 0x25a8, 0x25cc, 0x25e8, 0x260b, 0x2638,
0x2654, 0x267f, 0x26a0, 0x26c9, 0x26e7, 0x2708, 0x2729, 0x274f,
0x2779, 0x27a1, 0x27bc, 0x27d8, 0x27f4, 0x2813, 0x2830, 0x284d,
// Entry 2880 - 28BF
0x286c, 0x2889, 0x28a7, 0x28c3, 0x28e7, 0x2900, 0x291e, 0x293a,
0x2959, 0x2978, 0x2995, 0x29b0, 0x29ce, 0x29eb, 0x2a08, 0x2a26,
0x2a41, 0x2a5e, 0x2a7a, 0x2a95, 0x2aaf, 0x2acb, 0x2ae6, 0x2b04,
0x2b1f, 0x2b3b, 0x2b57, 0x2b73, 0x2b95, 0x2baf, 0x2bd0, 0x2bfb,
0x2c15, 0x2c3e, 0x2c5d, 0x2c84, 0x2ca0, 0x2cbf, 0x2cde, 0x2d02,
0x2d2a, 0x2d50, 0x2d76, 0x2d9a, 0x2dc2, 0x2de4, 0x2e04, 0x2e24,
0x2e4d, 0x2e72, 0x2e95, 0x2eba, 0x2edd, 0x2f02, 0x2f25, 0x2f3f,
0x2f5f, 0x2f7c, 0x2f9d, 0x2fc1, 0x2fe1, 0x2fff, 0x301d, 0x3038,
// Entry 28C0 - 28FF
0x3051, 0x3070, 0x308f, 0x30b4, 0x30dd, 0x3100, 0x311e, 0x3137,
0x315d, 0x3183, 0x319d, 0x31b5, 0x31cf, 0x31e7, 0x3202, 0x321b,
0x3236, 0x324f, 0x3268, 0x327f, 0x3298, 0x32af, 0x32c9, 0x32e1,
0x32fb, 0x3313, 0x332f, 0x3349, 0x3364, 0x337d, 0x3397, 0x33af,
0x33ca, 0x33e3, 0x33fb, 0x3411, 0x3429, 0x343f, 0x3458, 0x346f,
0x3486, 0x349b, 0x34b3, 0x34c9, 0x34e1, 0x34f7, 0x3511, 0x3529,
0x3542, 0x3559, 0x3571, 0x3587, 0x359f, 0x35b5, 0x35ce, 0x35e5,
0x35fe, 0x3615, 0x362e, 0x3645, 0x3669, 0x368b, 0x36af, 0x36d1,
// Entry 2900 - 293F
0x36f8, 0x371d, 0x3741, 0x3763, 0x3785, 0x37a5, 0x37cb, 0x37ef,
0x3813, 0x3835, 0x3850, 0x3869, 0x388b, 0x38ab, 0x38d0, 0x38f3,
0x3917, 0x3939, 0x395c, 0x397d, 0x39a1, 0x39c3, 0x39e8, 0x3a0b,
0x3a2e, 0x3a4f, 0x3a70, 0x3a8f, 0x3ab3, 0x3ad5, 0x3af9, 0x3b1b,
0x3b42, 0x3b67, 0x3b8b, 0x3bad, 0x3bd3, 0x3bf7, 0x3c1d, 0x3c41,
0x3c65, 0x3c87, 0x3cab, 0x3ccd, 0x3cf1, 0x3d13, 0x3d24, 0x3d37,
0x3d4a, 0x3d5f, 0x3d73, 0x3d87, 0x3d9f, 0x3dc7, 0x3ded, 0x3e17,
0x3e3f, 0x3e58, 0x3e77, 0x3e96, 0x3eb9, 0x3eda, 0x3ef5, 0x3f1b,
// Entry 2940 - 297F
0x3f43, 0x3f62, 0x3f7a, 0x3f8a, 0x3fa6, 0x3fbe, 0x3fd7, 0x3ff0,
0x4009, 0x4021, 0x403a, 0x4053, 0x406c, 0x4084, 0x409d, 0x40b6,
0x40cf, 0x40e8, 0x4100, 0x4119, 0x4133, 0x414c, 0x4165, 0x417e,
0x4196, 0x41b0, 0x41ca, 0x41e4, 0x41fd, 0x4217, 0x4231, 0x424a,
0x4263, 0x427c, 0x4296, 0x42af, 0x42c9, 0x42e2, 0x42fa, 0x4313,
0x432b, 0x4344, 0x435d, 0x4375, 0x438e, 0x43a0, 0x43b3, 0x43c7,
0x43da, 0x43ef, 0x4411, 0x4424, 0x4437, 0x444b, 0x445f, 0x4474,
0x4487, 0x449a, 0x44ad, 0x44c7, 0x44dc, 0x44ef, 0x4511, 0x452b,
// Entry 2980 - 29BF
0x453f, 0x4552, 0x4566, 0x4581, 0x4594, 0x45ae, 0x45c0, 0x45d4,
0x45f0, 0x460b, 0x461e, 0x4631, 0x4644, 0x465f, 0x467a, 0x468d,
0x469f, 0x46b2, 0x46c6, 0x46da, 0x46f5, 0x470e, 0x4721, 0x4735,
0x4749, 0x475c, 0x4770, 0x4784, 0x4798, 0x47ab, 0x47be, 0x47d1,
0x47e4, 0x4802, 0x4816, 0x4828, 0x483a, 0x4865, 0x487c, 0x4895,
0x48aa, 0x48bf, 0x48d4, 0x48e9, 0x48ff, 0x4914, 0x4929, 0x493e,
0x4953, 0x4969, 0x4985, 0x499a, 0x49af, 0x49c5, 0x49da, 0x49f0,
0x4a06, 0x4a1c, 0x4a31, 0x4a47, 0x4a5d, 0x4a74, 0x4a8a, 0x4a9f,
// Entry 29C0 - 29FF
0x4ab4, 0x4ac9, 0x4adf, 0x4af5, 0x4b0a, 0x4b1f, 0x4b34, 0x4b49,
0x4b5e, 0x4b74, 0x4b8a, 0x4b9f, 0x4bb4, 0x4bc9, 0x4bde, 0x4bf3,
0x4c09, 0x4c1f, 0x4c34, 0x4c49, 0x4c5f, 0x4c75, 0x4c8b, 0x4ca2,
0x4cb9, 0x4ccf, 0x4ce5, 0x4cfa, 0x4d0f, 0x4d24, 0x4d3a, 0x4d50,
0x4d65, 0x4d7a, 0x4d8f, 0x4da4, 0x4db9, 0x4dcf, 0x4de5, 0x4dfa,
0x4e0f, 0x4e24, 0x4e39, 0x4e4e, 0x4e64, 0x4e7a, 0x4e8f, 0x4ea4,
0x4eb9, 0x4ece, 0x4ee3, 0x4ef9, 0x4f0f, 0x4f24, 0x4f39, 0x4f55,
0x4f71, 0x4f8e, 0x4faa, 0x4fc7, 0x4fe3, 0x4fff, 0x501b, 0x5037,
// Entry 2A00 - 2A3F
0x5053, 0x506e, 0x508a, 0x50a6, 0x50c2, 0x50de, 0x50fa, 0x5117,
0x5134, 0x5151, 0x5170, 0x518e, 0x51ad, 0x51c8, 0x51e4, 0x5203,
0x5229, 0x5246, 0x5262, 0x5286, 0x52aa, 0x52cb, 0x52f5, 0x5314,
0x533a, 0x5353, 0x536d, 0x538d, 0x53ae, 0x53c9, 0x53eb, 0x5406,
0x5420, 0x543b, 0x5448, 0x5464, 0x5481, 0x5492, 0x549d, 0x54af,
0x54ca, 0x54d6, 0x54e3, 0x54f3, 0x5501, 0x551c, 0x5531, 0x5545,
0x5550, 0x5565, 0x557a, 0x5595, 0x55b1, 0x55c5, 0x55d9, 0x55f5,
0x5612, 0x5627, 0x563d, 0x5655, 0x566e, 0x5685, 0x569d, 0x56b4,
// Entry 2A40 - 2A7F
0x56cc, 0x56ed, 0x570e, 0x572a, 0x5737, 0x574d, 0x575b, 0x5765,
0x577e, 0x578a, 0x5794, 0x57a0, 0x57b0, 0x57c6, 0x57dd, 0x57ea,
0x57ff, 0x580a, 0x5817, 0x582d, 0x583e, 0x5852, 0x585b, 0x5868,
0x5876, 0x589a, 0x58af, 0x58c5, 0x58d8, 0x58fd, 0x5907, 0x591a,
0x592e, 0x593c, 0x5949, 0x5957, 0x5967, 0x597c, 0x5991, 0x59b0,
0x59ce, 0x59e6, 0x59ff, 0x5a15, 0x5a34, 0x5a54, 0x5a7a, 0x5aa1,
0x5aba, 0x5ad4, 0x5af0, 0x5b0d, 0x5b1b, 0x5b2d, 0x5b3e, 0x5b54,
0x5b6a, 0x5b82, 0x5b94, 0x5ba3, 0x5bb4, 0x5bc9, 0x5bde, 0x5bf4,
// Entry 2A80 - 2ABF
0x5c04, 0x5c19, 0x5c2e, 0x5c42, 0x5c56, 0x5c6c, 0x5c81, 0x5c92,
0x5ca4, 0x5cb9, 0x5cce, 0x5ce3, 0x5cf8, 0x5d08, 0x5d17, 0x5d28,
0x5d37, 0x5d47, 0x5d58, 0x5d6a, 0x5d7e, 0x5d93, 0x5da8, 0x5db8,
0x5dcb, 0x5dde, 0x5e04, 0x5e13, 0x5e22, 0x5e32, 0x5e4b, 0x5e5a,
0x5e70, 0x5e86, 0x5e98, 0x5ea8, 0x5ec5, 0x5ed8, 0x5eeb, 0x5f00,
0x5f14, 0x5f24, 0x5f35, 0x5f44, 0x5f53, 0x5f62, 0x5f77, 0x5f8c,
0x5f9c, 0x5fae, 0x5fc3, 0x5fd8, 0x5fef, 0x6000, 0x6013, 0x6027,
0x603b, 0x6057, 0x6072, 0x6082, 0x60a1, 0x60bf, 0x60cf, 0x60ec,
// Entry 2AC0 - 2AFF
0x6107, 0x611b, 0x612f, 0x613f, 0x615c, 0x6170, 0x6184, 0x61a1,
0x61be, 0x61d3, 0x61e8, 0x61f8, 0x6208, 0x622f, 0x624c, 0x6269,
0x6285, 0x6298, 0x62ab, 0x62c0, 0x62dc, 0x62ec, 0x630a, 0x631a,
0x632b, 0x6348, 0x6365, 0x6382, 0x639e, 0x63bb, 0x63d8, 0x63f5,
0x6412, 0x6430, 0x644e, 0x646d, 0x648c, 0x649e, 0x64bd, 0x64dc,
0x64ee, 0x6501, 0x6513, 0x6527, 0x653c, 0x654f, 0x6561, 0x6573,
0x6585, 0x6598, 0x65ac, 0x65c0, 0x65d7, 0x65eb, 0x65fd, 0x6611,
0x6628, 0x663c, 0x6650, 0x6663, 0x6677, 0x6694, 0x66b3, 0x66c5,
// Entry 2B00 - 2B3F
0x66de, 0x66f1, 0x6705, 0x671b, 0x672f, 0x6743, 0x675b, 0x676f,
0x6785, 0x6796, 0x67ae, 0x67c4, 0x67d6, 0x67ea, 0x67fe, 0x6811,
0x6824, 0x6838, 0x684b, 0x6860, 0x6875, 0x688c, 0x68a0, 0x68b3,
0x68c9, 0x68de, 0x68f0, 0x690b, 0x6926, 0x6940, 0x6958, 0x696c,
0x697e, 0x6992, 0x69a8, 0x69bb, 0x69cf, 0x69e5, 0x69f8, 0x6a0b,
0x6a20, 0x6a32, 0x6a47, 0x6a5c, 0x6a6e, 0x6a83, 0x6a95, 0x6aa7,
0x6ab9, 0x6acc, 0x6adf, 0x6af2, 0x6b05, 0x6b19, 0x6b2e, 0x6b43,
0x6b59, 0x6b6b, 0x6b7e, 0x6b92, 0x6ba6, 0x6bb9, 0x6bcc, 0x6be1,
// Entry 2B40 - 2B7F
0x6bf8, 0x6c16, 0x6c2a, 0x6c3d, 0x6c4f, 0x6c61, 0x6c78, 0x6c8b,
0x6c9f, 0x6cb2, 0x6cc6, 0x6cd9, 0x6ceb, 0x6cff, 0x6d1b, 0x6d32,
0x6d4c, 0x6d60, 0x6d73, 0x6d86, 0x6d98, 0x6dac, 0x6dc0, 0x6dd4,
0x6de9, 0x6dfd, 0x6e11, 0x6e24, 0x6e38, 0x6e4d, 0x6e60, 0x6e73,
0x6e85, 0x6e97, 0x6eab, 0x6ec1, 0x6ed3, 0x6ee5, 0x6ef8, 0x6f0a,
0x6f1e, 0x6f31, 0x6f48, 0x6f5b, 0x6f70, 0x6f85, 0x6f9a, 0x6faf,
0x6fc2, 0x6fd9, 0x6fed, 0x7001, 0x7015, 0x702a, 0x703e, 0x705b,
0x7071, 0x7084, 0x7096, 0x70a9, 0x70be, 0x70d3, 0x70e6, 0x70f8,
// Entry 2B80 - 2BBF
0x710d, 0x7121, 0x7133, 0x7145, 0x7158, 0x716b, 0x717e, 0x7193,
0x71a9, 0x71bc, 0x71cf, 0x71e2, 0x71fc, 0x7212, 0x7225, 0x7238,
0x724b, 0x725f, 0x7273, 0x7293, 0x72a6, 0x72b9, 0x72cd, 0x72e0,
0x72f6, 0x7313, 0x7326, 0x733a, 0x734d, 0x7360, 0x7372, 0x7384,
0x7397, 0x73ae, 0x73c2, 0x73d5, 0x73e8, 0x73fb, 0x740f, 0x742e,
0x7445, 0x7459, 0x746c, 0x747f, 0x7492, 0x74a5, 0x74b9, 0x74cc,
0x74e1, 0x74f6, 0x750a, 0x7523, 0x7536, 0x754b, 0x755e, 0x7570,
0x7583, 0x7596, 0x75aa, 0x75bf, 0x75d4, 0x75e8, 0x7617, 0x7647,
// Entry 2BC0 - 2BFF
0x7681, 0x76bc, 0x76eb, 0x7720, 0x7755, 0x7789, 0x77c3, 0x77fe,
0x7838, 0x7862, 0x7897, 0x78d2, 0x7909, 0x7933, 0x7944, 0x7955,
0x796a, 0x7974, 0x7997, 0x79b1, 0x79c9, 0x79e0, 0x79f2, 0x7a05,
0x7a1e, 0x7a38, 0x7a4b, 0x7a5f, 0x7a78, 0x7a92, 0x7aaf, 0x7acd,
0x7ad8, 0x7ae1, 0x7afc, 0x7b18, 0x7b35, 0x7b53, 0x7b74, 0x7b96,
0x7baf, 0x7bc9, 0x7bd2, 0x7bf6, 0x7c11, 0x7c30, 0x7c40, 0x7c54,
0x7c68, 0x7c7e, 0x7c93, 0x7ca8, 0x7cbc, 0x7cd2, 0x7ce8, 0x7cfd,
0x7d18, 0x7d34, 0x7d53, 0x7d71, 0x7d8c, 0x7da7, 0x7db0, 0x7dc9,
// Entry 2C00 - 2C3F
0x7df4, 0x7e18, 0x7e4e, 0x7e72, 0x7e85, 0x7eb5, 0x7ec9, 0x7ee0,
0x7ef7, 0x7f1a, 0x7f23, 0x7f38, 0x7f57, 0x7f72, 0x7f89, 0x7f9a,
0x7fb1, 0x7fc2, 0x7fd9, 0x7fea, 0x8001, 0x8012, 0x8029, 0x803a,
0x804c, 0x805e, 0x8070, 0x8082, 0x8094, 0x80a6, 0x80b8, 0x80ca,
0x80dc, 0x80ee, 0x8100, 0x8112, 0x8124, 0x8136, 0x8148, 0x815a,
0x816c, 0x817e, 0x8190, 0x81a2, 0x81b4, 0x81c6, 0x81d8, 0x81ea,
0x8202, 0x8214, 0x8226, 0x8238, 0x824a, 0x825c, 0x826e, 0x8280,
0x8292, 0x82a4, 0x82b6, 0x82c8, 0x82da, 0x82ec, 0x82fe, 0x8310,
// Entry 2C40 - 2C7F
0x8322, 0x8334, 0x8346, 0x8358, 0x836a, 0x837c, 0x838e, 0x83a0,
0x83b2, 0x83c4, 0x83d6, 0x83e8, 0x83fa, 0x840c, 0x841e, 0x8430,
0x8448, 0x845a, 0x8472, 0x8484, 0x849c, 0x84ae, 0x84c0, 0x84d2,
0x84e4, 0x84f6, 0x8508, 0x8520, 0x8532, 0x8544, 0x8556, 0x8568,
0x8579, 0x858b, 0x85a3, 0x85bb, 0x85e8, 0x861a, 0x863d, 0x8665,
0x867c, 0x869a, 0x86af, 0x86ce, 0x86e5, 0x86f6, 0x870d, 0x871e,
0x8735, 0x8746, 0x875d, 0x876e, 0x8785, 0x8796, 0x87a8, 0x87ba,
0x87cc, 0x87de, 0x87f0, 0x8802, 0x8814, 0x8826, 0x8838, 0x884a,
// Entry 2C80 - 2CBF
0x885c, 0x886e, 0x8880, 0x8892, 0x88a4, 0x88b6, 0x88c8, 0x88da,
0x88ec, 0x88fe, 0x8910, 0x8922, 0x8934, 0x8946, 0x895e, 0x8970,
0x8982, 0x8994, 0x89a6, 0x89b8, 0x89ca, 0x89dc, 0x89ee, 0x8a00,
0x8a12, 0x8a24, 0x8a36, 0x8a48, 0x8a5a, 0x8a6c, 0x8a7e, 0x8a90,
0x8aa2, 0x8ab4, 0x8ac6, 0x8ad8, 0x8aea, 0x8afc, 0x8b0e, 0x8b20,
0x8b32, 0x8b44, 0x8b56, 0x8b68, 0x8b7a, 0x8b8c, 0x8ba4, 0x8bb6,
0x8bce, 0x8be0, 0x8bf8, 0x8c0a, 0x8c1c, 0x8c2e, 0x8c40, 0x8c52,
0x8c64, 0x8c7c, 0x8c8e, 0x8ca0, 0x8cb2, 0x8cc4, 0x8cd5, 0x8ce7,
// Entry 2CC0 - 2CFF
0x8cff, 0x8d17, 0x8d29, 0x8d3b, 0x8d4d, 0x8d5f, 0x8d72, 0x8d98,
0x8daf, 0x8dcd, 0x8de2, 0x8df3, 0x8e04, 0x8e15, 0x8e26, 0x8e37,
0x8e48, 0x8e59, 0x8e6a, 0x8e7b, 0x8e8c, 0x8e9d, 0x8eae, 0x8ebf,
0x8ed0, 0x8ee2, 0x8ef4, 0x8f06, 0x8f17, 0x8f28, 0x8f39, 0x8f4a,
0x8f5b, 0x8f6c, 0x8f7d, 0x8f8f, 0x8fa1, 0x8fb3, 0x8fc5, 0x8fd7,
0x8fe9, 0x8ffb, 0x900e, 0x9021, 0x9033, 0x9044, 0x9055, 0x9067,
0x9078, 0x908a, 0x909c, 0x90ae, 0x90ce, 0x90e0, 0x90f4, 0x910d,
0x9126, 0x9139, 0x9152, 0x916b, 0x917f, 0x9198, 0x91ab, 0x91c5,
// Entry 2D00 - 2D3F
0x91de, 0x91f7, 0x920f, 0x922a, 0x9245, 0x925e, 0x9271, 0x9284,
0x929c, 0x92b4, 0x92c6, 0x92dd, 0x92f0, 0x9303, 0x931b, 0x9330,
0x9345, 0x935a, 0x936f, 0x9382, 0x9391, 0x93a1, 0x93b1, 0x93c2,
0x93d2, 0x93e1, 0x93f2, 0x9402, 0x9411, 0x9421, 0x9432, 0x9442,
0x9452, 0x9461, 0x9472, 0x9482, 0x9492, 0x94a2, 0x94b2, 0x94c2,
0x94d1, 0x94de, 0x94f6, 0x9510, 0x9528, 0x9543, 0x9562, 0x957c,
0x959a, 0x95b5, 0x95d4, 0x95ed, 0x9605, 0x9620, 0x963b, 0x9655,
0x966f, 0x968e, 0x96ad, 0x96c6, 0x96e1, 0x96fc, 0x971c, 0x9735,
// Entry 2D40 - 2D7F
0x974d, 0x9766, 0x977e, 0x9796, 0x97ab, 0x97c3, 0x97d9, 0x97f4,
0x9812, 0x982f, 0x9847, 0x9860, 0x9873, 0x9887, 0x9899, 0x98ad,
0x98c0, 0x98d2, 0x98e5, 0x98f9, 0x991c, 0x993f, 0x995e, 0x997d,
0x999e, 0x99be, 0x99dd, 0x99ff, 0x9a21, 0x9a42, 0x9a64, 0x9a85,
0x9aa7, 0x9ac9, 0x9aea, 0x9b09, 0x9b1b, 0x9b2d, 0x9b3f, 0x9b51,
0x9b63, 0x9b76, 0x9b88, 0x9b9b, 0x9bad, 0x9bc0, 0x9bd3, 0x9be6,
0x9bf8, 0x9c0b, 0x9c1f, 0x9c33, 0x9c45, 0x9c57, 0x9c6a, 0x9c7e,
0x9c95, 0x9cac, 0x9cc3, 0x9cda, 0x9cec, 0x9cfe, 0x9d10, 0x9d27,
// Entry 2D80 - 2DBF
0x9d39, 0x9d4b, 0x9d5d, 0x9d6f, 0x9d7b, 0x9d88, 0x9d95, 0x9da3,
0x9db0, 0x9dbe, 0x9dcc, 0x9dd9, 0x9de8, 0x9df7, 0x9e05, 0x9e14,
0x9e23, 0x9e31, 0x9e40, 0x9e4c, 0x9e58, 0x9e64, 0x9e70, 0x9e7d,
0x9e89, 0x9e96, 0x9ea3, 0x9eb0, 0x9ebe, 0x9ecb, 0x9ed8, 0x9ee5,
0x9ef2, 0x9eff, 0x9f0d, 0x9f1b, 0x9f2a, 0x9f3a, 0x9f47, 0x9f53,
0x9f61, 0x9f6f, 0x9f9c, 0x9fb4, 0x9fcc, 0x9fe4, 0x9ffc, 0xa014,
0xa02c, 0xa044, 0xa05c, 0xa074, 0xa08c, 0xa0a4, 0xa0bc, 0xa0d4,
0xa0ec, 0xa104, 0xa11c, 0xa137, 0xa151, 0xa16c, 0xa186, 0xa1a0,
// Entry 2DC0 - 2DFF
0xa1ba, 0xa1d3, 0xa1ed, 0xa207, 0xa223, 0xa23f, 0xa25b, 0xa277,
0xa291, 0xa2ae, 0xa2ca, 0xa2e7, 0xa303, 0xa31f, 0xa33b, 0xa356,
0xa372, 0xa38e, 0xa3ac, 0xa3ca, 0xa3e8, 0xa406, 0xa422, 0xa43e,
0xa462, 0xa485, 0xa4a0, 0xa4bb, 0xa4d8, 0xa4f4, 0xa510, 0xa52b,
0xa548, 0xa565, 0xa581, 0xa59c, 0xa5b8, 0xa5d4, 0xa5f1, 0xa60d,
0xa62a, 0xa647, 0xa662, 0xa67f, 0xa69b, 0xa6ba, 0xa6d6, 0xa6f5,
0xa716, 0xa73c, 0xa759, 0xa77a, 0xa796, 0xa7b3, 0xa7d4, 0xa7f6,
0xa816, 0xa836, 0xa856, 0xa872, 0xa88e, 0xa8ab, 0xa8c5, 0xa8e3,
// Entry 2E00 - 2E3F
0xa8fb, 0xa911, 0xa933, 0xa958, 0xa97d, 0xa9a1, 0xa9c5, 0xa9e9,
0xaa0f, 0xaa34, 0xaa44, 0xaa5d, 0xaa76, 0xaa91, 0xaaab, 0xaac5,
0xaade, 0xaaf9, 0xab14, 0xab2e, 0xab43, 0xab5c, 0xab75, 0xab90,
0xabaa, 0xabc4, 0xabd9, 0xabed, 0xac02, 0xac16, 0xac2a, 0xac3e,
0xac51, 0xac65, 0xac79, 0xac8f, 0xaca5, 0xacbb, 0xacd1, 0xace5,
0xacfc, 0xad12, 0xad29, 0xad3f, 0xad55, 0xad6b, 0xad80, 0xad96,
0xadac, 0xadc4, 0xaddc, 0xadf4, 0xae0c, 0xae22, 0xae41, 0xae5f,
0xae75, 0xae8b, 0xaea0, 0xaeb5, 0xaecc, 0xaee2, 0xaef8, 0xaf0d,
// Entry 2E40 - 2E7F
0xaf24, 0xaf3b, 0xaf51, 0xaf66, 0xaf7c, 0xaf92, 0xafa9, 0xafbf,
0xafd6, 0xafed, 0xb002, 0xb019, 0xb02f, 0xb048, 0xb05e, 0xb077,
0xb092, 0xb0b2, 0xb0c9, 0xb0e1, 0xb0f7, 0xb10f, 0xb129, 0xb144,
0xb15b, 0xb176, 0xb18c, 0xb1a2, 0xb1b8, 0xb1d1, 0xb1e7, 0xb1ff,
0xb214, 0xb22a, 0xb241, 0xb25b, 0xb275, 0xb28c, 0xb2a7, 0xb2c3,
0xb2dd, 0xb2f7, 0xb30e, 0xb327, 0xb342, 0xb35d, 0xb377, 0xb38b,
0xb3a3, 0xb3bb, 0xb3d5, 0xb3ee, 0xb407, 0xb41f, 0xb439, 0xb453,
0xb46c, 0xb480, 0xb4a8, 0xb4d1, 0xb4f7, 0xb51d, 0xb541, 0xb566,
// Entry 2E80 - 2EBF
0xb58b, 0xb5b2, 0xb5dc, 0xb604, 0xb62d, 0xb656, 0xb65f, 0xb669,
0xb672, 0xb688, 0xb69a, 0xb6ac, 0xb6be, 0xb6d0, 0xb6e2, 0xb6f5,
0xb708, 0xb71b, 0xb72e, 0xb741, 0xb754, 0xb767, 0xb77a, 0xb78d,
0xb7a0, 0xb7b3, 0xb7c6, 0xb7d9, 0xb7ec, 0xb7ff, 0xb812, 0xb825,
0xb838, 0xb84b, 0xb85e, 0xb871, 0xb884, 0xb897, 0xb8aa, 0xb8bd,
0xb8d0, 0xb8e3, 0xb8f6, 0xb909, 0xb91c, 0xb92f, 0xb942, 0xb955,
0xb968, 0xb97b, 0xb98e, 0xb9a1, 0xb9b4, 0xb9c7, 0xb9da, 0xb9ed,
0xba00, 0xba15, 0xba22, 0xba2f, 0xba3b, 0xba46, 0xba53, 0xba5e,
// Entry 2EC0 - 2EFF
0xba68, 0xba77, 0xba83, 0xba8e, 0xba99, 0xbaa5, 0xbab3, 0xbac1,
0xbacd, 0xbad9, 0xbae4, 0xbaf0, 0xbafd, 0xbb0b, 0xbb16, 0xbb27,
0xbb39, 0xbb49, 0xbb56, 0xbb66, 0xbb76, 0xbb84, 0xbb90, 0xbb9d,
0xbba9, 0xbbb7, 0xbbc6, 0xbbd4, 0xbbe0, 0xbbec, 0xbbf8, 0xbc03,
0xbc0e, 0xbc18, 0xbc23, 0xbc2f, 0xbc3b, 0xbc4a, 0xbc56, 0xbc64,
0xbc74, 0xbc81, 0xbc8c, 0xbc97, 0xbca6, 0xbcb3, 0xbcc2, 0xbcce,
0xbcde, 0xbce9, 0xbcf6, 0xbd03, 0xbd0f, 0xbd1b, 0xbd27, 0xbd34,
0xbd41, 0xbd4b, 0xbd57, 0xbd63, 0xbd6e, 0xbd7c, 0xbd88, 0xbd94,
// Entry 2F00 - 2F3F
0xbda1, 0xbdaf, 0xbdbd, 0xbdc8, 0xbdd8, 0xbde3, 0xbdf1, 0xbdff,
0xbe0b, 0xbe17, 0xbe22, 0xbe30, 0xbe3b, 0xbe47, 0xbe55, 0xbe60,
0xbe6f, 0xbe7b, 0xbea5, 0xbece, 0xbef7, 0xbf22, 0xbf4c, 0xbf76,
0xbf9f, 0xbfca, 0xbff5, 0xc01f, 0xc048, 0xc074, 0xc0a0, 0xc0ce,
0xc0fc, 0xc129, 0xc156, 0xc185, 0xc1b3, 0xc1e1, 0xc20d, 0xc23d,
0xc26d, 0xc29f, 0xc2d0, 0xc2da, 0xc2e3, 0xc2ec, 0xc2f6, 0xc2ff,
0xc308, 0xc311, 0xc322, 0xc331, 0xc33a, 0xc350, 0xc366, 0xc37d,
0xc392, 0xc3a4, 0xc3b2, 0xc3bb, 0xc3c6, 0xc3cf, 0xc3d8, 0xc3e1,
// Entry 2F40 - 2F7F
0xc3ea, 0xc3f3, 0xc3fd, 0xc408, 0xc411, 0xc41a, 0xc425, 0xc430,
0xc439, 0xc442, 0xc44b, 0xc455, 0xc45f, 0xc469, 0xc473, 0xc47e,
0xc487, 0xc490, 0xc499, 0xc4a2, 0xc4ab, 0xc4b6, 0xc4bf, 0xc4c8,
0xc4d1, 0xc4e2, 0xc4f3, 0xc503, 0xc514, 0xc523, 0xc532, 0xc540,
0xc54f, 0xc55e, 0xc575, 0xc57e, 0xc588, 0xc592, 0xc59c, 0xc5a6,
0xc5b7, 0xc5d0, 0xc5d9, 0xc5e2, 0xc5ed, 0xc5f6, 0xc5ff, 0xc608,
0xc613, 0xc61c, 0xc625, 0xc633, 0xc63c, 0xc645, 0xc650, 0xc659,
0xc662, 0xc670, 0xc67c, 0xc688, 0xc691, 0xc69a, 0xc6a3, 0xc6ac,
// Entry 2F80 - 2FBF
0xc6bc, 0xc6c5, 0xc6ce, 0xc6d7, 0xc6e0, 0xc6e9, 0xc6f2, 0xc6fb,
0xc70c, 0xc715, 0xc71e, 0xc727, 0xc731, 0xc73a, 0xc749, 0xc753,
0xc75d, 0xc766, 0xc76f, 0xc779, 0xc782, 0xc78b, 0xc794, 0xc79d,
0xc7ac, 0xc7bb, 0xc7e3, 0xc80b, 0xc835, 0xc85e, 0xc887, 0xc8af,
0xc8d9, 0xc903, 0xc92c, 0xc954, 0xc97f, 0xc9aa, 0xc9d7, 0xca04,
0xca30, 0xca5c, 0xca8a, 0xcab7, 0xcae4, 0xcb0f, 0xcb3e, 0xcb6d,
0xcb9e, 0xcbce, 0xcbfe, 0xcc2d, 0xcc5e, 0xcc8f, 0xccbf, 0xccea,
0xcd19, 0xcd23, 0xcd43, 0xcd63, 0xcd8b, 0xcda6, 0xcdba, 0xcdcf,
// Entry 2FC0 - 2FFF
0xcde4, 0xce01, 0xce1a, 0xce2f, 0xce41, 0xce58, 0xce6f, 0xce8c,
0xcea0, 0xceb7, 0xcecd, 0xceed, 0xcf02, 0xcf1c, 0xcf37, 0xcf49,
0xcf65, 0xcf78, 0xcf8e, 0xcfa7, 0xcfc1, 0xcfe1, 0xcfff, 0xd01d,
0xd033, 0xd048, 0xd05c, 0xd074, 0xd089, 0xd0ac, 0xd0c3, 0xd0da,
0xd0f2, 0xd10a, 0xd11f, 0xd134, 0xd14d, 0xd168, 0xd187, 0xd1a2,
0xd1b9, 0xd1ce, 0xd1e5, 0xd1fe, 0xd21f, 0xd246, 0xd25e, 0xd27e,
0xd294, 0xd2ad, 0xd2c9, 0xd2e5, 0xd2fc, 0xd313, 0xd32b, 0xd34b,
0xd368, 0xd386, 0xd394, 0xd3a2, 0xd3af, 0xd3bd, 0xd3cc, 0xd3db,
// Entry 3000 - 303F
0xd3e9, 0xd3f8, 0xd406, 0xd414, 0xd421, 0xd42f, 0xd43e, 0xd44c,
0xd45b, 0xd469, 0xd477, 0xd484, 0xd492, 0xd4a0, 0xd4ad, 0xd4bb,
0xd4ca, 0xd4d9, 0xd4e7, 0xd4f6, 0xd506, 0xd516, 0xd525, 0xd535,
0xd544, 0xd553, 0xd561, 0xd570, 0xd580, 0xd58f, 0xd59f, 0xd5ae,
0xd5bd, 0xd5cb, 0xd5da, 0xd5e9, 0xd5f7, 0xd606, 0xd615, 0xd624,
0xd632, 0xd641, 0xd651, 0xd660, 0xd66f, 0xd67e, 0xd68c, 0xd69b,
0xd6ab, 0xd6ba, 0xd6c9, 0xd6d8, 0xd6e6, 0xd6f5, 0xd705, 0xd714,
0xd724, 0xd733, 0xd742, 0xd750, 0xd75f, 0xd76f, 0xd77e, 0xd78e,
// Entry 3040 - 307F
0xd79d, 0xd7ac, 0xd7ba, 0xd7c9, 0xd7d8, 0xd7e7, 0xd7f5, 0xd804,
0xd814, 0xd823, 0xd832, 0xd841, 0xd84f, 0xd85e, 0xd86e, 0xd87d,
0xd88d, 0xd89d, 0xd8ac, 0xd8bc, 0xd8cd, 0xd8de, 0xd8ee, 0xd8ff,
0xd90f, 0xd91f, 0xd92e, 0xd93e, 0xd94f, 0xd95f, 0xd970, 0xd980,
0xd990, 0xd99f, 0xd9af, 0xd9bf, 0xd9ce, 0xd9de, 0xd9ee, 0xd9fe,
0xda0d, 0xda1d, 0xda2e, 0xda3e, 0xda4e, 0xda5e, 0xda6d, 0xda7d,
0xda8d, 0xda9d, 0xdaac, 0xdabc, 0xdacd, 0xdadd, 0xdaee, 0xdafe,
0xdb0e, 0xdb1d, 0xdb2d, 0xdb3d, 0xdb4d, 0xdb5c, 0xdb6c, 0xdb7c,
// Entry 3080 - 30BF
0xdb8c, 0xdb9b, 0xdbab, 0xdbbc, 0xdbcc, 0xdbdc, 0xdbec, 0xdbfb,
0xdc0b, 0xdc1c, 0xdc2c, 0xdc3c, 0xdc4c, 0xdc5b, 0xdc6b, 0xdc7c,
0xdc8c, 0xdc9d, 0xdcad, 0xdcbd, 0xdccc, 0xdcdc, 0xdced, 0xdcfd,
0xdd0e, 0xdd1e, 0xdd2e, 0xdd3d, 0xdd4d, 0xdd5d, 0xdd6d, 0xdd7c,
0xdd8c, 0xdd9d, 0xddad, 0xddbd, 0xddcc, 0xdddc, 0xdded, 0xddfd,
0xde0c, 0xde1b, 0xde29, 0xde38, 0xde48, 0xde57, 0xde67, 0xde76,
0xde85, 0xde93, 0xdea2, 0xdeb2, 0xdec2, 0xded1, 0xdee1, 0xdef0,
0xdeff, 0xdf0d, 0xdf1c, 0xdf2b, 0xdf39, 0xdf48, 0xdf57, 0xdf65,
// Entry 30C0 - 30FF
0xdf74, 0xdf84, 0xdf93, 0xdfa2, 0xdfb1, 0xdfbf, 0xdfce, 0xdfdd,
0xdfec, 0xdffa, 0xe009, 0xe018, 0xe027, 0xe035, 0xe044, 0xe053,
0xe061, 0xe070, 0xe07f, 0xe08e, 0xe09c, 0xe0ab, 0xe0bb, 0xe0ca,
0xe0d9, 0xe0e8, 0xe0f6, 0xe105, 0xe114, 0xe123, 0xe131, 0xe140,
0xe150, 0xe160, 0xe16f, 0xe17f, 0xe18e, 0xe19d, 0xe1ab, 0xe1ba,
0xe1c9, 0xe1d8, 0xe1e6, 0xe1f5, 0xe204, 0xe213, 0xe222, 0xe231,
0xe23f, 0xe24e, 0xe25e, 0xe26d, 0xe27c, 0xe28b, 0xe299, 0xe2a8,
0xe2b8, 0xe2c7, 0xe2d6, 0xe2e5, 0xe2f3, 0xe302, 0xe312, 0xe321,
// Entry 3100 - 313F
0xe331, 0xe340, 0xe34f, 0xe35d, 0xe36c, 0xe37c, 0xe38b, 0xe39a,
0xe3a9, 0xe3b7, 0xe3c6, 0xe3d5, 0xe3e3, 0xe3f2, 0xe401, 0xe410,
0xe41e, 0xe42d, 0xe43d, 0xe44c, 0xe45b, 0xe46a, 0xe478, 0xe487,
0xe497, 0xe4a6, 0xe4b6, 0xe4c5, 0xe4d4, 0xe4e2, 0xe4f1, 0xe501,
0xe511, 0xe520, 0xe530, 0xe53f, 0xe54e, 0xe55c, 0xe56b, 0xe57a,
0xe588, 0xe597, 0xe5a6, 0xe5b5, 0xe5c3, 0xe5d2, 0xe5e2, 0xe5f1,
0xe601, 0xe611, 0xe620, 0xe630, 0xe641, 0xe651, 0xe662, 0xe672,
0xe682, 0xe691, 0xe6a1, 0xe6b2, 0xe6c2, 0xe6d3, 0xe6e3, 0xe6f3,
// Entry 3140 - 317F
0xe702, 0xe712, 0xe722, 0xe731, 0xe741, 0xe751, 0xe761, 0xe770,
0xe780, 0xe791, 0xe7a1, 0xe7b1, 0xe7c1, 0xe7d0, 0xe7e0, 0xe7f1,
0xe801, 0xe811, 0xe821, 0xe830, 0xe840, 0xe850, 0xe860, 0xe86f,
0xe87f, 0xe88f, 0xe89e, 0xe8ae, 0xe8be, 0xe8ce, 0xe8dd, 0xe8ed,
0xe8fe, 0xe90e, 0xe91e, 0xe92e, 0xe93d, 0xe94d, 0xe95e, 0xe96f,
0xe97f, 0xe990, 0xe9a0, 0xe9b0, 0xe9bf, 0xe9cf, 0xe9e0, 0xe9f0,
0xea00, 0xea10, 0xea20, 0xea30, 0xea3f, 0xea4f, 0xea5f, 0xea6e,
0xea7d, 0xea8b, 0xea9a, 0xeaaa, 0xeab9, 0xeac9, 0xead8, 0xeae6,
// Entry 3180 - 31BF
0xeaf5, 0xeb05, 0xeb14, 0xeb24, 0xeb33, 0xeb42, 0xeb50, 0xeb5f,
0xeb6e, 0xeb7c, 0xeb8b, 0xeb9a, 0xeba9, 0xebb7, 0xebc6, 0xebd6,
0xebe5, 0xebf5, 0xec05, 0xec14, 0xec24, 0xec35, 0xec45, 0xec56,
0xec66, 0xec76, 0xec85, 0xec95, 0xeca6, 0xecb6, 0xecc7, 0xecd7,
0xece6, 0xecf6, 0xed06, 0xed15, 0xed25, 0xed35, 0xed45, 0xed54,
0xed64, 0xed75, 0xed85, 0xed95, 0xeda5, 0xedb4, 0xedc4, 0xedd5,
0xede5, 0xedf4, 0xee03, 0xee11, 0xee20, 0xee30, 0xee40, 0xee4f,
0xee5f, 0xee6e, 0xee7d, 0xee8b, 0xee9a, 0xeeaa, 0xeeba, 0xeec9,
// Entry 31C0 - 31FF
0xeed9, 0xeee8, 0xeef7, 0xef05, 0xef14, 0xef23, 0xef31, 0xef40,
0xef4f, 0xef5e, 0xef6c, 0xef7b, 0xef8b, 0xef9a, 0xefa9, 0xefb8,
0xefc6, 0xefd5, 0xefe5, 0xeff4, 0xf003, 0xf012, 0xf020, 0xf02f,
0xf03f, 0xf04f, 0xf05e, 0xf06e, 0xf07d, 0xf08c, 0xf09a, 0xf0a9,
0xf0b9, 0xf0c9, 0xf0d8, 0xf0e8, 0xf0f7, 0xf106, 0xf114, 0xf123,
0xf132, 0xf141, 0xf14f, 0xf15e, 0xf16d, 0xf17c, 0xf18a, 0xf199,
0xf1a9, 0xf1b8, 0xf1c7, 0xf1d6, 0xf1e4, 0xf1f3, 0xf203, 0xf212,
0xf222, 0xf231, 0xf240, 0xf24e, 0xf25d, 0xf26d, 0xf27c, 0xf28c,
// Entry 3200 - 323F
0xf29b, 0xf2aa, 0xf2b8, 0xf2c7, 0xf2d6, 0xf2e5, 0xf2f3, 0xf302,
0xf311, 0xf320, 0xf32e, 0xf33d, 0xf34d, 0xf35c, 0xf36c, 0xf37c,
0xf38b, 0xf39c, 0xf3ac, 0xf3bd, 0xf3cd, 0xf3dd, 0xf3ec, 0xf3fc,
0xf40d, 0xf41e, 0xf42e, 0xf43f, 0xf44f, 0xf45f, 0xf46e, 0xf47e,
0xf48e, 0xf49e, 0xf4ad, 0xf4bd, 0xf4cd, 0xf4dd, 0xf4ec, 0xf4fc,
0xf50d, 0xf51d, 0xf52e, 0xf53e, 0xf54e, 0xf55e, 0xf56d, 0xf57d,
0xf58e, 0xf59e, 0xf5af, 0xf5bf, 0xf5cf, 0xf5de, 0xf5ee, 0xf5fe,
0xf60d, 0xf61d, 0xf62d, 0xf63d, 0xf64c, 0xf65c, 0xf66d, 0xf67d,
// Entry 3240 - 327F
0xf68d, 0xf69d, 0xf6ac, 0xf6bc, 0xf6cd, 0xf6de, 0xf6ee, 0xf6ff,
0xf70f, 0xf71f, 0xf72e, 0xf73e, 0xf74f, 0xf760, 0xf770, 0xf781,
0xf791, 0xf7a1, 0xf7b0, 0xf7c0, 0xf7d0, 0xf7df, 0xf7ef, 0xf800,
0xf810, 0xf821, 0xf831, 0xf841, 0xf850, 0xf860, 0xf871, 0xf882,
0xf892, 0xf8a2, 0xf8b2, 0xf8c1, 0xf8d1, 0xf8e1, 0xf8f0, 0xf900,
0xf90f, 0xf91f, 0xf92e, 0xf93d, 0xf94c, 0xf95a, 0xf969, 0xf979,
0xf989, 0xf998, 0xf9a8, 0xf9b7, 0xf9c6, 0xf9d4, 0xf9e3, 0xf9f2,
0xfa00, 0xfa0f, 0xfa1e, 0xfa2d, 0xfa3b, 0xfa4a, 0xfa5a, 0xfa69,
// Entry 3280 - 32BF
0xfa79, 0xfa88, 0xfa96, 0xfaa5, 0xfab4, 0xfac2, 0xfad1, 0xfae0,
0xfaef, 0xfafd, 0xfb0c, 0xfb1c, 0xfb2b, 0xfb3b, 0xfb4a, 0xfb59,
0xfb67, 0xfb76, 0xfb86, 0xfb95, 0xfba5, 0xfbb4, 0xfbc3, 0xfbd1,
0xfbe0, 0xfbef, 0xfbfd, 0xfc0c, 0xfc1b, 0xfc2a, 0xfc38, 0xfc47,
0xfc57, 0xfc66, 0xfc75, 0xfc84, 0xfc92, 0xfca1, 0xfcb1, 0xfcc0,
0xfccf, 0xfcde, 0xfcec, 0xfcfb, 0xfd0b, 0xfd1b, 0xfd2a, 0xfd3a,
0xfd49, 0xfd58, 0xfd66, 0xfd75, 0xfd85, 0xfd94, 0xfda4, 0xfdb3,
0xfdc2, 0xfdd0, 0xfddf, 0xfdee, 0xfdfc, 0xfe0b, 0xfe1a, 0xfe29,
// Entry 32C0 - 32FF
0xfe37, 0xfe46, 0xfe56, 0xfe65, 0xfe74, 0xfe83, 0xfe91, 0xfea0,
0xfeb0, 0xfebf, 0xfecf, 0xfedf, 0xfeee, 0xfefe, 0xff0f, 0xff20,
0xff30, 0xff41, 0xff51, 0xff61, 0xff70, 0xff80, 0xff90, 0xff9f,
0xffaf, 0xffbf, 0xffce, 0xffde, 0xffee, 0xfffd, 0x000d, 0x001e,
0x002e, 0x003e, 0x004e, 0x005d, 0x006d, 0x007e, 0x008e, 0x009e,
0x00ae, 0x00bd, 0x00cd, 0x00de, 0x00ee, 0x00ff, 0x010f, 0x011f,
0x012e, 0x013e, 0x014f, 0x015f, 0x016f, 0x017f, 0x018f, 0x019e,
0x01ae, 0x01bd, 0x01cd, 0x01de, 0x01ee, 0x01fe, 0x020e, 0x021d,
// Entry 3300 - 333F
0x022d, 0x023e, 0x024e, 0x025d, 0x026c, 0x027a, 0x0289, 0x0299,
0x02a8, 0x02b8, 0x02c7, 0x02d6, 0x02e4, 0x02f3, 0x0303, 0x0312,
0x0322, 0x0331, 0x0340, 0x034e, 0x035d, 0x036c, 0x037a, 0x0389,
0x0398, 0x03a7, 0x03b5, 0x03c4, 0x03d4, 0x03e3, 0x03f2, 0x0401,
0x040f, 0x041e, 0x042e, 0x043d, 0x044d, 0x045d, 0x046c, 0x047c,
0x048d, 0x049d, 0x04ae, 0x04be, 0x04ce, 0x04dd, 0x04ed, 0x04fd,
0x050d, 0x051c, 0x052c, 0x053c, 0x054b, 0x055b, 0x056b, 0x057b,
0x058a, 0x059a, 0x05aa, 0x05ba, 0x05c9, 0x05d9, 0x05ea, 0x05fa,
// Entry 3340 - 337F
0x060a, 0x061a, 0x0629, 0x0639, 0x064a, 0x065a, 0x066b, 0x067b,
0x068b, 0x069a, 0x06aa, 0x06ba, 0x06ca, 0x06d9, 0x06e9, 0x06f9,
0x0709, 0x0718, 0x0728, 0x0739, 0x0749, 0x0759, 0x0769, 0x0778,
0x0788, 0x0799, 0x07a9, 0x07b9, 0x07c9, 0x07d8, 0x07e8, 0x07f9,
0x080a, 0x081a, 0x082b, 0x083b, 0x084b, 0x085a, 0x086a, 0x087a,
0x088a, 0x0899, 0x08a9, 0x08b9, 0x08c8, 0x08d8, 0x08e9, 0x08f9,
0x0909, 0x0919, 0x0928, 0x0938, 0x0949, 0x0959, 0x0969, 0x0978,
0x0989, 0x0999, 0x09a9, 0x09b9, 0x09c8, 0x09d8, 0x09e8, 0x09f8,
// Entry 3380 - 33BF
0x0a07, 0x0a17, 0x0a27, 0x0a37, 0x0a46, 0x0a56, 0x0a67, 0x0a77,
0x0a87, 0x0a97, 0x0aa6, 0x0ab6, 0x0ac7, 0x0ad7, 0x0ae7, 0x0af7,
0x0b06, 0x0b16, 0x0b26, 0x0b35, 0x0b45, 0x0b55, 0x0b65, 0x0b74,
0x0b84, 0x0b94, 0x0ba4, 0x0bb3, 0x0bc3, 0x0bd4, 0x0be4, 0x0bf4,
0x0c04, 0x0c13, 0x0c23, 0x0c34, 0x0c44, 0x0c54, 0x0c64, 0x0c73,
0x0c83, 0x0c94, 0x0ca4, 0x0cb5, 0x0cc5, 0x0cd5, 0x0ce4, 0x0cf4,
0x0d04, 0x0d14, 0x0d23, 0x0d33, 0x0d43, 0x0d53, 0x0d62, 0x0d72,
0x0d83, 0x0d93, 0x0da3, 0x0db3, 0x0dc2, 0x0dd2, 0x0de3, 0x0df3,
// Entry 33C0 - 33FF
0x0e02, 0x0e11, 0x0e1f, 0x0e2e, 0x0e3e, 0x0e4d, 0x0e5d, 0x0e6c,
0x0e7b, 0x0e89, 0x0e98, 0x0ea7, 0x0eb5, 0x0ec4, 0x0ed3, 0x0ee2,
0x0ef0, 0x0eff, 0x0f0f, 0x0f1e, 0x0f2d, 0x0f3c, 0x0f4a, 0x0f59,
0x0f69, 0x0f78, 0x0f87, 0x0f96, 0x0fa4, 0x0fb3, 0x0fc3, 0x0fd3,
0x0fe2, 0x0ff2, 0x1002, 0x1012, 0x1021, 0x1031, 0x1040, 0x104f,
0x105d, 0x106c, 0x107b, 0x108a, 0x1098, 0x10a7, 0x10b7, 0x10c6,
0x10d5, 0x10e4, 0x10f2, 0x1101, 0x1111, 0x1120, 0x112f, 0x113e,
0x114c, 0x115b, 0x116b, 0x117b, 0x118a, 0x119a, 0x11aa, 0x11ba,
// Entry 3400 - 343F
0x11c9, 0x11d9, 0x11e8, 0x11f7, 0x1205, 0x1214, 0x1223, 0x1232,
0x1240, 0x124f, 0x125f, 0x126e, 0x127d, 0x128c, 0x129a, 0x12a9,
0x12b9, 0x12c8, 0x12d8, 0x12e8, 0x12f7, 0x1307, 0x1318, 0x1329,
0x1339, 0x134a, 0x135b, 0x136b, 0x137c, 0x138c, 0x139c, 0x13ab,
0x13bb, 0x13cb, 0x13db, 0x13ea, 0x13fa, 0x140b, 0x141b, 0x142b,
0x143b, 0x144a, 0x145a, 0x146a, 0x147a, 0x1489, 0x1499, 0x14aa,
0x14bb, 0x14cb, 0x14dc, 0x14ed, 0x14fd, 0x150d, 0x151d, 0x152c,
0x153c, 0x154c, 0x155b, 0x156b, 0x157c, 0x158c, 0x159c, 0x15ac,
// Entry 3440 - 347F
0x15bb, 0x15cb, 0x15dc, 0x15ec, 0x15fc, 0x160c, 0x161b, 0x162b,
0x163c, 0x164d, 0x165d, 0x166e, 0x167f, 0x168f, 0x16a0, 0x16b0,
0x16c0, 0x16cf, 0x16df, 0x16ef, 0x16ff, 0x170e, 0x171e, 0x172d,
0x173c, 0x174a, 0x1759, 0x1769, 0x1779, 0x1788, 0x1798, 0x17a8,
0x17b7, 0x17c6, 0x17d5, 0x17e3, 0x17f2, 0x1801, 0x1810, 0x181e,
0x182d, 0x183d, 0x184c, 0x185b, 0x186a, 0x1878, 0x1887, 0x1897,
0x18a7, 0x18b6, 0x18c6, 0x18d6, 0x18e6, 0x18f5, 0x1905, 0x1914,
0x1923, 0x1931, 0x1940, 0x194f, 0x195e, 0x196c, 0x197b, 0x198b,
// Entry 3480 - 34BF
0x199a, 0x19a9, 0x19b8, 0x19c6, 0x19d5, 0x19e5, 0x19f4, 0x1a02,
0x1a0f, 0x1a1d, 0x1a2c, 0x1a3a, 0x1a48, 0x1a57, 0x1a65, 0x1a72,
0x1a81, 0x1a8f, 0x1a9e, 0x1aac, 0x1ab9, 0x1ac7, 0x1ad6, 0x1ae4,
0x1af1, 0x1aff, 0x1b0d, 0x1b1c, 0x1b2a, 0x1b39, 0x1b48, 0x1b55,
0x1b62, 0x1b71, 0x1b7f, 0x1b8d, 0x1b9b, 0x1ba9, 0x1bb7, 0x1bc5,
0x1bd3, 0x1be0, 0x1bed, 0x1bfc, 0x1c0a, 0x1c18, 0x1c27, 0x1c34,
0x1c41, 0x1c50, 0x1c5e, 0x1c6b, 0x1c7a, 0x1c88, 0x1c97, 0x1ca6,
0x1cb4, 0x1cc3, 0x1cd1, 0x1ce1, 0x1cf0, 0x1cfd, 0x1d0b, 0x1d19,
// Entry 34C0 - 34FF
0x1d28, 0x1d36, 0x1d44, 0x1d53, 0x1d61, 0x1d6f, 0x1d7e, 0x1d8c,
0x1d9a, 0x1da9, 0x1db8, 0x1dc7, 0x1dd7, 0x1de5, 0x1df3, 0x1e01,
0x1e0f, 0x1e1e, 0x1e2c, 0x1e3b, 0x1e49, 0x1e57, 0x1e66, 0x1e74,
0x1e82, 0x1e91, 0x1e9f, 0x1eae, 0x1ebb, 0x1ec9, 0x1ed6, 0x1ee4,
0x1ef1, 0x1efe, 0x1f0b, 0x1f19, 0x1f27, 0x1f35, 0x1f4c, 0x1f62,
0x1f7a, 0x1f91, 0x1fa8, 0x1fc0, 0x1fd6, 0x1ff0, 0x1fff, 0x200f,
0x201f, 0x202f, 0x2040, 0x2050, 0x2061, 0x2071, 0x2082, 0x2093,
0x20a5, 0x20b6, 0x20c6, 0x20d6, 0x20e6, 0x20f7, 0x2108, 0x211a,
// Entry 3500 - 353F
0x212a, 0x213a, 0x214a, 0x215b, 0x216b, 0x217c, 0x218c, 0x219d,
0x21ad, 0x21bd, 0x21ce, 0x21de, 0x21ee, 0x2200, 0x2210, 0x2220,
0x2230, 0x2241, 0x224f, 0x225e, 0x226d, 0x227d, 0x228c, 0x229c,
0x22ab, 0x22bb, 0x22ca, 0x22da, 0x22ea, 0x22fb, 0x230b, 0x231a,
0x2329, 0x2338, 0x2348, 0x2358, 0x2369, 0x2378, 0x2387, 0x2396,
0x23a6, 0x23b5, 0x23c5, 0x23d4, 0x23e4, 0x23f3, 0x2402, 0x2412,
0x2421, 0x2430, 0x2441, 0x2450, 0x245f, 0x246e, 0x247e, 0x248c,
0x249b, 0x24ac, 0x24bb, 0x24cb, 0x24da, 0x24ea, 0x24f9, 0x2509,
// Entry 3540 - 357F
0x2518, 0x2528, 0x2538, 0x2549, 0x255a, 0x256a, 0x2579, 0x2588,
0x2597, 0x25a7, 0x25b7, 0x25c8, 0x25d7, 0x25e6, 0x25f5, 0x2605,
0x2614, 0x2624, 0x2633, 0x2643, 0x2652, 0x2661, 0x2671, 0x2680,
0x268f, 0x269f, 0x26b0, 0x26bf, 0x26ce, 0x26dd, 0x26ed, 0x26fc,
0x270c, 0x271c, 0x272c, 0x273d, 0x274d, 0x275e, 0x276e, 0x277f,
0x2790, 0x27a2, 0x27b3, 0x27c3, 0x27d3, 0x27e3, 0x27f4, 0x2805,
0x2817, 0x2827, 0x2837, 0x2847, 0x2858, 0x2868, 0x2879, 0x2889,
0x289a, 0x28aa, 0x28ba, 0x28cb, 0x28db, 0x28eb, 0x28fd, 0x290d,
// Entry 3580 - 35BF
0x291d, 0x292d, 0x293e, 0x294c, 0x295b, 0x296a, 0x297a, 0x2989,
0x2999, 0x29a8, 0x29b8, 0x29c7, 0x29d7, 0x29e7, 0x29f8, 0x2a08,
0x2a17, 0x2a26, 0x2a35, 0x2a45, 0x2a55, 0x2a66, 0x2a75, 0x2a84,
0x2a93, 0x2aa3, 0x2ab2, 0x2ac2, 0x2ad1, 0x2ae1, 0x2af0, 0x2aff,
0x2b0f, 0x2b1e, 0x2b2d, 0x2b3e, 0x2b4d, 0x2b5c, 0x2b6b, 0x2b7b,
0x2b89, 0x2b98, 0x2ba9, 0x2bb8, 0x2bc8, 0x2bd7, 0x2be7, 0x2bf6,
0x2c06, 0x2c15, 0x2c25, 0x2c35, 0x2c46, 0x2c56, 0x2c67, 0x2c76,
0x2c85, 0x2c94, 0x2ca4, 0x2cb4, 0x2cc5, 0x2cd4, 0x2ce3, 0x2cf2,
// Entry 35C0 - 35FF
0x2d02, 0x2d11, 0x2d21, 0x2d30, 0x2d40, 0x2d4f, 0x2d5e, 0x2d6e,
0x2d7d, 0x2d8c, 0x2d9d, 0x2dac, 0x2dbb, 0x2dca, 0x2dda, 0x2de8,
0x2df7, 0x2e08, 0x2e17, 0x2e27, 0x2e36, 0x2e46, 0x2e55, 0x2e65,
0x2e74, 0x2e84, 0x2e94, 0x2ea5, 0x2eb6, 0x2ec6, 0x2ed7, 0x2ee6,
0x2ef5, 0x2f04, 0x2f14, 0x2f24, 0x2f35, 0x2f44, 0x2f53, 0x2f62,
0x2f72, 0x2f81, 0x2f91, 0x2fa0, 0x2fb0, 0x2fbf, 0x2fce, 0x2fde,
0x2fed, 0x2ffc, 0x300d, 0x301f, 0x302e, 0x303e, 0x304d, 0x305c,
0x306c, 0x307b, 0x3092, 0x309b, 0x30a8, 0x30b9, 0x30ce, 0x30e3,
// Entry 3600 - 363F
0x30f9, 0x3109, 0x3119, 0x3128, 0x3136, 0x3145, 0x3153, 0x3161,
0x3170, 0x3180, 0x318f, 0x319e, 0x31ad, 0x31bc, 0x31ca, 0x31d7,
0x31e4, 0x31f3, 0x3201, 0x320f, 0x321c, 0x322b, 0x323a, 0x3248,
0x325d, 0x3272, 0x3290, 0x32ac, 0x32c9, 0x32e4, 0x3308, 0x332a,
0x3346, 0x3360, 0x337d, 0x3398, 0x33bc, 0x33de, 0x3401, 0x3422,
0x3445, 0x3466, 0x3490, 0x34b8, 0x34dc, 0x34fe, 0x3521, 0x3542,
0x3564, 0x3584, 0x35ad, 0x35d4, 0x35f7, 0x3618, 0x364a, 0x367a,
0x3694, 0x36ac, 0x36d0, 0x36f2, 0x3711, 0x372e, 0x374d, 0x376a,
// Entry 3640 - 367F
0x3789, 0x37a6, 0x37c9, 0x37ea, 0x380d, 0x382e, 0x3858, 0x3880,
0x389d, 0x38b5, 0x38d9, 0x3901, 0x392a, 0x393b, 0x3961, 0x397c,
0x3998, 0x39b3, 0x39d6, 0x39f4, 0x3a17, 0x3a36, 0x3a4f, 0x3a69,
0x3a78, 0x3a88, 0x3aa3, 0x3abc, 0x3ad8, 0x3af2, 0x3b0e, 0x3b28,
0x3b44, 0x3b5e, 0x3b7a, 0x3b94, 0x3bbf, 0x3be8, 0x3c03, 0x3c1c,
0x3c38, 0x3c52, 0x3c6e, 0x3c88, 0x3ca4, 0x3cbe, 0x3cd9, 0x3cf2,
0x3d0e, 0x3d28, 0x3d48, 0x3d66, 0x3d87, 0x3da6, 0x3dc8, 0x3dea,
0x3e06, 0x3e2a, 0x3e38, 0x3e47, 0x3e55, 0x3e64, 0x3e73, 0x3e83,
// Entry 3680 - 36BF
0x3e93, 0x3ea1, 0x3eb1, 0x3ebf, 0x3ece, 0x3edd, 0x3eed, 0x3efe,
0x3f10, 0x3f22, 0x3f32, 0x3f43, 0x3f55, 0x3f63, 0x3f73, 0x3f82,
0x3f93, 0x3fa2, 0x3fb4, 0x3fc5, 0x3fd6, 0x3fe6, 0x3ff7, 0x4006,
0x4018, 0x4028, 0x4038, 0x4048, 0x4057, 0x4068, 0x4079, 0x408a,
0x409b, 0x40ac, 0x40bc, 0x40cc, 0x40dc, 0x40ec, 0x40fb, 0x410a,
0x4119, 0x4128, 0x4139, 0x4149, 0x4159, 0x416d, 0x417e, 0x418e,
0x419e, 0x41af, 0x41be, 0x41ce, 0x41dd, 0x41ec, 0x41fb, 0x420a,
0x421a, 0x4229, 0x423a, 0x424a, 0x425a, 0x4269, 0x4278, 0x4287,
// Entry 36C0 - 36FF
0x4296, 0x42a7, 0x42b7, 0x42c7, 0x42d7, 0x42e8, 0x42fa, 0x430d,
0x431f, 0x4332, 0x434e, 0x436c, 0x4379, 0x4388, 0x4393, 0x439e,
0x43ad, 0x43c0, 0x43e5, 0x440b, 0x4431, 0x4458, 0x447b, 0x449f,
0x44c2, 0x44e6, 0x4510, 0x4534, 0x4557, 0x457a, 0x45a3, 0x45d7,
0x4605, 0x4632, 0x465f, 0x4692, 0x46bf, 0x46e6, 0x470c, 0x4732,
0x475e, 0x477e, 0x4797, 0x47b9, 0x47e1, 0x4800, 0x4821, 0x4848,
0x4878, 0x48a5, 0x48c9, 0x48ec, 0x4913, 0x4938, 0x495e, 0x4982,
0x499b, 0x49b2, 0x49c9, 0x49de, 0x49fb, 0x4a16, 0x4a34, 0x4a50,
// Entry 3700 - 373F
0x4a79, 0x4aa0, 0x4abc, 0x4ad8, 0x4aef, 0x4b04, 0x4b1b, 0x4b30,
0x4b47, 0x4b5c, 0x4b73, 0x4b88, 0x4bb3, 0x4bdc, 0x4bf3, 0x4c08,
0x4c30, 0x4c56, 0x4c78, 0x4c98, 0x4cc3, 0x4cec, 0x4d22, 0x4d56,
0x4d73, 0x4d8e, 0x4db5, 0x4dda, 0x4e09, 0x4e36, 0x4e56, 0x4e74,
0x4e8b, 0x4ea0, 0x4ed4, 0x4f06, 0x4f2a, 0x4f4c, 0x4f75, 0x4f9c,
0x4fd0, 0x5002, 0x502d, 0x5056, 0x5074, 0x5090, 0x50b0, 0x50ce,
0x50f9, 0x5122, 0x5139, 0x514e, 0x516f, 0x518e, 0x51b4, 0x51d8,
0x5210, 0x5246, 0x525f, 0x5276, 0x528d, 0x52a2, 0x52b9, 0x52ce,
// Entry 3740 - 377F
0x52e6, 0x52fc, 0x530e, 0x5324, 0x533a, 0x5350, 0x5366, 0x537c,
0x539a, 0x53b0, 0x53c5, 0x53e3, 0x53ff, 0x541d, 0x5439, 0x5457,
0x547c, 0x549f, 0x54bc, 0x54d7, 0x54f5, 0x5511, 0x552f, 0x554b,
0x5569, 0x5585, 0x55aa, 0x55bf, 0x55e0, 0x55fd, 0x5618, 0x5635,
0x5666, 0x5682, 0x56a7, 0x56ca, 0x56e9, 0x5706, 0x572c, 0x5752,
0x5776, 0x5798, 0x57ba, 0x57da, 0x57f9, 0x5816, 0x5835, 0x5852,
0x5871, 0x588e, 0x58b8, 0x58e0, 0x590a, 0x5932, 0x595c, 0x5984,
0x59ae, 0x59d6, 0x5a00, 0x5a28, 0x5a48, 0x5a6c, 0x5a89, 0x5aa9,
// Entry 3780 - 37BF
0x5acd, 0x5ae9, 0x5b06, 0x5b23, 0x5b4b, 0x5b63, 0x5b7c, 0x5b93,
0x5bad, 0x5bc5, 0x5be7, 0x5c07, 0x5c25, 0x5c41, 0x5c5f, 0x5c7b,
0x5c99, 0x5cb5, 0x5cd6, 0x5cf5, 0x5d15, 0x5d33, 0x5d5b, 0x5d7b,
0x5da3, 0x5dd3, 0x5e01, 0x5e31, 0x5e5f, 0x5e7d, 0x5ea8, 0x5ed1,
0x5f01, 0x5f2f, 0x5f54, 0x5f77, 0x5f98, 0x5fb7, 0x5fd7, 0x5ff5,
0x6018, 0x6039, 0x6057, 0x6073, 0x608e, 0x60a7, 0x60ce, 0x60e7,
0x6100, 0x6119, 0x6132, 0x6156, 0x6178, 0x619a, 0x61bf, 0x61e0,
0x6203, 0x6225, 0x6247, 0x6269, 0x6288, 0x62a9, 0x62be, 0x62d3,
// Entry 37C0 - 37FF
0x62ed, 0x6302, 0x6317, 0x632c, 0x6345, 0x635b, 0x6372, 0x6388,
0x639f, 0x63b9, 0x63cf, 0x63e6, 0x63fc, 0x6413, 0x642a, 0x6442,
0x6459, 0x6471, 0x6487, 0x649e, 0x64b4, 0x64cb, 0x64e1, 0x64f7,
0x650e, 0x6524, 0x653b, 0x6551, 0x6567, 0x657d, 0x6594, 0x65aa,
0x65c0, 0x65d9, 0x65f2, 0x660b, 0x6624, 0x663e, 0x6658, 0x6672,
0x668c, 0x66a6, 0x66c9, 0x66e9, 0x6706, 0x6729, 0x674b, 0x676a,
0x678f, 0x67a7, 0x67c3, 0x67d9, 0x67f2, 0x6804, 0x6817, 0x6829,
0x683c, 0x684e, 0x6861, 0x6873, 0x6886, 0x6898, 0x68ab, 0x68bd,
// Entry 3800 - 383F
0x68cf, 0x68e1, 0x68f4, 0x6906, 0x6918, 0x692b, 0x693f, 0x6952,
0x6964, 0x6977, 0x6989, 0x69a0, 0x69b2, 0x69c4, 0x69d6, 0x69e9,
0x69fb, 0x6a0d, 0x6a1e, 0x6a2f, 0x6a40, 0x6a51, 0x6a62, 0x6a74,
0x6a86, 0x6a98, 0x6aab, 0x6abd, 0x6ad9, 0x6af5, 0x6b08, 0x6b1c,
0x6b2f, 0x6b42, 0x6b5e, 0x6b7b, 0x6b94, 0x6bb0, 0x6bcc, 0x6be9,
0x6c04, 0x6c1d, 0x6c36, 0x6c48, 0x6c61, 0x6c79, 0x6c90, 0x6ca3,
0x6cb7, 0x6cca, 0x6cde, 0x6cf1, 0x6d05, 0x6d20, 0x6d3c, 0x6d57,
0x6d73, 0x6d86, 0x6d9a, 0x6dae, 0x6dc1, 0x6dd5, 0x6de9, 0x6dfd,
// Entry 3840 - 387F
0x6e12, 0x6e26, 0x6e3b, 0x6e50, 0x6e64, 0x6e79, 0x6e8d, 0x6ea2,
0x6eb7, 0x6ecc, 0x6ee2, 0x6ef7, 0x6f0d, 0x6f22, 0x6f36, 0x6f4b,
0x6f5f, 0x6f74, 0x6f88, 0x6f9c, 0x6fb1, 0x6fc5, 0x6fda, 0x6fee,
0x7002, 0x7016, 0x702a, 0x703e, 0x7053, 0x7068, 0x707c, 0x7090,
0x70a5, 0x70c4, 0x70dc, 0x70f3, 0x710b, 0x7122, 0x713a, 0x7159,
0x7179, 0x7198, 0x71b8, 0x71cf, 0x71e7, 0x71ff, 0x7216, 0x722e,
0x7246, 0x725c, 0x7277, 0x7287, 0x729e, 0x72b3, 0x72c7, 0x72db,
0x72f1, 0x7306, 0x731b, 0x732f, 0x7345, 0x735b, 0x7370, 0x738f,
// Entry 3880 - 38BF
0x73ad, 0x73cb, 0x73eb, 0x740a, 0x7429, 0x7447, 0x7467, 0x7487,
0x74a6, 0x74c3, 0x74e0, 0x74fe, 0x751c, 0x753a, 0x7558, 0x7576,
0x7598, 0x75bb, 0x75dd, 0x7606, 0x7625, 0x7646, 0x766a, 0x7682,
0x7697, 0x76a7, 0x76bc, 0x76d3, 0x76e5, 0x76f9, 0x7711, 0x7724,
0x7736, 0x7748, 0x775c, 0x776f, 0x7782, 0x7794, 0x77a8, 0x77bc,
0x77cf, 0x77e1, 0x77f4, 0x7806, 0x7819, 0x782b, 0x783e, 0x7850,
0x7863, 0x7875, 0x7888, 0x789a, 0x78ac, 0x78bf, 0x78d1, 0x78e3,
0x78f5, 0x7907, 0x7919, 0x792b, 0x793d, 0x7950, 0x7962, 0x7974,
// Entry 38C0 - 38FF
0x7986, 0x7997, 0x79a9, 0x79ba, 0x79cc, 0x79dd, 0x79ed, 0x79fd,
0x7a0e, 0x7a1e, 0x7a32, 0x7a45, 0x7a5f, 0x7a70, 0x7a82, 0x7a92,
0x7aa2, 0x7ab3, 0x7ac3, 0x7ad3, 0x7ae3, 0x7af3, 0x7b03, 0x7b13,
0x7b23, 0x7b33, 0x7b44, 0x7b54, 0x7b64, 0x7b74, 0x7b84, 0x7b94,
0x7ba4, 0x7bb5, 0x7bc7, 0x7bd8, 0x7bea, 0x7bf9, 0x7c0c, 0x7c1f,
0x7c32, 0x7c46, 0x7c59, 0x7c6d, 0x7c81, 0x7c95, 0x7cad, 0x7cc4,
0x7cdb, 0x7cf2, 0x7cff, 0x7d12, 0x7d2e, 0x7d4a, 0x7d65, 0x7d81,
0x7d9d, 0x7dbe, 0x7dda, 0x7dfb, 0x7e16, 0x7e31, 0x7e51, 0x7e74,
// Entry 3900 - 393F
0x7e8e, 0x7ea9, 0x7ec6, 0x7ee2, 0x7efe, 0x7f18, 0x7f3a, 0x7f57,
0x7f72, 0x7f91, 0x7fac, 0x7fc7, 0x7fe7, 0x8003, 0x8020, 0x803a,
0x805a, 0x8071, 0x8084, 0x8097, 0x80ac, 0x80bd, 0x80d3, 0x80e4,
0x80f6, 0x8107, 0x811f, 0x8138, 0x8159, 0x816a, 0x817c, 0x818d,
0x819f, 0x81b7, 0x81cf, 0x81e1, 0x81f9, 0x820c, 0x821e, 0x8236,
0x8248, 0x8261, 0x827d, 0x8290, 0x82a3, 0x82c0, 0x82d3, 0x82f0,
0x8308, 0x831a, 0x8332, 0x8344, 0x8360, 0x8372, 0x8384, 0x839c,
0x83ae, 0x83c6, 0x83d8, 0x83ea, 0x83fc, 0x8414, 0x8426, 0x8438,
// Entry 3940 - 397F
0x8450, 0x846c, 0x847e, 0x8490, 0x84a8, 0x84c2, 0x84dc, 0x84f4,
0x8512, 0x852a, 0x8549, 0x8563, 0x8581, 0x859a, 0x85b7, 0x85d6,
0x85f3, 0x8603, 0x861a, 0x8632, 0x8645, 0x8658, 0x866b, 0x867e,
0x8693, 0x86a7, 0x86bb, 0x86cd, 0x86e4, 0x86f9, 0x8715, 0x8729,
0x873c, 0x874e, 0x8760, 0x8774, 0x8787, 0x879a, 0x87ac, 0x87c0,
0x87d4, 0x87e7, 0x8802, 0x8819, 0x8830, 0x8847, 0x885e, 0x8875,
0x888c, 0x88a1, 0x88cb, 0x88e7, 0x8902, 0x891d, 0x8939, 0x8954,
0x8970, 0x898c, 0x89a9, 0x89c5, 0x89e1, 0x89fc, 0x8a17, 0x8a34,
// Entry 3980 - 39BF
0x8a50, 0x8a6c, 0x8a87, 0x8aa4, 0x8ac1, 0x8add, 0x8af9, 0x8b14,
0x8b30, 0x8b4b, 0x8b67, 0x8b74, 0x8b81, 0x8b8e, 0x8b9b, 0x8ba9,
0x8bb6, 0x8bc4, 0x8bd3, 0x8be1, 0x8bf0, 0x8c00, 0x8c0f, 0x8c1e,
0x8c2e, 0x8c3c, 0x8c4b, 0x8c5b, 0x8c6a, 0x8c7a, 0x8c88, 0x8c97,
0x8ca5, 0x8cb4, 0x8cc3, 0x8cd1, 0x8ce0, 0x8cee, 0x8cfd, 0x8d0c,
0x8d1a, 0x8d29, 0x8d38, 0x8d46, 0x8d55, 0x8d63, 0x8d71, 0x8d7f,
0x8d8d, 0x8d9c, 0x8daa, 0x8db8, 0x8dca, 0x8ddb, 0x8ded, 0x8dff,
0x8e10, 0x8e22, 0x8e33, 0x8e45, 0x8e57, 0x8e69, 0x8e7f, 0x8e95,
// Entry 39C0 - 39FF
0x8eab, 0x8ec1, 0x8ed4, 0x8ee7, 0x8efb, 0x8f17, 0x8f2b, 0x8f3e,
0x8f51, 0x8f64, 0x8f77, 0x8f8a, 0x8f9d, 0x8fb1, 0x8fcc, 0x8fe7,
0x8ff6, 0x9004, 0x9012, 0x9022, 0x9031, 0x9040, 0x904e, 0x905e,
0x906e, 0x907d, 0x9094, 0x90aa, 0x90c7, 0x90e4, 0x90fc, 0x9114,
0x912d, 0x9145, 0x915e, 0x9177, 0x9190, 0x91aa, 0x91c3, 0x91dd,
0x91f6, 0x920e, 0x9226, 0x923e, 0x9257, 0x926f, 0x929b, 0x92b3,
0x92cb, 0x92e3, 0x92fe, 0x9318, 0x9332, 0x9352, 0x936a, 0x9382,
0x9399, 0x93b4, 0x93d1, 0x93ee, 0x940d, 0x942c, 0x9442, 0x9459,
// Entry 3A00 - 3A3F
0x9470, 0x9488, 0x94a0, 0x94b9, 0x94cf, 0x94e6, 0x94fd, 0x9515,
0x952b, 0x9542, 0x9559, 0x9571, 0x9587, 0x959e, 0x95b5, 0x95cd,
0x95e3, 0x95fa, 0x9610, 0x9627, 0x963e, 0x9656, 0x966c, 0x9683,
0x9699, 0x96b0, 0x96c6, 0x96dd, 0x96f4, 0x970c, 0x9722, 0x9739,
0x974f, 0x9766, 0x977c, 0x9793, 0x97a9, 0x97c0, 0x97d6, 0x97ed,
0x9803, 0x981a, 0x9830, 0x9847, 0x985c, 0x9872, 0x9883, 0x9894,
0x98a4, 0x98b5, 0x98c5, 0x98d5, 0x98e5, 0x98f6, 0x9907, 0x9919,
0x992a, 0x993c, 0x994d, 0x995e, 0x996f, 0x9983, 0x999a, 0x99af,
// Entry 3A40 - 3A7F
0x99c5, 0x99d8, 0x99ed, 0x9a00, 0x9a16, 0x9a2d, 0x9a42, 0x9a57,
0x9a6e, 0x9a85, 0x9a9c, 0x9ab4, 0x9acb, 0x9ae3, 0x9afa, 0x9b11,
0x9b28, 0x9b42, 0x9b5c, 0x9b77, 0x9b91, 0x9bac, 0x9bc1, 0x9bda,
0x9beb, 0x9c10, 0x9c31, 0x9c50, 0x9c63, 0x9c79, 0x9c8f, 0x9ca6,
0x9cbd, 0x9cd3, 0x9ce9, 0x9cff, 0x9d15, 0x9d2c, 0x9d43, 0x9d59,
0x9d6f, 0x9d84, 0x9d99, 0x9daf, 0x9dc5, 0x9dda, 0x9def, 0x9e06,
0x9e1d, 0x9e34, 0x9e4c, 0x9e64, 0x9e7b, 0x9e92, 0x9ea7, 0x9ebc,
0x9ed1, 0x9ee7, 0x9efd, 0x9f12, 0x9f27, 0x9f46, 0x9f69, 0x9f89,
// Entry 3A80 - 3ABF
0x9fa4, 0x9fc6, 0x9fe0, 0xa00d, 0xa036, 0xa063, 0xa088, 0xa0ae,
0xa0d4, 0xa0fc, 0xa11c, 0xa148, 0xa16d, 0xa18b, 0xa1b3, 0xa1e6,
0xa208, 0xa236, 0xa252, 0xa27d, 0xa2a0, 0xa2bb, 0xa2e1, 0xa30e,
0xa329, 0xa34e, 0xa36d, 0xa396, 0xa3c3, 0xa3d8, 0xa3f4, 0xa417,
0xa42d, 0xa457, 0xa481, 0xa4a9, 0xa4d0, 0xa50a, 0xa53c, 0xa565,
0xa587, 0xa5a1, 0xa5cd, 0xa5f6, 0xa61c, 0xa638, 0xa655, 0xa66f,
0xa684, 0xa6a5, 0xa6c5, 0xa6f6, 0xa727, 0xa754, 0xa772, 0xa78b,
0xa7a5, 0xa7bc, 0xa7d3, 0xa7ea, 0xa801, 0xa818, 0xa82f, 0xa847,
// Entry 3AC0 - 3AFF
0xa85f, 0xa877, 0xa88f, 0xa8a7, 0xa8bf, 0xa8d7, 0xa8ef, 0xa907,
0xa91f, 0xa937, 0xa94f, 0xa967, 0xa97f, 0xa997, 0xa9af, 0xa9c7,
0xa9df, 0xa9f7, 0xaa0f, 0xaa27, 0xaa3f, 0xaa57, 0xaa6f, 0xaa87,
0xaaa0, 0xaab9, 0xaad1, 0xaae9, 0xab01, 0xab19, 0xab31, 0xab4a,
0xab63, 0xab7c, 0xab95, 0xabae, 0xabc7, 0xabdf, 0xabf6, 0xac0e,
0xac26, 0xac3e, 0xac56, 0xac6e, 0xac86, 0xac9e, 0xacb6, 0xacce,
0xace6, 0xacfe, 0xad16, 0xad2e, 0xad46, 0xad5f, 0xad78, 0xad91,
0xadaa, 0xadc3, 0xaddc, 0xadf5, 0xae0e, 0xae27, 0xae40, 0xae59,
// Entry 3B00 - 3B3F
0xae72, 0xae8b, 0xaea3, 0xaebb, 0xaed3, 0xaeeb, 0xaf03, 0xaf1b,
0xaf33, 0xaf4a, 0xaf61, 0xaf78, 0xaf8f, 0xafa5, 0xafbb, 0xafd3,
0xafea, 0xb002, 0xb01a, 0xb032, 0xb049, 0xb061, 0xb078, 0xb08e,
0xb0a3, 0xb0bb, 0xb0d4, 0xb0eb, 0xb103, 0xb11a, 0xb130, 0xb147,
0xb15e, 0xb176, 0xb18e, 0xb1a6, 0xb1c4, 0xb1e2, 0xb200, 0xb21d,
0xb23a, 0xb258, 0xb277, 0xb293, 0xb2af, 0xb2cb, 0xb2e7, 0xb304,
0xb322, 0xb33e, 0xb35d, 0xb379, 0xb38e, 0xb3a3, 0xb3b9, 0xb3d0,
0xb3e6, 0xb3fc, 0xb414, 0xb42b, 0xb442, 0xb458, 0xb470, 0xb488,
// Entry 3B40 - 3B7F
0xb49f, 0xb4b5, 0xb4cb, 0xb4e0, 0xb4f6, 0xb50c, 0xb522, 0xb538,
0xb54e, 0xb563, 0xb578, 0xb58e, 0xb5a3, 0xb5b8, 0xb5cf, 0xb5e5,
0xb5fb, 0xb610, 0xb626, 0xb63b, 0xb650, 0xb664, 0xb67c, 0xb694,
0xb6b0, 0xb6ce, 0xb6ea, 0xb70c, 0xb729, 0xb745, 0xb768, 0xb785,
0xb7a4, 0xb7c3, 0xb7e5, 0xb808, 0xb82b, 0xb84d, 0xb870, 0xb894,
0xb8b3, 0xb8db, 0xb8f9, 0xb915, 0xb936, 0xb951, 0xb972, 0xb98e,
0xb9ab, 0xb9cf, 0xb9eb, 0xba06, 0xba28, 0xba44, 0xba62, 0xba7d,
0xbaa0, 0xbac1, 0xbae2, 0xbaff, 0xbb1a, 0xbb37, 0xbb54, 0xbb6f,
// Entry 3B80 - 3BBF
0xbb8d, 0xbbb3, 0xbbd2, 0xbbf1, 0xbc0d, 0xbc2e, 0xbc49, 0xbc66,
0xbc86, 0xbca6, 0xbcc6, 0xbce6, 0xbd06, 0xbd26, 0xbd46, 0xbd66,
0xbd86, 0xbda6, 0xbdc6, 0xbde6, 0xbe06, 0xbe26, 0xbe46, 0xbe66,
0xbe86, 0xbea6, 0xbec6, 0xbee6, 0xbf06, 0xbf26, 0xbf46, 0xbf66,
0xbf86, 0xbfa6, 0xbfc6, 0xbfe6, 0xc006, 0xc026, 0xc046, 0xc066,
0xc086, 0xc0a6, 0xc0c6, 0xc0e6, 0xc106, 0xc126, 0xc146, 0xc166,
0xc186, 0xc1a6, 0xc1c6, 0xc1e6, 0xc206, 0xc226, 0xc246, 0xc266,
0xc286, 0xc2a6, 0xc2c6, 0xc2e6, 0xc306, 0xc326, 0xc346, 0xc366,
// Entry 3BC0 - 3BFF
0xc386, 0xc3a6, 0xc3c6, 0xc3e6, 0xc406, 0xc426, 0xc446, 0xc466,
0xc486, 0xc4a6, 0xc4c6, 0xc4e6, 0xc506, 0xc526, 0xc546, 0xc566,
0xc586, 0xc5a6, 0xc5c6, 0xc5e6, 0xc606, 0xc626, 0xc646, 0xc666,
0xc686, 0xc6a6, 0xc6c6, 0xc6e6, 0xc706, 0xc726, 0xc746, 0xc766,
0xc786, 0xc7a6, 0xc7c6, 0xc7e6, 0xc806, 0xc826, 0xc846, 0xc866,
0xc886, 0xc8a6, 0xc8c6, 0xc8e6, 0xc906, 0xc926, 0xc946, 0xc966,
0xc986, 0xc9a6, 0xc9c6, 0xc9e6, 0xca06, 0xca26, 0xca46, 0xca66,
0xca86, 0xcaa6, 0xcac6, 0xcae6, 0xcb06, 0xcb26, 0xcb46, 0xcb66,
// Entry 3C00 - 3C3F
0xcb86, 0xcba6, 0xcbc6, 0xcbe6, 0xcc06, 0xcc26, 0xcc46, 0xcc66,
0xcc86, 0xcca6, 0xccc6, 0xcce6, 0xcd06, 0xcd26, 0xcd46, 0xcd66,
0xcd86, 0xcda6, 0xcdc6, 0xcde6, 0xce06, 0xce26, 0xce46, 0xce66,
0xce86, 0xcea6, 0xcec6, 0xcee6, 0xcf06, 0xcf26, 0xcf46, 0xcf66,
0xcf86, 0xcfa6, 0xcfc6, 0xcfe6, 0xd006, 0xd026, 0xd046, 0xd066,
0xd086, 0xd0a6, 0xd0c6, 0xd0e6, 0xd106, 0xd126, 0xd146, 0xd166,
0xd186, 0xd1a6, 0xd1c6, 0xd1e6, 0xd206, 0xd226, 0xd246, 0xd266,
0xd286, 0xd2a6, 0xd2c6, 0xd2e6, 0xd306, 0xd326, 0xd346, 0xd366,
// Entry 3C40 - 3C7F
0xd386, 0xd3a6, 0xd3c6, 0xd3e6, 0xd406, 0xd426, 0xd446, 0xd466,
0xd486, 0xd4a6, 0xd4c6, 0xd4e6, 0xd506, 0xd526, 0xd546, 0xd566,
0xd586, 0xd5a6, 0xd5c6, 0xd5e6, 0xd606, 0xd626, 0xd646, 0xd666,
0xd686, 0xd6a6, 0xd6c6, 0xd6e6, 0xd706, 0xd726, 0xd746, 0xd766,
0xd786, 0xd7a6, 0xd7c6, 0xd7e6, 0xd806, 0xd826, 0xd846, 0xd866,
0xd886, 0xd8a6, 0xd8c6, 0xd8e6, 0xd906, 0xd926, 0xd946, 0xd966,
0xd986, 0xd9a6, 0xd9c6, 0xd9e6, 0xda06, 0xda26, 0xda46, 0xda66,
0xda86, 0xdaa6, 0xdac6, 0xdae6, 0xdb06, 0xdb26, 0xdb46, 0xdb66,
// Entry 3C80 - 3CBF
0xdb86, 0xdba6, 0xdbc6, 0xdbe6, 0xdc06, 0xdc26, 0xdc46, 0xdc66,
0xdc86, 0xdca6, 0xdcc6, 0xdce6, 0xdd06, 0xdd26, 0xdd46, 0xdd66,
0xdd86, 0xdda6, 0xddc6, 0xdde6, 0xde06, 0xde26, 0xde46, 0xde66,
0xde86, 0xdea6, 0xdec6, 0xdee6, 0xdf06, 0xdf26, 0xdf46, 0xdf66,
0xdf86, 0xdfa6, 0xdfc6, 0xdfe6, 0xe006, 0xe026, 0xe046, 0xe066,
0xe086, 0xe0a6, 0xe0c6, 0xe0e6, 0xe106, 0xe126, 0xe146, 0xe166,
0xe186, 0xe1a6, 0xe1c6, 0xe1e6, 0xe206, 0xe226, 0xe246, 0xe266,
0xe286, 0xe2a6, 0xe2c6, 0xe2e6, 0xe306, 0xe326, 0xe346, 0xe366,
// Entry 3CC0 - 3CFF
0xe386, 0xe3a6, 0xe3c6, 0xe3e6, 0xe406, 0xe426, 0xe446, 0xe466,
0xe486, 0xe4a6, 0xe4c6, 0xe4e6, 0xe506, 0xe526, 0xe546, 0xe566,
0xe586, 0xe5a6, 0xe5c6, 0xe5e6, 0xe606, 0xe626, 0xe646, 0xe666,
0xe686, 0xe6a6, 0xe6c6, 0xe6e6, 0xe706, 0xe726, 0xe746, 0xe766,
0xe786, 0xe7a6, 0xe7c6, 0xe7e6, 0xe806, 0xe826, 0xe846, 0xe866,
0xe886, 0xe8a6, 0xe8c6, 0xe8e6, 0xe906, 0xe926, 0xe946, 0xe966,
0xe986, 0xe9a6, 0xe9c6, 0xe9e6, 0xea06, 0xea26, 0xea46, 0xea66,
0xea86, 0xeaa6, 0xeac6, 0xeae6, 0xeb06, 0xeb26, 0xeb46, 0xeb66,
// Entry 3D00 - 3D3F
0xeb86, 0xeba6, 0xebc6, 0xebe6, 0xec06, 0xec26, 0xec46, 0xec66,
0xec86, 0xeca6, 0xecc6, 0xece6, 0xed06, 0xed26, 0xed46, 0xed66,
0xed86, 0xeda6, 0xedc6, 0xede6, 0xee06, 0xee26, 0xee46, 0xee66,
0xee86, 0xeea6, 0xeec6, 0xeee6, 0xef06, 0xef26, 0xef46, 0xef66,
0xef86, 0xefa6, 0xefc6, 0xefe6, 0xf006, 0xf026, 0xf046, 0xf066,
0xf086, 0xf0a6, 0xf0c6, 0xf0e6, 0xf106, 0xf126, 0xf146, 0xf166,
0xf186, 0xf1a6, 0xf1c6, 0xf1e6, 0xf206, 0xf226, 0xf246, 0xf266,
0xf286, 0xf2a6, 0xf2c6, 0xf2e6, 0xf306, 0xf326, 0xf346, 0xf366,
// Entry 3D40 - 3D7F
0xf386, 0xf3a6, 0xf3c6, 0xf3e6, 0xf406, 0xf426, 0xf446, 0xf466,
0xf486, 0xf4a6, 0xf4c6, 0xf4e6, 0xf506, 0xf526, 0xf546, 0xf566,
0xf586, 0xf5a6, 0xf5c6, 0xf5e6, 0xf606, 0xf626, 0xf646, 0xf666,
0xf686, 0xf6a6, 0xf6c6, 0xf6e6, 0xf706, 0xf726, 0xf746, 0xf766,
0xf786, 0xf79d, 0xf7b4, 0xf7cb, 0xf7e3, 0xf7fb, 0xf818, 0xf82f,
0xf84e, 0xf86d, 0xf88c, 0xf8ab, 0xf8ca, 0xf8e6, 0xf907, 0xf92c,
0xf94a, 0xf961, 0xf979, 0xf98e, 0xf9a4, 0xf9bc, 0xf9d8, 0xf9ef,
0xfa05, 0xfa28, 0xfa48, 0xfa67, 0xfa92, 0xfabc, 0xfad9, 0xfaf7,
// Entry 3D80 - 3DBF
0xfb14, 0xfb31, 0xfb50, 0xfb6f, 0xfb8a, 0xfba7, 0xfbc6, 0xfbe3,
0xfc00, 0xfc23, 0xfc40, 0xfc5f, 0xfc7c, 0xfc99, 0xfcb9, 0xfcdb,
0xfcf7, 0xfd16, 0xfd33, 0xfd51, 0xfd6f, 0xfd8c, 0xfda8, 0xfdc3,
0xfdde, 0xfdf8, 0xfe12, 0xfe38, 0xfe5b, 0xfe7b, 0xfe98, 0xfeb7,
0xfed5, 0xfef4, 0xff10, 0xff2e, 0xff4b, 0xff6c, 0xff8a, 0xffaa,
0xffc9, 0xffeb, 0x000a, 0x002b, 0x004b, 0x006c, 0x008a, 0x00aa,
0x00c9, 0x00e9, 0x0106, 0x0125, 0x0143, 0x0162, 0x017e, 0x019c,
0x01b9, 0x01da, 0x01f8, 0x0218, 0x0237, 0x0257, 0x0274, 0x0293,
// Entry 3DC0 - 3DFF
0x02b1, 0x02d1, 0x02ee, 0x030d, 0x032b, 0x034c, 0x036a, 0x038a,
0x03a9, 0x03cc, 0x03ec, 0x040e, 0x042f, 0x0451, 0x0470, 0x0491,
0x04af, 0x04ce, 0x04ea, 0x050a, 0x0527, 0x0546, 0x0562, 0x0582,
0x059f, 0x05c0, 0x05de, 0x05fe, 0x061d, 0x063c, 0x0658, 0x0676,
0x0693, 0x06b3, 0x06d0, 0x06ef, 0x070d, 0x072e, 0x074c, 0x076c,
0x078b, 0x07b2, 0x07d6, 0x07f7, 0x0815, 0x0835, 0x0854, 0x0882,
0x08ad, 0x08d1, 0x08f2, 0x0915, 0x0937, 0x0962, 0x098a, 0x09b4,
0x09dd, 0x0a03, 0x0a26, 0x0a5d, 0x0a91, 0x0aa8, 0x0abf, 0x0adb,
// Entry 3E00 - 3E3F
0x0af7, 0x0b15, 0x0b33, 0x0b64, 0x0b95, 0x0bb2, 0x0bcf, 0x0bf6,
0x0c1d, 0x0c44, 0x0c56, 0x0c73, 0x0c90, 0x0ca9, 0x0cc6, 0x0ce9,
0x0d16, 0x0d3d, 0x0d66, 0x0d8f, 0x0db1, 0x0ddc, 0x0e06, 0x0e25,
0x0e4d, 0x0e76, 0x0ea1, 0x0ed5, 0x0f07, 0x0f27, 0x0f45, 0x0f60,
0x0f7d, 0x0f99, 0x0fb6, 0x0fd0, 0x0fee, 0x1009, 0x1027, 0x1042,
0x1070, 0x108e, 0x10a9, 0x10cf, 0x10f2, 0x1118, 0x113b, 0x1158,
0x1172, 0x118e, 0x11a9, 0x11e6, 0x1222, 0x125e, 0x1297, 0x12d1,
0x1308, 0x1343, 0x137b, 0x13b4, 0x13ea, 0x1424, 0x145b, 0x1495,
// Entry 3E40 - 3E7F
0x14cc, 0x1505, 0x153b, 0x1573, 0x15c6, 0x1616, 0x1668, 0x168d,
0x16af, 0x16d3, 0x16f6, 0x1732, 0x176d, 0x17a9, 0x17ed, 0x1828,
0x1853, 0x187d, 0x18a8, 0x18d3, 0x1906, 0x1930, 0x195b, 0x1985,
0x19b0, 0x19db, 0x1a0e, 0x1a38, 0x1a64, 0x1a90, 0x1ac4, 0x1aef,
0x1b1a, 0x1b46, 0x1b71, 0x1b9c, 0x1bc8, 0x1bf3, 0x1c1f, 0x1c4b,
0x1c76, 0x1ca2, 0x1cce, 0x1cf8, 0x1d23, 0x1d4e, 0x1d78, 0x1da3,
0x1dce, 0x1df8, 0x1e23, 0x1e4e, 0x1e79, 0x1ea4, 0x1ed1, 0x1efe,
0x1f29, 0x1f53, 0x1f7e, 0x1fa9, 0x1fdc, 0x2006, 0x2030, 0x205b,
// Entry 3E80 - 3EBF
0x208e, 0x20b8, 0x20e3, 0x210e, 0x2138, 0x2163, 0x218d, 0x21b8,
0x21eb, 0x2215, 0x2240, 0x226a, 0x2295, 0x22c0, 0x22f3, 0x231d,
0x2349, 0x2374, 0x23a0, 0x23cc, 0x2400, 0x242b, 0x2457, 0x2482,
0x24ae, 0x24da, 0x250e, 0x2539, 0x2564, 0x258f, 0x25c2, 0x25ec,
0x2617, 0x2641, 0x266c, 0x2697, 0x26ca, 0x26f4, 0x272c, 0x2763,
0x27a3, 0x27d5, 0x2807, 0x2836, 0x2865, 0x2894, 0x28ce, 0x2906,
0x293f, 0x2978, 0x29b1, 0x29f2, 0x2a2a, 0x2a51, 0x2a79, 0x2aa1,
0x2ac9, 0x2af9, 0x2b20, 0x2b47, 0x2b6f, 0x2b97, 0x2bbf, 0x2bef,
// Entry 3EC0 - 3EFF
0x2c16, 0x2c3e, 0x2c67, 0x2c90, 0x2cb9, 0x2cea, 0x2d12, 0x2d42,
0x2d69, 0x2d99, 0x2dc0, 0x2de8, 0x2e0f, 0x2e37, 0x2e67, 0x2e8e,
0x2eb6, 0x2ee6, 0x2f0d, 0x2f36, 0x2f5f, 0x2f87, 0x2fb0, 0x2fd9,
0x3002, 0x3033, 0x305b, 0x3098, 0x30bf, 0x30e7, 0x310f, 0x3137,
0x3167, 0x318e, 0x31c9, 0x3203, 0x323e, 0x3279, 0x32b3, 0x32dd,
0x3306, 0x3330, 0x335a, 0x3383, 0x33ad, 0x33d6, 0x3400, 0x342a,
0x3453, 0x347e, 0x34a8, 0x34d3, 0x34fd, 0x3527, 0x3552, 0x357d,
0x35a8, 0x35d2, 0x35fd, 0x3628, 0x3651, 0x367b, 0x36a5, 0x36cf,
// Entry 3F00 - 3F3F
0x36f8, 0x3722, 0x374c, 0x3775, 0x379f, 0x37c9, 0x37f3, 0x381f,
0x384b, 0x3875, 0x389e, 0x38c8, 0x38f2, 0x391b, 0x3945, 0x396f,
0x3998, 0x39c2, 0x39eb, 0x3a15, 0x3a3f, 0x3a68, 0x3a92, 0x3abc,
0x3ae5, 0x3b10, 0x3b3a, 0x3b65, 0x3b90, 0x3bbb, 0x3be5, 0x3c10,
0x3c3b, 0x3c65, 0x3c8f, 0x3cb9, 0x3cef, 0x3d19, 0x3d42, 0x3d6c,
0x3d96, 0x3dbf, 0x3df9, 0x3e32, 0x3e5b, 0x3e83, 0x3eac, 0x3ed4,
0x3efe, 0x3f27, 0x3f51, 0x3f7a, 0x3fa5, 0x3fcf, 0x3ff7, 0x4020,
0x4049, 0x4073, 0x409c, 0x40c5, 0x40ed, 0x411a, 0x4147, 0x4174,
// Entry 3F40 - 3F7F
0x41a7, 0x41d1, 0x4204, 0x422e, 0x4263, 0x428f, 0x42c3, 0x42ee,
0x4323, 0x434f, 0x4382, 0x43ac, 0x43e0, 0x440b, 0x443f, 0x446a,
0x449d, 0x44c7, 0x44fa, 0x4524, 0x4551, 0x457d, 0x45aa, 0x45d7,
0x4603, 0x462e, 0x4658, 0x4682, 0x46b2, 0x46d9, 0x4709, 0x4730,
0x4762, 0x478b, 0x47bc, 0x47e4, 0x4816, 0x483f, 0x486f, 0x4896,
0x48c7, 0x48ef, 0x4920, 0x4948, 0x4978, 0x499f, 0x49cf, 0x49f6,
0x4a20, 0x4a49, 0x4a73, 0x4a9d, 0x4ac6, 0x4aee, 0x4b15, 0x4b3c,
0x4b68, 0x4b93, 0x4bbf, 0x4beb, 0x4c15, 0x4c40, 0x4c6a, 0x4c94,
// Entry 3F80 - 3FBF
0x4cbd, 0x4ce7, 0x4d12, 0x4d3c, 0x4d67, 0x4d90, 0x4db9, 0x4de6,
0x4e16, 0x4e2d, 0x4e45, 0x4e64, 0x4e84, 0x4ea6, 0x4ec8, 0x4eec,
0x4f10, 0x4f3b, 0x4f5b, 0x4f7c, 0x4f9f, 0x4fcb, 0x4fe9, 0x501e,
0x503f, 0x5063, 0x5083, 0x50b7, 0x50e8, 0x511b, 0x514e, 0x5182,
0x51b6, 0x51e9, 0x521d, 0x524f, 0x5283, 0x52b4, 0x52ee, 0x5322,
0x5356, 0x5391, 0x53c3, 0x53f7, 0x542c, 0x545f, 0x5494, 0x54c4,
0x54f6, 0x5528, 0x555b, 0x5590, 0x55c3, 0x55f7, 0x562d, 0x5661,
0x5697, 0x56d0, 0x5702, 0x5736, 0x5767, 0x579a, 0x57ce, 0x57ff,
// Entry 3FC0 - 3FFF
0x5831, 0x5863, 0x5897, 0x58d1, 0x5905, 0x5938, 0x5974, 0x59a6,
0x59da, 0x5a0b, 0x5a3d, 0x5a6e, 0x5a9e, 0x5ad7, 0x5b0b, 0x5b3d,
0x5b6f, 0x5ba3, 0x5bd4, 0x5c07, 0x5c3b, 0x5c6f, 0x5ca0, 0x5cd4,
0x5d09, 0x5d3e, 0x5d73, 0x5d98, 0x5dbf, 0x5df4, 0x5e28, 0x5e5c,
0x5e90, 0x5eca, 0x5efd, 0x5f32, 0x5f6d, 0x5f9f, 0x5fda, 0x600c,
0x6040, 0x6071, 0x60a2, 0x60dc, 0x610d, 0x6147, 0x6178, 0x61b2,
0x61e4, 0x621e, 0x6259, 0x6294, 0x62c4, 0x62f6, 0x6326, 0x6357,
0x6388, 0x63b8, 0x63e9, 0x641a, 0x644c, 0x647d, 0x64ae, 0x64e1,
// Entry 4000 - 403F
0x6514, 0x6545, 0x6576, 0x65aa, 0x65dc, 0x6610, 0x6642, 0x6674,
0x66a6, 0x66d7, 0x6708, 0x673a, 0x676b, 0x679b, 0x67cf, 0x6803,
0x6837, 0x6869, 0x689b, 0x68c2, 0x68ea, 0x6914, 0x6940, 0x697b,
0x69b5, 0x69db, 0x69fc, 0x6a39, 0x6a75, 0x6a98, 0x6abb, 0x6ae1,
0x6b04, 0x6b28, 0x6b4c, 0x6b72, 0x6b95, 0x6bc0, 0x6bdf, 0x6be8,
0x6c15, 0x6c3a, 0x6c56, 0x6c6a, 0x6c7e, 0x6c92, 0x6ca6, 0x6cba,
0x6cce, 0x6ce2, 0x6cf6, 0x6d0a, 0x6d1f, 0x6d34, 0x6d49, 0x6d5e,
0x6d73, 0x6d88, 0x6d9d, 0x6dc1, 0x6df1, 0x6e25, 0x6e49, 0x6e71,
// Entry 4040 - 407F
0x6ea0, 0x6ecc, 0x6f08, 0x6f45, 0x6f77, 0x6f93, 0x6fb0, 0x6fd0,
0x6ff1, 0x700b, 0x7026, 0x7041, 0x7063, 0x7086, 0x70a5, 0x70c5,
0x70e5, 0x7106, 0x7127, 0x7149, 0x716c, 0x7199, 0x71bf, 0x71e5,
0x720c, 0x7238, 0x7267, 0x7297, 0x72c8, 0x72fa, 0x7334, 0x736f,
0x73ab, 0x73e8, 0x7420, 0x7459, 0x748a, 0x74bc, 0x74ee, 0x7521,
0x7559, 0x7592, 0x759c, 0x75ac, 0x75de, 0x7611, 0x7620, 0x7633,
0x7640, 0x7654, 0x7663, 0x7676, 0x7683, 0x768e, 0x76a5, 0x76b4,
0x76c3, 0x76ce, 0x76e1, 0x76f7, 0x7704, 0x771a, 0x7731, 0x7749,
// Entry 4080 - 40BF
0x7762, 0x7783, 0x77a5, 0x77b6, 0x77c5, 0x77d3, 0x77e2, 0x77f4,
0x7808, 0x781f, 0x7830, 0x7845, 0x7856, 0x7868, 0x787b, 0x7898,
0x78ba, 0x78d7, 0x78eb, 0x7908, 0x7922, 0x793a, 0x7954, 0x796c,
0x7986, 0x799e, 0x79b9, 0x79d2, 0x79ec, 0x7a04, 0x7a25, 0x7a56,
0x7a84, 0x7ab5, 0x7ae3, 0x7b13, 0x7b40, 0x7b71, 0x7b9f, 0x7bcf,
0x7bfc, 0x7c2b, 0x7c59, 0x7c79, 0x7c96, 0x7cb5, 0x7cd1, 0x7cef,
0x7d0c, 0x7d33, 0x7d57, 0x7d76, 0x7d92, 0x7db0, 0x7dcd, 0x7ded,
0x7e0a, 0x7e29, 0x7e47, 0x7e67, 0x7e84, 0x7ea3, 0x7ec1, 0x7ee0,
// Entry 40C0 - 40FF
0x7efc, 0x7f1a, 0x7f37, 0x7f57, 0x7f74, 0x7f93, 0x7fb1, 0x7fd0,
0x7fec, 0x800c, 0x8029, 0x8048, 0x8064, 0x8084, 0x80a1, 0x80c1,
0x80de, 0x80fd, 0x811b, 0x813c, 0x815a, 0x817a, 0x8199, 0x81b8,
0x81d4, 0x81f2, 0x820f, 0x822e, 0x824a, 0x8268, 0x8285, 0x82a4,
0x82c0, 0x82de, 0x82fb, 0x831a, 0x8336, 0x8354, 0x8371, 0x8390,
0x83ac, 0x83ca, 0x83e7, 0x8408, 0x8426, 0x8446, 0x8465, 0x8484,
0x84a0, 0x84be, 0x84db, 0x84fa, 0x8516, 0x8534, 0x8551, 0x8570,
0x858c, 0x85aa, 0x85c7, 0x85e6, 0x8602, 0x8620, 0x863d, 0x865d,
// Entry 4100 - 413F
0x867a, 0x8699, 0x86b7, 0x86d7, 0x86f4, 0x8713, 0x8731, 0x8750,
0x876c, 0x878a, 0x87a7, 0x87c6, 0x87e2, 0x880a, 0x882f, 0x884e,
0x886a, 0x8888, 0x88a5, 0x88e1, 0x891a, 0x8956, 0x898f, 0x89cb,
0x8a04, 0x8a2f, 0x8a57, 0x8a70, 0x8a8a, 0x8aa2, 0x8ab7, 0x8acc,
0x8ae2, 0x8af5, 0x8b09, 0x8b23, 0x8b3e, 0x8b50, 0x8b63, 0x8b72,
0x8b88, 0x8b9b, 0x8bac, 0x8bc0, 0x8bd3, 0x8be6, 0x8bfb, 0x8c0f,
0x8c23, 0x8c36, 0x8c4b, 0x8c60, 0x8c74, 0x8c83, 0x8c96, 0x8cae,
0x8cc3, 0x8cde, 0x8cf5, 0x8d0c, 0x8d2c, 0x8d4c, 0x8d6c, 0x8d8c,
// Entry 4140 - 417F
0x8dac, 0x8dcc, 0x8dec, 0x8e0c, 0x8e2c, 0x8e4c, 0x8e6c, 0x8e8c,
0x8eac, 0x8ecc, 0x8eec, 0x8f0c, 0x8f2c, 0x8f4c, 0x8f6c, 0x8f8c,
0x8fac, 0x8fcc, 0x8fec, 0x900c, 0x902c, 0x904c, 0x9069, 0x9082,
0x90a0, 0x90bb, 0x90cd, 0x90e3, 0x9101, 0x911f, 0x913d, 0x915b,
0x9179, 0x9197, 0x91b5, 0x91d3, 0x91f1, 0x920f, 0x922d, 0x924b,
0x9269, 0x9287, 0x92a5, 0x92c3, 0x92e1, 0x92ff, 0x931d, 0x933b,
0x9359, 0x9377, 0x9395, 0x93b3, 0x93d1, 0x93ef, 0x940b, 0x9422,
0x943f, 0x944e, 0x946e, 0x948f, 0x94ae, 0x94cb, 0x94e9, 0x9504,
// Entry 4180 - 41BF
0x9521, 0x953d, 0x955e, 0x957f, 0x95a0, 0x95c1, 0x95e2, 0x9604,
0x9626, 0x9648, 0x966a, 0x969a, 0x96b5, 0x96d0, 0x96eb, 0x9706,
0x9721, 0x973d, 0x9759, 0x9775, 0x9791, 0x97ad, 0x97c9, 0x97e5,
0x9801, 0x981d, 0x9839, 0x9855, 0x9871, 0x988d, 0x98a9, 0x98c5,
0x98e1, 0x98fd, 0x9919, 0x9935, 0x9951, 0x996d, 0x9989, 0x99a5,
0x99c1, 0x99dd, 0x99f9, 0x9a15, 0x9a31, 0x9a4d, 0x9a69, 0x9a85,
0x9aa1, 0x9abd, 0x9ad9, 0x9af5, 0x9b11, 0x9b2d, 0x9b49, 0x9b65,
0x9b80, 0x9ba4, 0x9bcd, 0x9be4, 0x9c02, 0x9c25, 0x9c48, 0x9c65,
// Entry 41C0 - 41FF
0x9c88, 0x9cab, 0x9cc9, 0x9cec, 0x9d09, 0x9d2d, 0x9d50, 0x9d73,
0x9d95, 0x9dba, 0x9ddf, 0x9e02, 0x9e1f, 0x9e3c, 0x9e5e, 0x9e80,
0x9e9c, 0x9ebd, 0x9eda, 0x9ef7, 0x9f19, 0x9f38, 0x9f57, 0x9f76,
0x9f95, 0x9fb2, 0x9fcb, 0x9fe5, 0x9fff, 0xa01a, 0xa034, 0xa04d,
0xa068, 0xa082, 0xa09b, 0xa0b5, 0xa0d0, 0xa0ea, 0xa104, 0xa11d,
0xa138, 0xa152, 0xa16c, 0xa186, 0xa1a0, 0xa1ba, 0xa1d3, 0xa1e6,
0xa1fa, 0xa20c, 0xa21c, 0xa230, 0xa242, 0xa254, 0xa272, 0xa28b,
0xa2a2, 0xa2bc, 0xa2d5, 0xa2eb, 0xa301, 0xa31e, 0xa33e, 0xa35f,
// Entry 4200 - 423F
0xa37b, 0xa390, 0xa3a8, 0xa3c0, 0xa3d8, 0xa3f0, 0xa408, 0xa421,
0xa43a, 0xa453, 0xa46c, 0xa485, 0xa49e, 0xa4b7, 0xa4d0, 0xa4e9,
0xa502, 0xa51b, 0xa534, 0xa54d, 0xa566, 0xa57f, 0xa598, 0xa5b1,
0xa5ca, 0xa5e3, 0xa5fc, 0xa615, 0xa62e, 0xa647, 0xa660, 0xa679,
0xa692, 0xa6ab, 0xa6c4, 0xa6dd, 0xa6f6, 0xa70f, 0xa728, 0xa741,
0xa75a, 0xa773, 0xa78c, 0xa7a5, 0xa7be, 0xa7d7, 0xa7f0, 0xa809,
0xa822, 0xa83b, 0xa854, 0xa86d, 0xa886, 0xa89f, 0xa8b8, 0xa8d1,
0xa8ea, 0xa903, 0xa91c, 0xa935, 0xa94e, 0xa967, 0xa980, 0xa999,
// Entry 4240 - 427F
0xa9b2, 0xa9cc, 0xa9e6, 0xaa00, 0xaa1a, 0xaa34, 0xaa4e, 0xaa68,
0xaa82, 0xaa9c, 0xaab6, 0xaad0, 0xaae4, 0xaaf8, 0xab0c, 0xab20,
0xab34, 0xab48, 0xab5c, 0xab70, 0xab84, 0xab98, 0xabac, 0xabc0,
0xabd4, 0xabe8, 0xac02, 0xac1e, 0xac39, 0xac55, 0xac71, 0xac91,
0xacac, 0xacc7, 0xace7, 0xad06, 0xad21, 0xad3d, 0xad58, 0xad74,
0xad90, 0xadad, 0xadc9, 0xade5, 0xae03, 0xae1e, 0xae3b, 0xae55,
0xae70, 0xae86, 0xaea2, 0xaebd, 0xaeda, 0xaef5, 0xaf0b, 0xaf26,
0xaf3c, 0xaf52, 0xaf6d, 0xaf83, 0xaf99, 0xafaf, 0xafcb, 0xafe1,
// Entry 4280 - 42BF
0xaff7, 0xb013, 0xb029, 0xb03f, 0xb05d, 0xb07a, 0xb090, 0xb0a6,
0xb0bc, 0xb0d2, 0xb0e8, 0xb0fe, 0xb114, 0xb12a, 0xb140, 0xb15c,
0xb172, 0xb18d, 0xb1a3, 0xb1b9, 0xb1cf, 0xb1e5, 0xb1fb, 0xb211,
0xb227, 0xb23d, 0xb253, 0xb269, 0xb27f, 0xb29c, 0xb2bc, 0xb2da,
0xb2f6, 0xb312, 0xb328, 0xb344, 0xb35a, 0xb370, 0xb396, 0xb3b4,
0xb3d8, 0xb3f4, 0xb40a, 0xb420, 0xb43c, 0xb452, 0xb468, 0xb47e,
0xb494, 0xb4aa, 0xb4c5, 0xb4db, 0xb4f1, 0xb507, 0xb51d, 0xb533,
0xb550, 0xb56d, 0xb58a, 0xb5a7, 0xb5c4, 0xb5e1, 0xb5fe, 0xb61b,
// Entry 42C0 - 42FF
0xb638, 0xb655, 0xb672, 0xb68f, 0xb6ac, 0xb6c9, 0xb6e6, 0xb703,
0xb720, 0xb73d, 0xb75a, 0xb777, 0xb794, 0xb7b1, 0xb7ce, 0xb7eb,
0xb808, 0xb825, 0xb842, 0xb85f, 0xb87c, 0xb896, 0xb8af, 0xb8c0,
0xb8d1, 0xb8e2, 0xb8f5, 0xb907, 0xb919, 0xb92a, 0xb93d, 0xb950,
0xb962, 0xb973, 0xb987, 0xb99b, 0xb9ae, 0xb9c1, 0xb9d4, 0xb9e9,
0xb9fd, 0xba11, 0xba2a, 0xba43, 0xba5e, 0xba78, 0xba92, 0xbaab,
0xbac6, 0xbae1, 0xbafb, 0xbb15, 0xbb2f, 0xbb4b, 0xbb66, 0xbb81,
0xbb9b, 0xbbb7, 0xbbd3, 0xbbee, 0xbc08, 0xbc25, 0xbc42, 0xbc5e,
// Entry 4300 - 433F
0xbc7a, 0xbc96, 0xbcb4, 0xbcd1, 0xbcee, 0xbd05, 0xbd20, 0xbd3c,
0xbd57, 0xbd73, 0xbd93, 0xbdb6, 0xbdd3, 0xbdef, 0xbe11, 0xbe30,
0xbe52, 0xbe6d, 0xbe89, 0xbeac, 0xbed0, 0xbef5, 0xbf18, 0xbf3a,
0xbf5e, 0xbf88, 0xbfb3, 0xbfde, 0xc00a, 0xc02d, 0xc04f, 0xc073,
0xc09d, 0xc0c8, 0xc0f3, 0xc11e, 0xc14b, 0xc16a, 0xc18f, 0xc1ac,
0xc1cb, 0xc1ea, 0xc207, 0xc22d, 0xc255, 0xc275, 0xc294, 0xc2c2,
0xc2e1, 0xc2ff, 0xc31c, 0xc33c, 0xc35d, 0xc38d, 0xc3ae, 0xc3cd,
0xc3f2, 0xc419, 0xc441, 0xc469, 0xc48f, 0xc4b6, 0xc4da, 0xc500,
// Entry 4340 - 437F
0xc527, 0xc549, 0xc56d, 0xc580, 0xc5a2, 0xc5b7, 0xc5d0, 0xc5df,
0xc5f0, 0xc602, 0xc611, 0xc625, 0xc63b, 0xc650, 0xc665, 0xc678,
0xc68f, 0xc69f, 0xc6b0, 0xc6c1, 0xc6d2, 0xc6e3, 0xc6f4, 0xc70c,
0xc71b, 0xc731, 0xc744, 0xc758, 0xc764, 0xc776, 0xc786, 0xc799,
0xc7ab, 0xc7c5, 0xc7d7, 0xc7ea, 0xc7fe, 0xc813, 0xc827, 0xc834,
0xc848, 0xc854, 0xc868, 0xc885, 0xc8a3, 0xc8c3, 0xc8dd, 0xc8f5,
0xc90d, 0xc926, 0xc941, 0xc959, 0xc971, 0xc987, 0xc9a0, 0xc9b7,
0xc9d2, 0xc9ec, 0xca02, 0xca18, 0xca34, 0xca56, 0xca6f, 0xca86,
// Entry 4380 - 43BF
0xca9e, 0xcab7, 0xcad1, 0xcae8, 0xcaff, 0xcb16, 0xcb32, 0xcb48,
0xcb5e, 0xcb76, 0xcb8d, 0xcba5, 0xcbbb, 0xcbd8, 0xcbef, 0xcc09,
0xcc23, 0xcc3a, 0xcc54, 0xcc6c, 0xcc85, 0xcca0, 0xccbc, 0xccd8,
0xcd03, 0xcd12, 0xcd21, 0xcd30, 0xcd40, 0xcd4f, 0xcd5e, 0xcd6d,
0xcd7c, 0xcd8b, 0xcd9b, 0xcdaa, 0xcdb9, 0xcdc8, 0xcdd7, 0xcde6,
0xcdf5, 0xce05, 0xce15, 0xce24, 0xce33, 0xce43, 0xce52, 0xce61,
0xce70, 0xce80, 0xce90, 0xcea0, 0xceaf, 0xcebe, 0xcecd, 0xcedd,
0xceec, 0xcefb, 0xcf0c, 0xcf1b, 0xcf2b, 0xcf3b, 0xcf4a, 0xcf59,
// Entry 43C0 - 43FF
0xcf68, 0xcf77, 0xcf87, 0xcf96, 0xcfa6, 0xcfb7, 0xcfc6, 0xcfd8,
0xcfe7, 0xcff7, 0xd006, 0xd015, 0xd026, 0xd035, 0xd045, 0xd054,
0xd063, 0xd075, 0xd084, 0xd094, 0xd0a4, 0xd0b4, 0xd0c3, 0xd0d3,
0xd0e3, 0xd0f4, 0xd104, 0xd114, 0xd126, 0xd136, 0xd148, 0xd158,
0xd168, 0xd179, 0xd18a, 0xd19b, 0xd1ac, 0xd1bc, 0xd1ce, 0xd1e9,
0xd1ff, 0xd215, 0xd22d, 0xd244, 0xd25b, 0xd271, 0xd289, 0xd2a1,
0xd2b8, 0xd2cf, 0xd2e9, 0xd303, 0xd31c, 0xd335, 0xd34e, 0xd369,
0xd383, 0xd39d, 0xd3bc, 0xd3db, 0xd3fc, 0xd41c, 0xd43c, 0xd45b,
// Entry 4400 - 443F
0xd47c, 0xd49d, 0xd4bd, 0xd4d0, 0xd4e4, 0xd4f8, 0xd50c, 0xd51f,
0xd533, 0xd547, 0xd55b, 0xd570, 0xd583, 0xd597, 0xd5ab, 0xd5bf,
0xd5d3, 0xd5e8, 0xd5fb, 0xd60f, 0xd624, 0xd638, 0xd64c, 0xd660,
0xd674, 0xd687, 0xd69c, 0xd6b1, 0xd6c6, 0xd6da, 0xd6ef, 0xd704,
0xd718, 0xd72c, 0xd741, 0xd757, 0xd76e, 0xd784, 0xd79c, 0xd7b0,
0xd7ce, 0xd7ec, 0xd7fe, 0xd813, 0xd825, 0xd837, 0xd84b, 0xd861,
0xd873, 0xd885, 0xd899, 0xd8aa, 0xd8bd, 0xd8d0, 0xd8e3, 0xd8f7,
0xd908, 0xd91a, 0xd930, 0xd944, 0xd957, 0xd96a, 0xd97d, 0xd990,
// Entry 4440 - 447F
0xd9a3, 0xd9b6, 0xd9c9, 0xd9dc, 0xd9f6, 0xda0a, 0xda1f, 0xda34,
0xda49, 0xda5c, 0xda72, 0xda89, 0xda9f, 0xdab6, 0xdac9, 0xdadf,
0xdaf4, 0xdb0b, 0xdb22, 0xdb38, 0xdb4e, 0xdb63, 0xdb78, 0xdb8d,
0xdba0, 0xdbb7, 0xdbce, 0xdbe7, 0xdbfc, 0xdc12, 0xdc25, 0xdc39,
0xdc4d, 0xdc61, 0xdc77, 0xdc8c, 0xdca1, 0xdcb7, 0xdccc, 0xdce0,
0xdcf4, 0xdd08, 0xdd1c, 0xdd3a, 0xdd59, 0xdd79, 0xdd9a, 0xddb9,
0xddcd, 0xdde1, 0xddf6, 0xde09, 0xde1e, 0xde30, 0xde42, 0xde56,
0xde6a, 0xde7d, 0xde90, 0xdea3, 0xdeb7, 0xdecc, 0xdedf, 0xdef3,
// Entry 4480 - 44BF
0xdf06, 0xdf18, 0xdf2d, 0xdf40, 0xdf52, 0xdf66, 0xdf7a, 0xdf8f,
0xdfa5, 0xdfba, 0xdfcc, 0xdfdd, 0xdfee, 0xe001, 0xe016, 0xe028,
0xe03a, 0xe04c, 0xe05f, 0xe072, 0xe085, 0xe098, 0xe0ab, 0xe0be,
0xe0d1, 0xe0e4, 0xe0f7, 0xe10a, 0xe11d, 0xe130, 0xe143, 0xe157,
0xe16a, 0xe17d, 0xe190, 0xe1a3, 0xe1b6, 0xe1c9, 0xe1dc, 0xe1ef,
0xe202, 0xe215, 0xe228, 0xe23b, 0xe24e, 0xe261, 0xe274, 0xe287,
0xe29b, 0xe2af, 0xe2c2, 0xe2dd, 0xe2fa, 0xe317, 0xe334, 0xe34e,
0xe36a, 0xe37f, 0xe397, 0xe3af, 0xe3c5, 0xe3db, 0xe3f1, 0xe40a,
// Entry 44C0 - 44FF
0xe424, 0xe441, 0xe45e, 0xe47b, 0xe499, 0xe4b6, 0xe4d4, 0xe4f2,
0xe510, 0xe52e, 0xe54d, 0xe56b, 0xe58a, 0xe5a3, 0xe5bc, 0xe5d5,
0xe5ef, 0xe607, 0xe621, 0xe63b, 0xe655, 0xe66f, 0xe68a, 0xe6a4,
0xe6be, 0xe6d8, 0xe6f1, 0xe70b, 0xe725, 0xe740, 0xe759, 0xe773,
0xe78d, 0xe7a8, 0xe7c1, 0xe7da, 0xe7f3, 0xe80c, 0xe826, 0xe83f,
0xe858, 0xe873, 0xe88e, 0xe8a9, 0xe8c5, 0xe8e0, 0xe8fc, 0xe918,
0xe934, 0xe950, 0xe96d, 0xe989, 0xe9a6, 0xe9bd, 0xe9d4, 0xe9eb,
0xea03, 0xea19, 0xea31, 0xea49, 0xea61, 0xea79, 0xea92, 0xeaaa,
// Entry 4500 - 453F
0xeac2, 0xeada, 0xeaf1, 0xeb09, 0xeb21, 0xeb3a, 0xeb51, 0xeb69,
0xeb81, 0xeb9a, 0xebb1, 0xebc8, 0xebdf, 0xebf6, 0xec0e, 0xec25,
0xec3c, 0xec4f, 0xec61, 0xec74, 0xec86, 0xec9a, 0xecab, 0xecbe,
0xecd3, 0xece5, 0xecf8, 0xed0a, 0xed1d, 0xed2f, 0xed41, 0xed54,
0xed66, 0xed7c, 0xed90, 0xeda2, 0xedb6, 0xedc9, 0xeddc, 0xeded,
0xedff, 0xee11, 0xee23, 0xee34, 0xee47, 0xee59, 0xee6a, 0xee7d,
0xee8f, 0xeea1, 0xeeb3, 0xeec5, 0xeed6, 0xeee8, 0xeefb, 0xef0d,
0xef1f, 0xef31, 0xef42, 0xef54, 0xef66, 0xef7a, 0xef8c, 0xef9e,
// Entry 4540 - 457F
0xefb0, 0xefc3, 0xefd4, 0xefe5, 0xeff6, 0xf007, 0xf019, 0xf02c,
0xf03d, 0xf04e, 0xf062, 0xf074, 0xf087, 0xf098, 0xf0a9, 0xf0bc,
0xf0cf, 0xf0e2, 0xf0f5, 0xf108, 0xf11a, 0xf12b, 0xf13c, 0xf14c,
0xf15c, 0xf16c, 0xf17c, 0xf18c, 0xf19d, 0xf1ae, 0xf1bf, 0xf1d1,
0xf1e2, 0xf1f3, 0xf206, 0xf218, 0xf22a, 0xf23b, 0xf24e, 0xf261,
0xf273, 0xf289, 0xf2a0, 0xf2b8, 0xf2cf, 0xf2e7, 0xf2ff, 0xf319,
0xf32f, 0xf347, 0xf35e, 0xf376, 0xf38c, 0xf3a3, 0xf3bc, 0xf3d4,
0xf3eb, 0xf402, 0xf419, 0xf42f, 0xf447, 0xf45e, 0xf477, 0xf48e,
// Entry 4580 - 45BF
0xf4a6, 0xf4bd, 0xf4d6, 0xf4ee, 0xf508, 0xf521, 0xf539, 0xf54f,
0xf566, 0xf57e, 0xf596, 0xf5ad, 0xf5c5, 0xf5d9, 0xf5ee, 0xf604,
0xf619, 0xf62f, 0xf645, 0xf65d, 0xf671, 0xf687, 0xf69c, 0xf6b2,
0xf6c6, 0xf6db, 0xf6f2, 0xf708, 0xf71d, 0xf732, 0xf747, 0xf75b,
0xf771, 0xf786, 0xf79d, 0xf7b2, 0xf7c8, 0xf7dd, 0xf7f4, 0xf80a,
0xf822, 0xf839, 0xf84f, 0xf863, 0xf878, 0xf88e, 0xf8a4, 0xf8b9,
0xf8cf, 0xf8df, 0xf8f0, 0xf901, 0xf913, 0xf924, 0xf936, 0xf948,
0xf959, 0xf969, 0xf97a, 0xf98b, 0xf99d, 0xf9ae, 0xf9be, 0xf9cf,
// Entry 45C0 - 45FF
0xf9e0, 0xf9f1, 0xfa03, 0xfa14, 0xfa25, 0xfa36, 0xfa48, 0xfa58,
0xfa69, 0xfa7a, 0xfa8b, 0xfa9d, 0xfaae, 0xfac0, 0xfad1, 0xfae3,
0xfaf3, 0xfb04, 0xfb15, 0xfb25, 0xfb36, 0xfb48, 0xfb5a, 0xfb6f,
0xfb81, 0xfb9e, 0xfbbb, 0xfbd8, 0xfbf5, 0xfc11, 0xfc2f, 0xfc4c,
0xfc6a, 0xfc87, 0xfca4, 0xfcc2, 0xfcdf, 0xfcfc, 0xfd19, 0xfd36,
0xfd54, 0xfd72, 0xfd90, 0xfdad, 0xfdcb, 0xfde8, 0xfe06, 0xfe24,
0xfe41, 0xfe5e, 0xfe7c, 0xfe99, 0xfeb7, 0xfed4, 0xfef1, 0xff0f,
0xff2e, 0xff4c, 0xff6a, 0xff86, 0xffa4, 0xffc1, 0xffdf, 0xfffd,
// Entry 4600 - 463F
0x001a, 0x0039, 0x0056, 0x0074, 0x0092, 0x00b0, 0x00ce, 0x00eb,
0x0109, 0x0127, 0x0145, 0x0163, 0x0180, 0x01a0, 0x01b9, 0x01d4,
0x01ee, 0x0208, 0x0223, 0x023d, 0x0258, 0x0272, 0x028b, 0x02a5,
0x02bf, 0x02d9, 0x02f4, 0x030d, 0x0328, 0x0342, 0x035c, 0x0376,
0x0391, 0x03ab, 0x03c5, 0x03e0, 0x03f9, 0x0413, 0x042d, 0x0447,
0x0461, 0x047c, 0x0496, 0x04b1, 0x04ca, 0x04e4, 0x04fe, 0x0517,
0x0531, 0x0548, 0x0561, 0x0579, 0x0591, 0x05aa, 0x05c2, 0x05db,
0x05f3, 0x060a, 0x0622, 0x063a, 0x0652, 0x066b, 0x0682, 0x069b,
// Entry 4640 - 467F
0x06b3, 0x06cb, 0x06e3, 0x06fc, 0x0714, 0x072c, 0x0745, 0x075c,
0x0774, 0x078c, 0x07a4, 0x07bc, 0x07d5, 0x07ed, 0x0806, 0x081d,
0x0835, 0x084d, 0x0864, 0x087c, 0x088b, 0x089b, 0x08ab, 0x08bc,
0x08cc, 0x08dd, 0x08ed, 0x08fe, 0x090f, 0x091f, 0x092e, 0x093e,
0x094e, 0x095f, 0x0970, 0x0982, 0x0992, 0x09a3, 0x09b2, 0x09c2,
0x09d2, 0x09e2, 0x09f3, 0x0a03, 0x0a13, 0x0a25, 0x0a34, 0x0a44,
0x0a54, 0x0a64, 0x0a75, 0x0a85, 0x0a96, 0x0aa8, 0x0ab8, 0x0ac9,
0x0ad8, 0x0ae8, 0x0af8, 0x0b09, 0x0b1a, 0x0b2c, 0x0b3b, 0x0b4b,
// Entry 4680 - 46BF
0x0b5b, 0x0b6c, 0x0b7d, 0x0b8e, 0x0ba0, 0x0bb1, 0x0bc2, 0x0bd2,
0x0be5, 0x0bf8, 0x0c0b, 0x0c1e, 0x0c31, 0x0c44, 0x0c57, 0x0c6a,
0x0c7d, 0x0c90, 0x0ca3, 0x0cb6, 0x0cc9, 0x0cdc, 0x0cef, 0x0d02,
0x0d16, 0x0d2a, 0x0d3d, 0x0d51, 0x0d65, 0x0d78, 0x0d8c, 0x0d9f,
0x0db2, 0x0dc5, 0x0dd8, 0x0deb, 0x0dfe, 0x0e11, 0x0e24, 0x0e37,
0x0e4a, 0x0e5d, 0x0e70, 0x0e83, 0x0e96, 0x0ea9, 0x0ebc, 0x0ecf,
0x0ee2, 0x0ef5, 0x0f08, 0x0f1b, 0x0f2e, 0x0f41, 0x0f54, 0x0f67,
0x0f7a, 0x0f8d, 0x0fa0, 0x0fb3, 0x0fc6, 0x0fd9, 0x0fec, 0x0fff,
// Entry 46C0 - 46FF
0x1012, 0x1025, 0x1038, 0x104b, 0x105e, 0x1071, 0x1084, 0x1097,
0x10aa, 0x10bd, 0x10d0, 0x10e3, 0x10f6, 0x1109, 0x111c, 0x1132,
0x1145, 0x1158, 0x116b, 0x117e, 0x1191, 0x11a5, 0x11b9, 0x11cc,
0x11df, 0x11f2, 0x1205, 0x1218, 0x122b, 0x123d, 0x124f, 0x1261,
0x1273, 0x1285, 0x1297, 0x12a9, 0x12bb, 0x12ce, 0x12e1, 0x12f4,
0x1306, 0x1318, 0x132a, 0x133d, 0x1350, 0x1363, 0x1375, 0x1387,
0x1399, 0x13ab, 0x13bd, 0x13cf, 0x13e1, 0x13f3, 0x1405, 0x1417,
0x1429, 0x143b, 0x144d, 0x145f, 0x1471, 0x1483, 0x1495, 0x14a7,
// Entry 4700 - 473F
0x14b9, 0x14cb, 0x14dd, 0x14ef, 0x1501, 0x1513, 0x1525, 0x1537,
0x1549, 0x155b, 0x156d, 0x157f, 0x1591, 0x15a3, 0x15b5, 0x15c7,
0x15d9, 0x15eb, 0x15fd, 0x160f, 0x1621, 0x1633, 0x1645, 0x1657,
0x1669, 0x167b, 0x168d, 0x169f, 0x16b1, 0x16c3, 0x16d5, 0x16e7,
0x16f9, 0x170b, 0x171d, 0x172f, 0x1741, 0x1753, 0x1765, 0x1777,
0x178d, 0x17a3, 0x17b9, 0x17cf, 0x17e5, 0x17fb, 0x1811, 0x1827,
0x183d, 0x1853, 0x1869, 0x187f, 0x1895, 0x18ab, 0x18c1, 0x18d7,
0x18ed, 0x1903, 0x1919, 0x192b, 0x193d, 0x194f, 0x1961, 0x1973,
// Entry 4740 - 477F
0x1985, 0x1997, 0x19a9, 0x19bb, 0x19cd, 0x19df, 0x19f1, 0x1a03,
0x1a15, 0x1a27, 0x1a39, 0x1a4b, 0x1a5d, 0x1a6f, 0x1a81, 0x1a93,
0x1aa5, 0x1ab7, 0x1ac9, 0x1adb, 0x1aed, 0x1aff, 0x1b11, 0x1b23,
0x1b35, 0x1b47, 0x1b59, 0x1b6b, 0x1b7d, 0x1b8f, 0x1ba1, 0x1bb3,
0x1bc5, 0x1bd7, 0x1be9, 0x1bfb, 0x1c0d, 0x1c1f, 0x1c31, 0x1c43,
0x1c55, 0x1c67, 0x1c79, 0x1c8b, 0x1c9d, 0x1caf, 0x1cc1, 0x1cd3,
0x1ce5, 0x1cf7, 0x1d09, 0x1d1b, 0x1d2d, 0x1d3f, 0x1d51, 0x1d63,
0x1d75, 0x1d87, 0x1d99, 0x1dab, 0x1dbd, 0x1dcf, 0x1de1, 0x1df3,
// Entry 4780 - 47BF
0x1e05, 0x1e17, 0x1e29, 0x1e3b, 0x1e4d, 0x1e5f, 0x1e71, 0x1e83,
0x1e95, 0x1ea7, 0x1eb9, 0x1ecb, 0x1edd, 0x1eef, 0x1f01, 0x1f13,
0x1f25, 0x1f37, 0x1f49, 0x1f5b, 0x1f6d, 0x1f7f, 0x1f91, 0x1fa3,
0x1fb5, 0x1fc7, 0x1fd9, 0x1feb, 0x1ffd, 0x200f, 0x2021, 0x2033,
0x2045, 0x2057, 0x2069, 0x207b, 0x208d, 0x209f, 0x20b1, 0x20c3,
0x20d5, 0x20e7, 0x20f9, 0x210b, 0x211d, 0x212f, 0x2141, 0x2153,
0x2165, 0x2177, 0x2189, 0x219b, 0x21ad, 0x21bf, 0x21d1, 0x21e3,
0x21f5, 0x2207, 0x2219, 0x222b, 0x223d, 0x224f, 0x2261, 0x2275,
// Entry 47C0 - 47FF
0x2289, 0x229d, 0x22b1, 0x22c5, 0x22d9, 0x22ed, 0x2301, 0x2315,
0x232c, 0x2343, 0x235a, 0x2371, 0x2385, 0x2399, 0x23ad, 0x23c5,
0x23db, 0x23f0, 0x2405, 0x241c, 0x2431, 0x2443, 0x2455, 0x2467,
0x2479, 0x248b, 0x249d, 0x24af, 0x24c1, 0x24e1, 0x250d, 0x253e,
0x2556, 0x2575, 0x2596, 0x25b6, 0x25ea, 0x2614, 0x2636, 0x2657,
0x2678, 0x26a2, 0x26c2, 0x26ee, 0x2710, 0x272f, 0x274e, 0x276f,
0x2798, 0x27bb, 0x27da, 0x27fe, 0x2832, 0x2852, 0x2872, 0x2893,
0x28bc, 0x28f0, 0x290a, 0x2938, 0x2956, 0x297e, 0x29a1, 0x29c1,
// Entry 4800 - 483F
0x29e3, 0x29fa, 0x2a26, 0x2a65, 0x2a86, 0x2aab, 0x2aca, 0x2af4,
0x2b14, 0x2b48, 0x2b6a, 0x2b95, 0x2bbc, 0x2bdb, 0x2c03, 0x2c34,
0x2c52, 0x2c6e, 0x2c8b, 0x2ca9, 0x2cdc, 0x2cfd, 0x2d0f, 0x2d21,
0x2d33, 0x2d45, 0x2d57, 0x2d6a, 0x2d7d, 0x2d90, 0x2da3, 0x2db6,
0x2dc9, 0x2ddc, 0x2def, 0x2e02, 0x2e15, 0x2e28, 0x2e3b, 0x2e4e,
0x2e61, 0x2e74, 0x2e87, 0x2e9a, 0x2ead, 0x2ec0, 0x2ed3, 0x2ee6,
0x2ef9, 0x2f0c, 0x2f1f, 0x2f32, 0x2f45, 0x2f58, 0x2f6b, 0x2f7e,
0x2f91, 0x2fa4, 0x2fb7, 0x2fca, 0x2fdd, 0x2ff0, 0x3003, 0x3016,
// Entry 4840 - 487F
0x3029, 0x303c, 0x304f, 0x3062, 0x3075, 0x3088, 0x309b, 0x30ae,
0x30c1, 0x30d4, 0x30e7, 0x30fa, 0x310d, 0x312a, 0x3146, 0x3163,
0x3181, 0x319b, 0x31b6, 0x31d3, 0x31ef, 0x320b, 0x3227, 0x3243,
0x3261, 0x327c, 0x3297, 0x32b5, 0x32d1, 0x32eb, 0x3308, 0x3324,
0x3340, 0x335c, 0x3377, 0x3394, 0x33af, 0x33ca, 0x33e7, 0x3402,
0x3420, 0x3443, 0x3467, 0x348b, 0x34a1, 0x34b6, 0x34cc, 0x34e3,
0x34f6, 0x350a, 0x3520, 0x3535, 0x354a, 0x355f, 0x3574, 0x358b,
0x359f, 0x35b9, 0x35cd, 0x35e4, 0x35f9, 0x360c, 0x3622, 0x3637,
// Entry 4880 - 48BF
0x364c, 0x3661, 0x3675, 0x3694, 0x36b4, 0x36c8, 0x36dc, 0x36f2,
0x3707, 0x371c, 0x3730, 0x3747, 0x3763, 0x3779, 0x3794, 0x37a9,
0x37bf, 0x37d6, 0x37ef, 0x3802, 0x3816, 0x382c, 0x3841, 0x3856,
0x3871, 0x3886, 0x38a1, 0x38b6, 0x38d3, 0x38ea, 0x3904, 0x3918,
0x3932, 0x3946, 0x395d, 0x3972, 0x3985, 0x399b, 0x39b0, 0x39c5,
0x39e0, 0x39f5, 0x3a09, 0x3a1d, 0x3a31, 0x3a47, 0x3a5c, 0x3a7b,
0x3a90, 0x3aa4, 0x3abb, 0x3ad7, 0x3aea, 0x3afc, 0x3b0f, 0x3b28,
0x3b38, 0x3b49, 0x3b5b, 0x3b6d, 0x3b7f, 0x3b91, 0x3ba3, 0x3bb7,
// Entry 48C0 - 48FF
0x3bc8, 0x3bd9, 0x3bed, 0x3bfe, 0x3c0e, 0x3c21, 0x3c33, 0x3c45,
0x3c56, 0x3c67, 0x3c79, 0x3c8a, 0x3c9e, 0x3cb7, 0x3ccc, 0x3ce1,
0x3cf7, 0x3d0d, 0x3d21, 0x3d36, 0x3d4b, 0x3d60, 0x3d75, 0x3d8a,
0x3d9f, 0x3db5, 0x3dca, 0x3ddf, 0x3df5, 0x3e0a, 0x3e1e, 0x3e34,
0x3e49, 0x3e5f, 0x3e75, 0x3e8a, 0x3e9f, 0x3eb4, 0x3ecc, 0x3ee9,
0x3efe, 0x3f15, 0x3f2e, 0x3f3d, 0x3f4c, 0x3f5b, 0x3f6a, 0x3f79,
0x3f88, 0x3f97, 0x3fa6, 0x3fb5, 0x3fc4, 0x3fd3, 0x3fe2, 0x3ff1,
0x4000, 0x4010, 0x401f, 0x402e, 0x403d, 0x404c, 0x405b, 0x406b,
// Entry 4900 - 493F
0x407b, 0x408b, 0x409b, 0x40ab, 0x40ba, 0x40d0, 0x40e2, 0x40f4,
0x4106, 0x4118, 0x412a, 0x413c, 0x414e, 0x4160, 0x4172, 0x4184,
0x4196, 0x41a8, 0x41ba, 0x41cc, 0x41de, 0x41f0, 0x4202, 0x4214,
0x4226, 0x4238, 0x424a, 0x425c, 0x426e, 0x4280, 0x4292, 0x42a4,
0x42c2, 0x42e0, 0x42fe, 0x431c, 0x433b, 0x435a, 0x4379, 0x439a,
0x43b9, 0x43d8, 0x43f7, 0x4418, 0x4437, 0x4458, 0x4477, 0x4498,
0x44b7, 0x44d7, 0x44f7, 0x4516, 0x4537, 0x4556, 0x4575, 0x4594,
0x45b3, 0x45d4, 0x45f3, 0x4614, 0x4633, 0x4652, 0x4673, 0x4696,
// Entry 4940 - 497F
0x46af, 0x46c8, 0x46e1, 0x46fa, 0x4714, 0x472e, 0x4748, 0x4762,
0x477c, 0x4796, 0x47b0, 0x47ca, 0x47e4, 0x47ff, 0x481a, 0x4834,
0x4856, 0x4870, 0x488a, 0x48a4, 0x48be, 0x48d8, 0x48f2, 0x490c,
0x4935, 0x4957, 0x4974, 0x4991, 0x49ac, 0x49c7, 0x49e4, 0x4a00,
0x4a1c, 0x4a37, 0x4a54, 0x4a71, 0x4a8d, 0x4aa8, 0x4ac6, 0x4ae4,
0x4b01, 0x4b1e, 0x4b3b, 0x4b5a, 0x4b7d, 0x4ba0, 0x4bc5, 0x4be9,
0x4c0d, 0x4c30, 0x4c55, 0x4c7a, 0x4c9e, 0x4cc2, 0x4ce6, 0x4d0c,
0x4d31, 0x4d56, 0x4d7a, 0x4da0, 0x4dc6, 0x4deb, 0x4e0f, 0x4e36,
// Entry 4980 - 49BF
0x4e5d, 0x4e83, 0x4ea9, 0x4ecf, 0x4ef7, 0x4f1e, 0x4f45, 0x4f71,
0x4f9d, 0x4fcb, 0x4ff8, 0x5025, 0x5051, 0x507f, 0x50ad, 0x50da,
0x50ff, 0x5125, 0x514d, 0x5174, 0x519b, 0x51c1, 0x51e9, 0x5211,
0x5238, 0x525e, 0x5271, 0x5288, 0x529f, 0x52be, 0x52d5, 0x52ec,
0x5308, 0x5329, 0x5341, 0x5358, 0x536c, 0x5381, 0x5395, 0x53aa,
0x53be, 0x53d3, 0x53e7, 0x53fc, 0x5411, 0x5427, 0x543c, 0x5452,
0x5467, 0x547b, 0x5490, 0x54a4, 0x54b9, 0x54cd, 0x54e1, 0x54f6,
0x550a, 0x551f, 0x5533, 0x5547, 0x555b, 0x556f, 0x5583, 0x5598,
// Entry 49C0 - 49FF
0x55ad, 0x55c1, 0x55d5, 0x55e9, 0x55fe, 0x5615, 0x562b, 0x5640,
0x5659, 0x566e, 0x5687, 0x5698, 0x56ac, 0x56c0, 0x56d6, 0x56eb,
0x5700, 0x5718, 0x5735, 0x5753, 0x576f, 0x5789, 0x57ac, 0x57c9,
0x57ec, 0x580b, 0x5827, 0x5843, 0x5866, 0x5882, 0x589d, 0x58bc,
0x58d9, 0x58f5, 0x5912, 0x592e, 0x594b, 0x5968, 0x5985, 0x59a1,
0x59bd, 0x59da, 0x59f6, 0x5a14, 0x5a32, 0x5a51, 0x5a6c, 0x5a89,
0x5aa5, 0x5ac4, 0x5ae2, 0x5b01, 0x5b1f, 0x5b3c, 0x5b59, 0x5b79,
0x5b96, 0x5bb3, 0x5bd1, 0x5bed, 0x5c0b, 0x5c2e, 0x5c4a, 0x5c66,
// Entry 4A00 - 4A3F
0x5c82, 0x5c9f, 0x5cbb, 0x5cd7, 0x5cf4, 0x5d10, 0x5d2c, 0x5d48,
0x5d65, 0x5d81, 0x5d9e, 0x5dbb, 0x5dd7, 0x5df4, 0x5e10, 0x5e2d,
0x5e49, 0x5e65, 0x5e82, 0x5e9e, 0x5ebc, 0x5ed8, 0x5ef5, 0x5f12,
0x5f2e, 0x5f4b, 0x5f67, 0x5f83, 0x5f9f, 0x5fbe, 0x5fd5, 0x5feb,
0x6002, 0x6019, 0x6031, 0x6049, 0x605d, 0x6072, 0x6084, 0x609b,
0x60b3, 0x60ca, 0x60e2, 0x60f8, 0x610e, 0x6124, 0x613a, 0x6150,
0x6167, 0x617f, 0x6198, 0x61b1, 0x61c6, 0x61db, 0x61f3, 0x6209,
0x6220, 0x6234, 0x6248, 0x625f, 0x6275, 0x628b, 0x62a2, 0x62b8,
// Entry 4A40 - 4A7F
0x62ce, 0x62e5, 0x62fa, 0x631c, 0x633e, 0x6353, 0x6369, 0x637e,
0x6396, 0x63b3, 0x63ce, 0x63ec, 0x6418, 0x643d, 0x6457, 0x6476,
0x6498, 0x64a8, 0x64b9, 0x64ca, 0x64dc, 0x64ed, 0x64ff, 0x6510,
0x6522, 0x6532, 0x6543, 0x6553, 0x6564, 0x6574, 0x6585, 0x6595,
0x65a6, 0x65b7, 0x65c8, 0x65da, 0x65ec, 0x65fd, 0x660f, 0x6621,
0x6632, 0x6643, 0x6654, 0x6666, 0x6677, 0x6689, 0x669b, 0x66ac,
0x66bd, 0x66ce, 0x66e0, 0x66f2, 0x6705, 0x6718, 0x6729, 0x673b,
0x674d, 0x675e, 0x6770, 0x6782, 0x6793, 0x67a4, 0x67b5, 0x67c6,
// Entry 4A80 - 4ABF
0x67d7, 0x67e8, 0x67fa, 0x680c, 0x681f, 0x6832, 0x6843, 0x685c,
0x6882, 0x68a9, 0x68d0, 0x68f7, 0x6920, 0x6949, 0x696c, 0x698e,
0x69b1, 0x69d5, 0x69f5, 0x6a16, 0x6a39, 0x6a5b, 0x6a7d, 0x6a9f,
0x6ac1, 0x6ae5, 0x6b06, 0x6b27, 0x6b4b, 0x6b6d, 0x6b8d, 0x6bb0,
0x6bd2, 0x6bf4, 0x6c16, 0x6c37, 0x6c58, 0x6c79, 0x6c9c, 0x6cbe,
0x6cdf, 0x6d03, 0x6d2c, 0x6d56, 0x6d78, 0x6d99, 0x6dbb, 0x6dde,
0x6dfd, 0x6e27, 0x6e49, 0x6e6a, 0x6e8b, 0x6eac, 0x6ecd, 0x6ef0,
0x6f15, 0x6f35, 0x6f58, 0x6f77, 0x6f99, 0x6fba, 0x6fda, 0x6ffa,
// Entry 4AC0 - 4AFF
0x701a, 0x703c, 0x705d, 0x707d, 0x70a0, 0x70c8, 0x70f1, 0x710d,
0x7128, 0x7144, 0x7161, 0x717a, 0x719e, 0x71ba, 0x71d5, 0x71f0,
0x720b, 0x7228, 0x7247, 0x7261, 0x727e, 0x7297, 0x72b3, 0x72ce,
0x72e8, 0x7304, 0x7327, 0x734b, 0x736d, 0x7387, 0x73a1, 0x73bd,
0x73d8, 0x73f2, 0x740f, 0x7431, 0x744b, 0x7466, 0x7482, 0x749c,
0x74b7, 0x74d2, 0x74ec, 0x7507, 0x7523, 0x753e, 0x755a, 0x7576,
0x7593, 0x75ae, 0x75ca, 0x75e6, 0x7603, 0x761e, 0x763a, 0x7656,
0x7671, 0x768d, 0x76a8, 0x76c4, 0x76e0, 0x76fd, 0x7719, 0x7736,
// Entry 4B00 - 4B3F
0x7752, 0x776f, 0x778a, 0x77a6, 0x77c2, 0x77de, 0x77f9, 0x7814,
0x7830, 0x784d, 0x7869, 0x7886, 0x78a2, 0x78bf, 0x78db, 0x78f8,
0x7915, 0x7931, 0x794f, 0x796a, 0x7985, 0x79a0, 0x79bb, 0x79d7,
0x79f2, 0x7a0e, 0x7a29, 0x7a45, 0x7a60, 0x7a7c, 0x7a97, 0x7ab3,
0x7acf, 0x7aea, 0x7b06, 0x7b22, 0x7b3f, 0x7b5b, 0x7b78, 0x7b93,
0x7baf, 0x7bcb, 0x7be8, 0x7c03, 0x7c20, 0x7c3e, 0x7c5d, 0x7c7c,
0x7c9c, 0x7cbb, 0x7cdb, 0x7cfb, 0x7d1a, 0x7d3a, 0x7d58, 0x7d7c,
0x7d9b, 0x7dba, 0x7dd9, 0x7df9, 0x7e18, 0x7e36, 0x7e55, 0x7e74,
// Entry 4B40 - 4B7F
0x7e93, 0x7eb2, 0x7ed2, 0x7ef1, 0x7f11, 0x7f30, 0x7f4f, 0x7f6f,
0x7f8d, 0x7fac, 0x7fd6, 0x7fff, 0x801f, 0x803e, 0x805e, 0x807d,
0x80a2, 0x80c1, 0x80e1, 0x8100, 0x8120, 0x8140, 0x8160, 0x817e,
0x819d, 0x81c7, 0x81f0, 0x820f, 0x822e, 0x824e, 0x827a, 0x8299,
0x82b5, 0x82d2, 0x82ef, 0x830d, 0x832a, 0x8348, 0x8366, 0x8383,
0x83a1, 0x83bd, 0x83df, 0x83fc, 0x8419, 0x8436, 0x8454, 0x8471,
0x848d, 0x84aa, 0x84c7, 0x84e4, 0x8501, 0x851f, 0x853c, 0x855a,
0x8577, 0x8594, 0x85b2, 0x85ce, 0x85eb, 0x8613, 0x863a, 0x8658,
// Entry 4B80 - 4BBF
0x8675, 0x8693, 0x86b0, 0x86d3, 0x86f0, 0x870e, 0x872b, 0x8749,
0x8767, 0x8785, 0x87a1, 0x87be, 0x87e6, 0x880d, 0x882a, 0x8847,
0x8865, 0x888f, 0x88ac, 0x88c4, 0x88dd, 0x88f5, 0x890f, 0x892f,
0x8950, 0x8968, 0x8981, 0x899a, 0x89b3, 0x89cd, 0x89e6, 0x89ff,
0x8a18, 0x8a32, 0x8a4b, 0x8a64, 0x8a7e, 0x8a97, 0x8ab1, 0x8aca,
0x8ae3, 0x8afd, 0x8b16, 0x8b2f, 0x8b48, 0x8b61, 0x8b7a, 0x8b93,
0x8bb2, 0x8bcb, 0x8bea, 0x8c04, 0x8c1e, 0x8c37, 0x8c4e, 0x8c65,
0x8c7c, 0x8c93, 0x8caa, 0x8cc4, 0x8ce2, 0x8cff, 0x8d1a, 0x8d33,
// Entry 4BC0 - 4BFF
0x8d4d, 0x8d67, 0x8d80, 0x8d99, 0x8db4, 0x8dce, 0x8de8, 0x8e01,
0x8e1c, 0x8e37, 0x8e51, 0x8e61, 0x8e70, 0x8e7f, 0x8e90, 0x8ea0,
0x8eb0, 0x8ebf, 0x8ed0, 0x8ee1, 0x8ef1, 0x8f03, 0x8f15, 0x8f27,
0x8f3a, 0x8f51, 0x8f5c, 0x8f72, 0x8f89, 0x8fa0, 0x8fb7, 0x8fce,
0x8fe5, 0x8ffc, 0x9013, 0x902a, 0x9041, 0x9058, 0x906f, 0x9086,
0x909d, 0x90b4, 0x90cc, 0x90e3, 0x90fa, 0x9111, 0x9128, 0x9143,
0x915e, 0x9170, 0x918f, 0x91a8, 0x91c8, 0x91e9, 0x91f5, 0x920d,
0x9221, 0x9236, 0x924b, 0x9260, 0x9275, 0x928a, 0x929f, 0x92b4,
// Entry 4C00 - 4C3F
0x92c9, 0x92de, 0x92f3, 0x9308, 0x931d, 0x9332, 0x9347, 0x935d,
0x9372, 0x9387, 0x939c, 0x93b1, 0x93ca, 0x93e3, 0x93f2, 0x9402,
0x9410, 0x941e, 0x942e, 0x943d, 0x944c, 0x945a, 0x946a, 0x947a,
0x9489, 0x9498, 0x94aa, 0x94bc, 0x94cd, 0x94de, 0x94ef, 0x9502,
0x9514, 0x9526, 0x953d, 0x9554, 0x956d, 0x9585, 0x959d, 0x95b4,
0x95cd, 0x95e6, 0x95fe, 0x9614, 0x962d, 0x9644, 0x965c, 0x966e,
0x967e, 0x968e, 0x969f, 0x96b0, 0x96c0, 0x96d1, 0x96e3, 0x96f6,
0x9707, 0x9717, 0x9728, 0x9739, 0x9749, 0x975a, 0x976a, 0x977a,
// Entry 4C40 - 4C7F
0x978b, 0x979d, 0x97ae, 0x97bf, 0x97cf, 0x97df, 0x97f0, 0x9803,
0x9813, 0x9823, 0x9842, 0x9853, 0x9864, 0x9876, 0x9887, 0x9898,
0x98a9, 0x98ba, 0x98ca, 0x98db, 0x98eb, 0x98fb, 0x990c, 0x991d,
0x992d, 0x9948, 0x9963, 0x997a, 0x999a, 0x99c1, 0x99f1, 0x9a21,
0x9a51, 0x9a7c, 0x9a93, 0x9ab9, 0x9ad5, 0x9b02, 0x9b2f, 0x9b5e,
0x9b84, 0x9ba4, 0x9bc6, 0x9be9, 0x9c11, 0x9c31, 0x9c46, 0x9c63,
0x9c7e, 0x9c98, 0x9cb3, 0x9ccb, 0x9ce9, 0x9d00, 0x9d1d, 0x9d35,
0x9d4a, 0x9d65, 0x9d7b, 0x9d93, 0x9daa, 0x9dc1, 0x9dd8, 0x9df1,
// Entry 4C80 - 4CBF
0x9e07, 0x9e1d, 0x9e39, 0x9e68, 0x9e81, 0x9e98, 0x9eb9, 0x9ece,
0x9ee6, 0x9f04, 0x9f35, 0x9f58, 0x9f6f, 0x9f85, 0x9fa1, 0x9fd0,
0x9fe6, 0x9ffc, 0xa014, 0xa02b, 0xa042, 0xa058, 0xa071, 0xa08a,
0xa0a8, 0xa0c5, 0xa0e5, 0xa0f9, 0xa10c, 0xa120, 0xa131, 0xa143,
0xa157, 0xa16a, 0xa17d, 0xa190, 0xa1a5, 0xa1b7, 0xa1c9, 0xa1de,
0xa1f1, 0xa202, 0xa216, 0xa22e, 0xa241, 0xa253, 0xa266, 0xa279,
0xa291, 0xa2ac, 0xa2cc, 0xa2e7, 0xa307, 0xa324, 0xa341, 0xa35d,
0xa379, 0xa39a, 0xa3b6, 0xa3d4, 0xa3e6, 0xa3f8, 0xa40d, 0xa427,
// Entry 4CC0 - 4CFF
0xa44c, 0xa47b, 0xa49e, 0xa4c7, 0xa4ef, 0xa506, 0xa51c, 0xa538,
0xa54d, 0xa564, 0xa580, 0xa596, 0xa5ac, 0xa5c4, 0xa5d9, 0xa5ee,
0xa606, 0xa61a, 0xa631, 0xa647, 0xa65d, 0xa672, 0xa688, 0xa6a6,
0xa6c4, 0xa6e7, 0xa70a, 0xa724, 0xa743, 0xa762, 0xa782, 0xa799,
0xa7b6, 0xa7cc, 0xa7e3, 0xa7fb, 0xa80f, 0xa824, 0xa840, 0xa857,
0xa86d, 0xa883, 0xa899, 0xa8b1, 0xa8c6, 0xa8db, 0xa8f3, 0xa909,
0xa91d, 0xa933, 0xa949, 0xa95e, 0xa973, 0xa988, 0xa99f, 0xa9b5,
0xa9ca, 0xa9e2, 0xa9ff, 0xaa13, 0xaa26, 0xaa3a, 0xaa4f, 0xaa60,
// Entry 4D00 - 4D3F
0xaa72, 0xaa86, 0xaa99, 0xaaac, 0xaabf, 0xaad2, 0xaae7, 0xaaf9,
0xab0b, 0xab20, 0xab33, 0xab44, 0xab58, 0xab6b, 0xab7e, 0xab91,
0xaba3, 0xabbe, 0xabd5, 0xabe9, 0xabfc, 0xac13, 0xac2a, 0xac39,
0xac49, 0xac58, 0xac68, 0xac77, 0xac87, 0xac9e, 0xacb6, 0xaccd,
0xace5, 0xacf4, 0xad04, 0xad13, 0xad23, 0xad33, 0xad44, 0xad54,
0xad65, 0xad76, 0xad86, 0xad97, 0xada7, 0xadb8, 0xadc9, 0xadda,
0xadec, 0xadfd, 0xae0f, 0xae20, 0xae30, 0xae41, 0xae51, 0xae62,
0xae72, 0xae82, 0xae93, 0xaea3, 0xaeb4, 0xaec4, 0xaed4, 0xaee4,
// Entry 4D40 - 4D7F
0xaef4, 0xaf04, 0xaf15, 0xaf26, 0xaf36, 0xaf46, 0xaf57, 0xaf73,
0xaf8e, 0xafaa, 0xafbe, 0xafde, 0xaff1, 0xb005, 0xb018, 0xb02c,
0xb047, 0xb063, 0xb07e, 0xb09a, 0xb0ad, 0xb0c1, 0xb0d4, 0xb0e8,
0xb0f5, 0xb101, 0xb114, 0xb12a, 0xb147, 0xb15e, 0xb17d, 0xb195,
0xb1a6, 0xb1b7, 0xb1ca, 0xb1dc, 0xb1ee, 0xb1ff, 0xb212, 0xb225,
0xb237, 0xb248, 0xb25c, 0xb270, 0xb283, 0xb296, 0xb2a9, 0xb2be,
0xb2d2, 0xb2e6, 0xb2ff, 0xb319, 0xb32a, 0xb33a, 0xb34a, 0xb35c,
0xb36d, 0xb37e, 0xb38e, 0xb3a0, 0xb3b2, 0xb3c3, 0xb3df, 0xb3fe,
// Entry 4D80 - 4DBF
0xb41d, 0xb440, 0xb463, 0xb47e, 0xb492, 0xb4a9, 0xb4bd, 0xb4d0,
0xb4df, 0xb4ef, 0xb4fe, 0xb50e, 0xb51d, 0xb52d, 0xb53c, 0xb54c,
0xb55b, 0xb56b, 0xb57b, 0xb58c, 0xb59c, 0xb5ad, 0xb5be, 0xb5ce,
0xb5df, 0xb5ef, 0xb600, 0xb611, 0xb622, 0xb634, 0xb645, 0xb658,
0xb66a, 0xb67b, 0xb68c, 0xb69c, 0xb6ad, 0xb6bd, 0xb6ce, 0xb6de,
0xb6ee, 0xb6ff, 0xb70f, 0xb720, 0xb730, 0xb740, 0xb750, 0xb760,
0xb770, 0xb781, 0xb792, 0xb7a2, 0xb7b2, 0xb7c6, 0xb7d9, 0xb7ed,
0xb800, 0xb814, 0xb827, 0xb83b, 0xb84e, 0xb862, 0xb874, 0xb885,
// Entry 4DC0 - 4DFF
0xb89d, 0xb8b4, 0xb8c6, 0xb8d9, 0xb8f3, 0xb8ff, 0xb912, 0xb92d,
0xb945, 0xb95c, 0xb973, 0xb98a, 0xb9a1, 0xb9b8, 0xb9cf, 0xb9e6,
0xb9fe, 0xba15, 0xba2c, 0xba43, 0xba5a, 0xba71, 0xba88, 0xba9f,
0xbab6, 0xbacd, 0xbae5, 0xbafb, 0xbb12, 0xbb28, 0xbb3e, 0xbb54,
0xbb6a, 0xbb81, 0xbb98, 0xbbae, 0xbbc4, 0xbbdc, 0xbbf3, 0xbc0a,
0xbc20, 0xbc38, 0xbc50, 0xbc67, 0xbc7e, 0xbc92, 0xbca5, 0xbcb5,
0xbcc4, 0xbcd3, 0xbce2, 0xbcf3, 0xbd05, 0xbd16, 0xbd28, 0xbd3a,
0xbd4b, 0xbd5d, 0xbd6e, 0xbd80, 0xbd92, 0xbda4, 0xbdb7, 0xbdc9,
// Entry 4E00 - 4E3F
0xbddc, 0xbdee, 0xbdff, 0xbe11, 0xbe22, 0xbe34, 0xbe45, 0xbe56,
0xbe68, 0xbe79, 0xbe8b, 0xbe9c, 0xbeae, 0xbebf, 0xbed0, 0xbee1,
0xbef2, 0xbf03, 0xbf14, 0xbf27, 0xbf3a, 0xbf4e, 0xbf61, 0xbf75,
0xbf88, 0xbf9c, 0xbfaf, 0xbfc3, 0xbfd7, 0xbfe4, 0xbff2, 0xbfff,
0xc00d, 0xc01e, 0xc02e, 0xc03e, 0xc050, 0xc061, 0xc072, 0xc082,
0xc094, 0xc0a6, 0xc0b7, 0xc0ca, 0xc0d6, 0xc0e9, 0xc0fd, 0xc10f,
0xc123, 0xc137, 0xc148, 0xc159, 0xc16a, 0xc17b, 0xc18c, 0xc19d,
0xc1af, 0xc1c2, 0xc1d4, 0xc1e7, 0xc1f9, 0xc20c, 0xc21e, 0xc231,
// Entry 4E40 - 4E7F
0xc244, 0xc257, 0xc26b, 0xc27e, 0xc292, 0xc2a5, 0xc2b7, 0xc2ca,
0xc2dc, 0xc2ef, 0xc301, 0xc313, 0xc326, 0xc338, 0xc34b, 0xc35d,
0xc36f, 0xc381, 0xc393, 0xc3a5, 0xc3b7, 0xc3ca, 0xc3dd, 0xc3f7,
0xc40c, 0xc422, 0xc43a, 0xc44f, 0xc463, 0xc473, 0xc484, 0xc494,
0xc4a5, 0xc4b5, 0xc4c6, 0xc4de, 0xc4f7, 0xc50f, 0xc528, 0xc538,
0xc549, 0xc559, 0xc56a, 0xc57b, 0xc58d, 0xc59e, 0xc5b0, 0xc5c2,
0xc5d3, 0xc5e5, 0xc5f6, 0xc608, 0xc61a, 0xc62c, 0xc63f, 0xc651,
0xc664, 0xc676, 0xc687, 0xc699, 0xc6aa, 0xc6bc, 0xc6cd, 0xc6de,
// Entry 4E80 - 4EBF
0xc6f0, 0xc701, 0xc713, 0xc724, 0xc735, 0xc746, 0xc757, 0xc769,
0xc77a, 0xc78c, 0xc79e, 0xc7af, 0xc7c0, 0xc7d5, 0xc7e9, 0xc7fe,
0xc812, 0xc827, 0xc843, 0xc860, 0xc87c, 0xc899, 0xc8ad, 0xc8c2,
0xc8d6, 0xc8eb, 0xc8fe, 0xc913, 0xc92b, 0xc943, 0xc94d, 0xc95a,
0xc96e, 0xc987, 0xc998, 0xc9ab, 0xc9bd, 0xc9d8, 0xc9f6, 0xca08,
0xca2a, 0xca4b, 0xca5d, 0xca6e, 0xca7f, 0xca92, 0xcaa4, 0xcab6,
0xcac7, 0xcada, 0xcaed, 0xcaff, 0xcb0b, 0xcb1f, 0xcb31, 0xcb4a,
0xcb60, 0xcb76, 0xcb8f, 0xcba8, 0xcbc3, 0xcbdd, 0xcbf7, 0xcc10,
// Entry 4EC0 - 4EFF
0xcc2b, 0xcc46, 0xcc60, 0xcc7a, 0xcc97, 0xccb4, 0xccd0, 0xccec,
0xcd08, 0xcd26, 0xcd43, 0xcd60, 0xcd82, 0xcda5, 0xcdb4, 0xcdc4,
0xcdd3, 0xcde2, 0xcdf1, 0xce01, 0xce10, 0xce20, 0xce30, 0xce41,
0xce51, 0xce62, 0xce73, 0xce84, 0xce94, 0xcea5, 0xceb5, 0xcec6,
0xced7, 0xcee8, 0xcefa, 0xcf0b, 0xcf1d, 0xcf2e, 0xcf3e, 0xcf4f,
0xcf5f, 0xcf71, 0xcf82, 0xcf92, 0xcfa2, 0xcfb3, 0xcfc3, 0xcfd4,
0xcfe5, 0xcff5, 0xd005, 0xd015, 0xd025, 0xd035, 0xd045, 0xd055,
0xd066, 0xd07a, 0xd08d, 0xd0a1, 0xd0b4, 0xd0c7, 0xd0db, 0xd0ee,
// Entry 4F00 - 4F3F
0xd102, 0xd116, 0xd128, 0xd139, 0xd14b, 0xd157, 0xd16a, 0xd17f,
0xd192, 0xd1ac, 0xd1c4, 0xd1d5, 0xd1e5, 0xd1fa, 0xd215, 0xd225,
0xd235, 0xd245, 0xd255, 0xd266, 0xd278, 0xd289, 0xd29b, 0xd2ac,
0xd2be, 0xd2cf, 0xd2e1, 0xd2f3, 0xd305, 0xd318, 0xd32a, 0xd33d,
0xd350, 0xd362, 0xd373, 0xd385, 0xd396, 0xd3a8, 0xd3b9, 0xd3ca,
0xd3dc, 0xd3ed, 0xd3ff, 0xd410, 0xd421, 0xd432, 0xd443, 0xd454,
0xd465, 0xd476, 0xd488, 0xd49a, 0xd4ae, 0xd4c0, 0xd4d3, 0xd4e5,
0xd4f8, 0xd50a, 0xd51d, 0xd52f, 0xd542, 0xd554, 0xd567, 0xd57a,
// Entry 4F40 - 4F7F
0xd58e, 0xd5a1, 0xd5b5, 0xd5c9, 0xd5dd, 0xd5f0, 0xd604, 0xd617,
0xd62b, 0xd63f, 0xd653, 0xd667, 0xd67c, 0xd690, 0xd6a5, 0xd6b9,
0xd6ce, 0xd6e2, 0xd6f5, 0xd709, 0xd71c, 0xd730, 0xd743, 0xd756,
0xd76a, 0xd77d, 0xd791, 0xd7a5, 0xd7b8, 0xd7cb, 0xd7de, 0xd7f1,
0xd804, 0xd818, 0xd82b, 0xd83e, 0xd855, 0xd86c, 0xd882, 0xd899,
0xd8af, 0xd8c6, 0xd8dc, 0xd8f3, 0xd909, 0xd920, 0xd934, 0xd949,
0xd95d, 0xd970, 0xd983, 0xd998, 0xd9ac, 0xd9c0, 0xd9d3, 0xd9e8,
0xd9fd, 0xda11, 0xda36, 0xda4e, 0xda63, 0xda77, 0xda87, 0xda98,
// Entry 4F80 - 4FBF
0xdaa8, 0xdab9, 0xdac9, 0xdada, 0xdaf2, 0xdb0a, 0xdb1b, 0xdb2c,
0xdb3d, 0xdb4e, 0xdb5f, 0xdb71, 0xdb82, 0xdb94, 0xdba6, 0xdbb7,
0xdbc9, 0xdbda, 0xdbec, 0xdbfe, 0xdc10, 0xdc23, 0xdc35, 0xdc48,
0xdc5a, 0xdc6b, 0xdc7d, 0xdc8e, 0xdca0, 0xdcb1, 0xdcc2, 0xdcd4,
0xdce5, 0xdcf7, 0xdd08, 0xdd19, 0xdd2a, 0xdd3b, 0xdd4d, 0xdd5e,
0xdd70, 0xdd82, 0xdd93, 0xdda4, 0xddb9, 0xddcb, 0xdde0, 0xddf5,
0xde09, 0xde1e, 0xde32, 0xde47, 0xde63, 0xde80, 0xde95, 0xdeaa,
0xdebf, 0xded4, 0xdee7, 0xdef1, 0xdf07, 0xdf19, 0xdf36, 0xdf5a,
// Entry 4FC0 - 4FFF
0xdf73, 0xdf8c, 0xdfa8, 0xdfc5, 0xdfe1, 0xdffc, 0xe017, 0xe034,
0xe050, 0xe06c, 0xe087, 0xe0a1, 0xe0bc, 0xe0d7, 0xe0f2, 0xe10d,
0xe123, 0xe13a, 0xe150, 0xe167, 0xe17d, 0xe194, 0xe1b2, 0xe1d1,
0xe1ef, 0xe20e, 0xe225, 0xe23c, 0xe253, 0xe26a, 0xe281, 0xe299,
0xe2b0, 0xe2c8, 0xe2e0, 0xe2f7, 0xe30f, 0xe326, 0xe33e, 0xe356,
0xe36e, 0xe387, 0xe39f, 0xe3b8, 0xe3d0, 0xe3e7, 0xe3ff, 0xe416,
0xe42e, 0xe445, 0xe45c, 0xe474, 0xe48b, 0xe4a3, 0xe4ba, 0xe4d1,
0xe4e8, 0xe4ff, 0xe516, 0xe52e, 0xe546, 0xe55d, 0xe574, 0xe58c,
// Entry 5000 - 503F
0xe5a4, 0xe5bd, 0xe5d8, 0xe5f3, 0xe60d, 0xe628, 0xe642, 0xe65d,
0xe67f, 0xe6a2, 0xe6c4, 0xe6e7, 0xe702, 0xe71d, 0xe738, 0xe753,
0xe76f, 0xe792, 0xe7ad, 0xe7c7, 0xe7e0, 0xe800, 0xe817, 0xe82a,
0xe847, 0xe85f, 0xe872, 0xe88c, 0xe8aa, 0xe8cb, 0xe8eb, 0xe90c,
0xe919, 0xe927, 0xe934, 0xe942, 0xe94f, 0xe95d, 0xe972, 0xe988,
0xe99d, 0xe9b3, 0xe9c0, 0xe9ce, 0xe9db, 0xe9e9, 0xe9f7, 0xea06,
0xea14, 0xea23, 0xea32, 0xea42, 0xea50, 0xea5f, 0xea6d, 0xea7c,
0xea8b, 0xea9b, 0xeaaa, 0xeaba, 0xeac9, 0xead9, 0xeae8, 0xeaf6,
// Entry 5040 - 507F
0xeb05, 0xeb13, 0xeb22, 0xeb30, 0xeb3f, 0xeb4d, 0xeb5c, 0xeb6a,
0xeb79, 0xeb87, 0xeb96, 0xeba4, 0xebb2, 0xebc1, 0xebcf, 0xebde,
0xebec, 0xebfb, 0xec0a, 0xec18, 0xec26, 0xec38, 0xec49, 0xec5b,
0xec6c, 0xec7e, 0xec97, 0xecb1, 0xecca, 0xece4, 0xecf5, 0xed07,
0xed18, 0xed2a, 0xed3a, 0xed4f, 0xed61, 0xed72, 0xed81, 0xed93,
0xedab, 0xedb2, 0xedbd, 0xedc7, 0xedd8, 0xede2, 0xedf1, 0xee07,
0xee16, 0xee24, 0xee32, 0xee42, 0xee51, 0xee60, 0xee6e, 0xee7e,
0xee8e, 0xee9d, 0xeeae, 0xeec3, 0xeed6, 0xeee6, 0xef00, 0xef15,
// Entry 5080 - 50BF
0xef2a, 0xef36, 0xef46, 0xef57, 0xef67, 0xef78, 0xef88, 0xef99,
0xefb1, 0xefca, 0xefe2, 0xeffb, 0xf00b, 0xf01c, 0xf02c, 0xf03d,
0xf04e, 0xf060, 0xf071, 0xf083, 0xf095, 0xf0a6, 0xf0b8, 0xf0c9,
0xf0db, 0xf0ed, 0xf0ff, 0xf112, 0xf124, 0xf137, 0xf149, 0xf15a,
0xf16c, 0xf17d, 0xf18f, 0xf1a0, 0xf1b1, 0xf1c3, 0xf1d4, 0xf1e6,
0xf1f7, 0xf208, 0xf219, 0xf22a, 0xf23b, 0xf24d, 0xf25f, 0xf270,
0xf281, 0xf296, 0xf2aa, 0xf2bf, 0xf2d3, 0xf2e8, 0xf304, 0xf321,
0xf33d, 0xf35a, 0xf36e, 0xf388, 0xf39d, 0xf3b1, 0xf3cb, 0xf3e0,
// Entry 50C0 - 50FF
0xf3f8, 0xf40d, 0xf421, 0xf434, 0xf446, 0xf45b, 0xf468, 0xf481,
0xf48b, 0xf49d, 0xf4ae, 0xf4bf, 0xf4d2, 0xf4e4, 0xf4f6, 0xf507,
0xf51a, 0xf52d, 0xf53f, 0xf54f, 0xf560, 0xf570, 0xf581, 0xf591,
0xf5a2, 0xf5ba, 0xf5d3, 0xf5eb, 0xf604, 0xf614, 0xf625, 0xf635,
0xf646, 0xf657, 0xf669, 0xf67a, 0xf68c, 0xf69e, 0xf6af, 0xf6c1,
0xf6d2, 0xf6e4, 0xf6f6, 0xf708, 0xf71b, 0xf72d, 0xf740, 0xf752,
0xf763, 0xf775, 0xf786, 0xf798, 0xf7a9, 0xf7ba, 0xf7cc, 0xf7dd,
0xf7ef, 0xf800, 0xf811, 0xf822, 0xf833, 0xf844, 0xf856, 0xf868,
// Entry 5100 - 513F
0xf879, 0xf88a, 0xf89f, 0xf8b3, 0xf8c8, 0xf8dc, 0xf8f1, 0xf90d,
0xf92a, 0xf93e, 0xf953, 0xf967, 0xf97c, 0xf994, 0xf9a9, 0xf9bd,
0xf9d0, 0xf9e2, 0xf9f6, 0xfa03, 0xfa17, 0xfa2c, 0xfa41, 0xfa5a,
0xfa73, 0xfa8c, 0xfaa4, 0xfadc, 0xfb12, 0xfb45, 0xfb7f, 0xfbb9,
0xfbd9, 0xfc03, 0xfc2d, 0xfc57, 0xfc84, 0xfcb0, 0xfcda, 0xfd0e,
0xfd43, 0xfd6a, 0xfd8f, 0xfdb5, 0xfdcf, 0xfded, 0xfe0c, 0xfe19,
0xfe27, 0xfe34, 0xfe42, 0xfe4f, 0xfe5d, 0xfe72, 0xfe88, 0xfe9d,
0xfeb3, 0xfec0, 0xfece, 0xfedb, 0xfee9, 0xfef7, 0xff06, 0xff14,
// Entry 5140 - 517F
0xff23, 0xff32, 0xff40, 0xff4f, 0xff5d, 0xff6c, 0xff7b, 0xff8a,
0xff9a, 0xffa9, 0xffb9, 0xffc8, 0xffd6, 0xffe5, 0xfff3, 0x0002,
0x0010, 0x001e, 0x002d, 0x003b, 0x004a, 0x0058, 0x0066, 0x0074,
0x0082, 0x0090, 0x009f, 0x00ae, 0x00bc, 0x00ca, 0x00d9, 0x00eb,
0x00fc, 0x010e, 0x011f, 0x0131, 0x014a, 0x0164, 0x017d, 0x0197,
0x01a8, 0x01ba, 0x01cb, 0x01dd, 0x01ef, 0x0200, 0x0210, 0x0225,
0x022f, 0x0240, 0x0256, 0x0264, 0x0273, 0x0281, 0x028f, 0x029f,
0x02ae, 0x02bd, 0x02cb, 0x02db, 0x02eb, 0x02fa, 0x0317, 0x032e,
// Entry 5180 - 51BF
0x0352, 0x0376, 0x039a, 0x03bf, 0x03eb, 0x0403, 0x0430, 0x0445,
0x0468, 0x0492, 0x04c3, 0x04d1, 0x04e0, 0x04ee, 0x04fd, 0x050b,
0x051a, 0x0528, 0x0537, 0x0545, 0x0554, 0x0563, 0x0573, 0x0582,
0x0592, 0x05a2, 0x05b1, 0x05c1, 0x05d0, 0x05e0, 0x05f0, 0x0600,
0x0611, 0x0621, 0x0632, 0x0642, 0x0651, 0x0661, 0x0670, 0x0680,
0x068f, 0x069e, 0x06ae, 0x06bd, 0x06cd, 0x06dc, 0x06eb, 0x06fa,
0x0709, 0x0718, 0x0728, 0x0737, 0x0746, 0x0756, 0x0769, 0x077b,
0x078e, 0x07a0, 0x07b3, 0x07c5, 0x07d8, 0x07ea, 0x07fd, 0x080f,
// Entry 51C0 - 51FF
0x0822, 0x0833, 0x0843, 0x085b, 0x0872, 0x0882, 0x0891, 0x08a0,
0x08b1, 0x08c1, 0x08d1, 0x08e0, 0x08f1, 0x0902, 0x0912, 0x0928,
0x093d, 0x0952, 0x0969, 0x097f, 0x0995, 0x09aa, 0x09c1, 0x09d8,
0x09ee, 0x0a12, 0x0a35, 0x0a58, 0x0a7d, 0x0aa1, 0x0ac5, 0x0ae8,
0x0b0d, 0x0b32, 0x0b56, 0x0b64, 0x0b73, 0x0b82, 0x0b90, 0x0b9e,
0x0bb6, 0x0bc4, 0x0bd3, 0x0be1, 0x0bef, 0x0bfd, 0x0c0c, 0x0c1b,
0x0c29, 0x0c37, 0x0c45, 0x0c54, 0x0c62, 0x0c6f, 0x0c7d, 0x0c8c,
0x0c9a, 0x0cb2, 0x0cc1, 0x0cd0, 0x0cdf, 0x0cf7, 0x0d14, 0x0d31,
// Entry 5200 - 523F
0x0d57, 0x0d68, 0x0d7a, 0x0d8b, 0x0d9d, 0x0dae, 0x0dc0, 0x0dd1,
0x0de3, 0x0df4, 0x0e06, 0x0e18, 0x0e28, 0x0e37, 0x0e45, 0x0e53,
0x0e63, 0x0e72, 0x0e81, 0x0e8f, 0x0e9f, 0x0eaf, 0x0ebe, 0x0ecd,
0x0edf, 0x0ef6, 0x0f07, 0x0f16, 0x0f24, 0x0f32, 0x0f41, 0x0f51,
0x0f60, 0x0f70, 0x0f7f, 0x0f8e, 0x0f9c, 0x0fab, 0x0fb9, 0x0fc8,
0x0fd6, 0x0fe5, 0x0ff3, 0x1002, 0x1010, 0x101f, 0x102e, 0x103e,
0x104d, 0x105d, 0x106d, 0x107c, 0x108c, 0x109b, 0x10ab, 0x10bb,
0x10cb, 0x10dc, 0x10ec, 0x10fd, 0x110d, 0x111c, 0x112c, 0x113b,
// Entry 5240 - 527F
0x114b, 0x115a, 0x1169, 0x1179, 0x1188, 0x1198, 0x11a7, 0x11b6,
0x11c5, 0x11d4, 0x11e3, 0x11f3, 0x1203, 0x1212, 0x1221, 0x1231,
0x1244, 0x1256, 0x1269, 0x127b, 0x128e, 0x12a8, 0x12c3, 0x12d5,
0x12e8, 0x12fa, 0x130d, 0x1320, 0x1332, 0x1343, 0x1353, 0x136a,
0x1389, 0x13a5, 0x13c2, 0x13df, 0x13fc, 0x1419, 0x1436, 0x1453,
0x146f, 0x148b, 0x14a9, 0x14c6, 0x14e3, 0x1501, 0x151f, 0x153c,
0x155a, 0x1578, 0x1596, 0x15b5, 0x15d2, 0x15ef, 0x160c, 0x1629,
0x1646, 0x1665, 0x1684, 0x16a3, 0x16c1, 0x16e0, 0x16fe, 0x171d,
// Entry 5280 - 52BF
0x173a, 0x1754, 0x176f, 0x178a, 0x17a5, 0x17c0, 0x17db, 0x17f6,
0x1810, 0x182a, 0x1846, 0x1861, 0x187c, 0x1898, 0x18b4, 0x18cf,
0x18eb, 0x1907, 0x1923, 0x1940, 0x195b, 0x1976, 0x1991, 0x19ac,
0x19c7, 0x19e4, 0x1a01, 0x1a1e, 0x1a3a, 0x1a57, 0x1a73, 0x1a90,
0x1aa6, 0x1abb, 0x1ad0, 0x1ae7, 0x1afd, 0x1b13, 0x1b28, 0x1b3f,
0x1b56, 0x1b6c, 0x1b82, 0x1b9b, 0x1bb4, 0x1bcc, 0x1be4, 0x1bfc,
0x1c16, 0x1c2f, 0x1c48, 0x1c56, 0x1c6a, 0x1c7f, 0x1c93, 0x1ca8,
0x1cbc, 0x1cd1, 0x1ce5, 0x1cf9, 0x1d0e, 0x1d24, 0x1d39, 0x1d4f,
// Entry 52C0 - 52FF
0x1d65, 0x1d7a, 0x1d90, 0x1da5, 0x1dbb, 0x1dd1, 0x1de7, 0x1dfe,
0x1e14, 0x1e29, 0x1e3f, 0x1e54, 0x1e6a, 0x1e7f, 0x1e94, 0x1eaa,
0x1ebf, 0x1ed5, 0x1eea, 0x1eff, 0x1f15, 0x1f2a, 0x1f3f, 0x1f54,
0x1f6a, 0x1f80, 0x1f95, 0x1faa, 0x1fc0, 0x1fd5, 0x1fee, 0x2006,
0x201f, 0x2037, 0x2050, 0x2068, 0x2081, 0x2099, 0x20b2, 0x20ce,
0x20e6, 0x20f8, 0x2117, 0x212c, 0x2142, 0x2157, 0x216d, 0x2185,
0x219b, 0x21b7, 0x21cd, 0x21e2, 0x21f7, 0x220e, 0x2224, 0x223a,
0x224f, 0x2266, 0x227d, 0x2293, 0x22a7, 0x22bc, 0x22d0, 0x22e5,
// Entry 5300 - 533F
0x22f9, 0x230e, 0x232a, 0x2347, 0x235b, 0x2370, 0x2384, 0x2399,
0x23ae, 0x23c4, 0x23d9, 0x23ef, 0x2405, 0x241a, 0x2430, 0x2445,
0x245b, 0x2471, 0x2487, 0x249e, 0x24b4, 0x24cb, 0x24e1, 0x24f6,
0x250c, 0x2521, 0x2537, 0x254c, 0x2561, 0x2577, 0x258c, 0x25a2,
0x25b7, 0x25cc, 0x25e1, 0x25f6, 0x260b, 0x2621, 0x2637, 0x264c,
0x2661, 0x2677, 0x268d, 0x26a6, 0x26be, 0x26d7, 0x26ef, 0x2708,
0x2728, 0x2749, 0x2761, 0x277a, 0x2792, 0x27ab, 0x27c4, 0x27dc,
0x27f3, 0x280c, 0x2824, 0x283a, 0x2860, 0x2879, 0x2896, 0x28b4,
// Entry 5340 - 537F
0x28d1, 0x28ee, 0x290c, 0x2929, 0x2947, 0x2965, 0x298b, 0x29ad,
0x29c7, 0x29e2, 0x29fc, 0x2a17, 0x2a32, 0x2a4c, 0x2a67, 0x2a81,
0x2a9c, 0x2ab7, 0x2ad3, 0x2aee, 0x2b0a, 0x2b25, 0x2b3f, 0x2b5a,
0x2b74, 0x2b8f, 0x2ba9, 0x2bc3, 0x2bde, 0x2bf8, 0x2c13, 0x2c2d,
0x2c48, 0x2c64, 0x2c7f, 0x2c9b, 0x2cb6, 0x2cd0, 0x2cea, 0x2d04,
0x2d1e, 0x2d38, 0x2d52, 0x2d6d, 0x2d88, 0x2da2, 0x2dbc, 0x2dd8,
0x2dfd, 0x2e19, 0x2e3a, 0x2e69, 0x2e93, 0x2eb1, 0x2ece, 0x2ef8,
0x2f20, 0x2f48, 0x2f70, 0x2f98, 0x2fba, 0x2fdc, 0x2ff7, 0x3011,
// Entry 5380 - 53BF
0x3032, 0x3052, 0x3081, 0x30b0, 0x30ca, 0x30da, 0x30ee, 0x3103,
0x3117, 0x312b, 0x313f, 0x3154, 0x3169, 0x317e, 0x319a, 0x31b6,
0x31cf, 0x31e0, 0x31f2, 0x3203, 0x3215, 0x3227, 0x3238, 0x324a,
0x325b, 0x326d, 0x327f, 0x3291, 0x32a4, 0x32b6, 0x32c9, 0x32db,
0x32ec, 0x32fe, 0x330f, 0x3321, 0x3332, 0x3343, 0x3355, 0x3366,
0x3378, 0x3389, 0x339b, 0x33ae, 0x33c0, 0x33d2, 0x33e3, 0x33f4,
0x3405, 0x3416, 0x3427, 0x3438, 0x344a, 0x345c, 0x346d, 0x347e,
0x3491, 0x34a9, 0x34c1, 0x34e2, 0x3503, 0x3525, 0x3546, 0x3564,
// Entry 53C0 - 53FF
0x3582, 0x35a1, 0x35bf, 0x35dd, 0x35fb, 0x3619, 0x3637, 0x3655,
0x3674, 0x3692, 0x36b1, 0x36c6, 0x36da, 0x36f1, 0x3702, 0x3714,
0x3725, 0x373d, 0x374f, 0x3783, 0x37b0, 0x37d3, 0x37ea, 0x3801,
0x381f, 0x383e, 0x385c, 0x387b, 0x3899, 0x38b8, 0x38d8, 0x38f9,
0x3919, 0x393a, 0x395a, 0x397b, 0x3991, 0x39a7, 0x39bd, 0x39d3,
0x39e8, 0x39fd, 0x3a12, 0x3a27, 0x3a3c, 0x3a51, 0x3a66, 0x3a7c,
0x3a91, 0x3aa6, 0x3abc, 0x3ad1, 0x3ae6, 0x3afb, 0x3b10, 0x3b26,
0x3b3b, 0x3b51, 0x3b66, 0x3b7b, 0x3b91, 0x3ba5, 0x3bb9, 0x3bcd,
// Entry 5400 - 543F
0x3be1, 0x3bf5, 0x3c0a, 0x3c1f, 0x3c39, 0x3c53, 0x3c6d, 0x3c87,
0x3ca1, 0x3cbb, 0x3cd5, 0x3cf0, 0x3d0a, 0x3d26, 0x3d3d, 0x3d5c,
0x3d7e, 0x3d9b, 0x3dc0, 0x3ddc, 0x3df3, 0x3e15, 0x3e32, 0x3e4c,
0x3e6c, 0x3e91, 0x3eb1, 0x3ed2, 0x3eee, 0x3f06, 0x3f2d, 0x3f4f,
0x3f6d, 0x3f81, 0x3fa5, 0x3fba, 0x3fd9, 0x3ff7, 0x401f, 0x4046,
0x406d, 0x4095, 0x40aa, 0x40bf, 0x40d5, 0x40ea, 0x4100, 0x411a,
0x4134, 0x414f, 0x416a, 0x417d, 0x4191, 0x41a3, 0x41b6, 0x41c8,
0x41dc, 0x41ee, 0x41ff, 0x4213, 0x4225, 0x4237, 0x424b, 0x425f,
// Entry 5440 - 547F
0x4271, 0x4283, 0x4296, 0x42ab, 0x42bf, 0x42d4, 0x42e8, 0x42fa,
0x430c, 0x431e, 0x4332, 0x4346, 0x4359, 0x436c, 0x437e, 0x4392,
0x43a7, 0x43bb, 0x43cf, 0x43e3, 0x43f3, 0x4405, 0x4416, 0x4427,
0x443a, 0x444c, 0x445e, 0x446f, 0x4482, 0x4495, 0x44a7, 0x44b9,
0x44cc, 0x44de, 0x44f1, 0x4503, 0x4516, 0x4530, 0x454b, 0x4565,
0x4577, 0x458a, 0x459c, 0x45af, 0x45c2, 0x45d6, 0x45e9, 0x45fd,
0x4611, 0x4624, 0x4638, 0x464b, 0x465f, 0x4673, 0x4687, 0x469c,
0x46b0, 0x46c5, 0x46d9, 0x46ec, 0x4700, 0x4713, 0x4727, 0x473a,
// Entry 5480 - 54BF
0x474d, 0x4761, 0x4774, 0x4788, 0x479b, 0x47ae, 0x47c1, 0x47d4,
0x47e7, 0x47fb, 0x480f, 0x4822, 0x4835, 0x484c, 0x4862, 0x4879,
0x488f, 0x48a6, 0x48c4, 0x48e3, 0x4901, 0x4917, 0x492e, 0x4944,
0x495b, 0x4975, 0x498c, 0x49a2, 0x49b7, 0x49ce, 0x49dd, 0x49f3,
0x4a0b, 0x4a21, 0x4a37, 0x4a4b, 0x4a5e, 0x4a71, 0x4a86, 0x4a9a,
0x4aae, 0x4ac1, 0x4ad6, 0x4aeb, 0x4aff, 0x4b13, 0x4b27, 0x4b3d,
0x4b52, 0x4b67, 0x4b7b, 0x4b91, 0x4ba7, 0x4bbc, 0x4bd0, 0x4be7,
0x4bfe, 0x4c14, 0x4c2a, 0x4c40, 0x4c58, 0x4c6f, 0x4c86, 0x4ca2,
// Entry 54C0 - 54FF
0x4cb3, 0x4cc4, 0x4cd5, 0x4ce7, 0x4cf8, 0x4d0a, 0x4d1b, 0x4d2d,
0x4d3e, 0x4d50, 0x4d61, 0x4d73, 0x4d84, 0x4d95, 0x4da6, 0x4db8,
0x4dc9, 0x4dda, 0x4dec, 0x4dff, 0x4e11, 0x4e22, 0x4e34, 0x4e45,
0x4e56, 0x4e67, 0x4e78, 0x4e89, 0x4e9b, 0x4eac, 0x4ebd, 0x4ecd,
0x4ee8, 0x4f04, 0x4f1f, 0x4f3b, 0x4f56, 0x4f72, 0x4f8d, 0x4fa9,
0x4fc4, 0x4fe0, 0x4ffb, 0x5016, 0x5031, 0x504d, 0x5068, 0x5083,
0x509f, 0x50bc, 0x50d8, 0x50f3, 0x510f, 0x512a, 0x5145, 0x5160,
0x517b, 0x5197, 0x51b2, 0x51cd, 0x51e7, 0x51fc, 0x5210, 0x5224,
// Entry 5500 - 553F
0x5238, 0x524c, 0x5261, 0x5279, 0x528f, 0x52a6, 0x52bc, 0x52d3,
0x52e9, 0x5300, 0x5316, 0x532d, 0x5343, 0x535a, 0x5371, 0x5389,
0x53a0, 0x53b8, 0x53d0, 0x53e7, 0x53ff, 0x5416, 0x542e, 0x5446,
0x545e, 0x5477, 0x548f, 0x54a8, 0x54c0, 0x54d7, 0x54ef, 0x5506,
0x551e, 0x5535, 0x554c, 0x5564, 0x557b, 0x5593, 0x55aa, 0x55c1,
0x55d8, 0x55ef, 0x5606, 0x561e, 0x5636, 0x564d, 0x5664, 0x567c,
0x5695, 0x56ae, 0x56c6, 0x56e1, 0x56fb, 0x5716, 0x5730, 0x574b,
0x576d, 0x5787, 0x57a2, 0x57bc, 0x57d7, 0x57f2, 0x580c, 0x5824,
// Entry 5540 - 557F
0x583d, 0x5857, 0x586b, 0x587e, 0x5893, 0x58ab, 0x58c2, 0x58d9,
0x58f2, 0x590a, 0x5922, 0x5939, 0x5952, 0x596b, 0x5983, 0x5999,
0x59b0, 0x59c6, 0x59dd, 0x59f3, 0x5a0a, 0x5a21, 0x5a38, 0x5a4f,
0x5a66, 0x5a7d, 0x5a94, 0x5aab, 0x5ac3, 0x5ada, 0x5af1, 0x5b09,
0x5b20, 0x5b38, 0x5b4f, 0x5b66, 0x5b7e, 0x5b95, 0x5bad, 0x5bc4,
0x5bdb, 0x5bf3, 0x5c0b, 0x5c24, 0x5c3c, 0x5c53, 0x5c6b, 0x5c83,
0x5c9c, 0x5cb4, 0x5ccb, 0x5ce3, 0x5cfa, 0x5d11, 0x5d28, 0x5d43,
0x5d5d, 0x5d78, 0x5d92, 0x5dad, 0x5dc8, 0x5de3, 0x5dfe, 0x5e19,
// Entry 5580 - 55BF
0x5e34, 0x5e4e, 0x5e62, 0x5e72, 0x5e8a, 0x5ea1, 0x5eb8, 0x5ed1,
0x5ee9, 0x5f01, 0x5f18, 0x5f31, 0x5f4a, 0x5f62, 0x5f76, 0x5f8a,
0x5f9e, 0x5fb2, 0x5fc6, 0x5fdb, 0x5fef, 0x6004, 0x6018, 0x602d,
0x6041, 0x6055, 0x606a, 0x607e, 0x6093, 0x60a7, 0x60bc, 0x60d2,
0x60e7, 0x60fd, 0x6112, 0x6126, 0x613b, 0x614f, 0x6164, 0x6179,
0x618d, 0x61a2, 0x61b6, 0x61cb, 0x61e0, 0x61f4, 0x6208, 0x621c,
0x6230, 0x6246, 0x625a, 0x626e, 0x6282, 0x6297, 0x62ad, 0x62c2,
0x62d9, 0x62ea, 0x6300, 0x6315, 0x632a, 0x6341, 0x6357, 0x636d,
// Entry 55C0 - 55FF
0x6382, 0x6399, 0x63b0, 0x63c6, 0x63d7, 0x63e8, 0x63fa, 0x640b,
0x641c, 0x642d, 0x643e, 0x644f, 0x6460, 0x6471, 0x6482, 0x6494,
0x64a5, 0x64b6, 0x64c7, 0x64d8, 0x64e9, 0x64f9, 0x6506, 0x651a,
0x652e, 0x6542, 0x6556, 0x6568, 0x657e, 0x6593, 0x65a5, 0x65b4,
0x65c5, 0x65d2, 0x65e0, 0x65ed, 0x65fb, 0x6608, 0x6616, 0x662b,
0x6641, 0x6656, 0x666c, 0x6679, 0x6687, 0x6694, 0x66a2, 0x66b1,
0x66bf, 0x66ce, 0x66dd, 0x66eb, 0x66fa, 0x6708, 0x6717, 0x6726,
0x6735, 0x6745, 0x6754, 0x6764, 0x6773, 0x6781, 0x6790, 0x679e,
// Entry 5600 - 563F
0x67ad, 0x67bb, 0x67c9, 0x67d8, 0x67e6, 0x67f5, 0x6803, 0x6811,
0x681f, 0x682d, 0x683b, 0x684a, 0x6859, 0x6867, 0x6875, 0x6885,
0x6897, 0x68b3, 0x68c4, 0x68d6, 0x68e7, 0x68f9, 0x6912, 0x6923,
0x6935, 0x6947, 0x6957, 0x6965, 0x696f, 0x6980, 0x699f, 0x69c8,
0x69df, 0x69fc, 0x6a10, 0x6a2b, 0x6a46, 0x6a5d, 0x6a7b, 0x6a92,
0x6ab1, 0x6ac0, 0x6ace, 0x6adc, 0x6aec, 0x6afb, 0x6b0a, 0x6b18,
0x6b28, 0x6b38, 0x6b47, 0x6b56, 0x6b65, 0x6b93, 0x6bbe, 0x6bda,
0x6bf9, 0x6c14, 0x6c34, 0x6c53, 0x6c75, 0x6c91, 0x6caf, 0x6ccd,
// Entry 5640 - 567F
0x6ce5, 0x6cfe, 0x6d1d, 0x6d3c, 0x6d54, 0x6d6e, 0x6d87, 0x6da0,
0x6dbd, 0x6de4, 0x6df2, 0x6e03, 0x6e17, 0x6e29, 0x6e3f, 0x6e50,
0x6e63, 0x6e77, 0x6e87, 0x6e97, 0x6ea5, 0x6eb8, 0x6ec9, 0x6ed9,
0x6ee8, 0x6f02, 0x6f1c, 0x6f2b, 0x6f3e, 0x6f5b, 0x6f78, 0x6f8a,
0x6f9c, 0x6fac, 0x6fbc, 0x6fd4, 0x6fec, 0x7000, 0x7015, 0x7032,
0x7042, 0x705a, 0x7074, 0x7094, 0x70ad, 0x70c7, 0x70e8, 0x7103,
0x711d, 0x712e, 0x713f, 0x715b, 0x717c, 0x7197, 0x71b8, 0x71d2,
0x71f2, 0x720e, 0x722b, 0x7248, 0x726f, 0x7285, 0x7297, 0x72b5,
// Entry 5680 - 56BF
0x72d7, 0x72fa, 0x7317, 0x7334, 0x7345, 0x7356, 0x7373, 0x739a,
0x73ab, 0x73c5, 0x73e1, 0x73fd, 0x7417, 0x7433, 0x744d, 0x7468,
0x7483, 0x7496, 0x74aa, 0x74bd, 0x74da, 0x74eb, 0x7504, 0x7521,
0x7552, 0x7575, 0x7589, 0x759c, 0x75af, 0x75cc, 0x75e0, 0x75f4,
0x7606, 0x7622, 0x763e, 0x767b, 0x769f, 0x76e2, 0x76f5, 0x770a,
0x771b, 0x772d, 0x7740, 0x7755, 0x7767, 0x7782, 0x7796, 0x77a8,
0x77bc, 0x77cd, 0x77e6, 0x7801, 0x7821, 0x7832, 0x784e, 0x786a,
0x7887, 0x789b, 0x78ba, 0x78cc, 0x78df, 0x78f0, 0x7902, 0x792d,
// Entry 56C0 - 56FF
0x7951, 0x7976, 0x7998, 0x79ba, 0x79e6, 0x7a08, 0x7a2c, 0x7a4f,
0x7a71, 0x7a93, 0x7abd, 0x7ae0, 0x7b02, 0x7b24, 0x7b51, 0x7b74,
0x7b96, 0x7bc2, 0x7be4, 0x7c08, 0x7c34, 0x7c57, 0x7c69, 0x7c7b,
0x7c8f, 0x7ca3, 0x7cb4, 0x7cc6, 0x7cd8, 0x7cf4, 0x7d07, 0x7d19,
0x7d3e, 0x7d51, 0x7d62, 0x7d7b, 0x7d91, 0x7daa, 0x7dbc, 0x7dd9,
0x7dec, 0x7dfe, 0x7e12, 0x7e24, 0x7e36, 0x7e49, 0x7e61, 0x7e7e,
0x7e91, 0x7ea4, 0x7eb4, 0x7ece, 0x7ef2, 0x7f03, 0x7f2c, 0x7f47,
0x7f61, 0x7f7c, 0x7f97, 0x7fb0, 0x7fc3, 0x7fd6, 0x7fe7, 0x7ff8,
// Entry 5700 - 573F
0x8014, 0x8035, 0x804f, 0x806c, 0x8089, 0x80a2, 0x80b5, 0x80c9,
0x80dc, 0x80ef, 0x810a, 0x812e, 0x815c, 0x8178, 0x8195, 0x81b8,
0x81e0, 0x81fc, 0x821d, 0x823f, 0x825f, 0x8287, 0x82a4, 0x82c0,
0x82e7, 0x8303, 0x831f, 0x833b, 0x8357, 0x8368, 0x837e, 0x8390,
0x83ba, 0x83dc, 0x83ff, 0x8429, 0x8444, 0x8460, 0x8486, 0x84a2,
0x84c6, 0x84e2, 0x8506, 0x8521, 0x853c, 0x8562, 0x857e, 0x8599,
0x85bc, 0x85d7, 0x8602, 0x8624, 0x8640, 0x865b, 0x8677, 0x869a,
0x86bf, 0x86ec, 0x8708, 0x872c, 0x874f, 0x876c, 0x878d, 0x87ba,
// Entry 5740 - 577F
0x87d6, 0x87f5, 0x8811, 0x8836, 0x885a, 0x8875, 0x8898, 0x88b3,
0x88cf, 0x88f4, 0x890f, 0x892b, 0x8947, 0x8963, 0x8988, 0x89a5,
0x89c1, 0x89de, 0x89f8, 0x8a13, 0x8a36, 0x8a51, 0x8a64, 0x8a85,
0x8a97, 0x8abf, 0x8ad1, 0x8afd, 0x8b11, 0x8b23, 0x8b35, 0x8b48,
0x8b60, 0x8b7d, 0x8b9e, 0x8bb0, 0x8bc3, 0x8bd8, 0x8bee, 0x8c0e,
0x8c1f, 0x8c38, 0x8c51, 0x8c6e, 0x8c80, 0x8c9b, 0x8cba, 0x8cce,
0x8ce1, 0x8cf9, 0x8d0c, 0x8d30, 0x8d53, 0x8d70, 0x8d95, 0x8db1,
0x8dc5, 0x8dd8, 0x8df9, 0x8e16, 0x8e34, 0x8e4c, 0x8e5d, 0x8e7a,
// Entry 5780 - 57BF
0x8e8c, 0x8ea8, 0x8ed3, 0x8eef, 0x8f15, 0x8f2c, 0x8f3e, 0x8f61,
0x8f7d, 0x8f9e, 0x8fb0, 0x8fc2, 0x8fde, 0x8ff0, 0x9003, 0x9017,
0x902c, 0x903d, 0x9053, 0x9069, 0x907b, 0x908c, 0x90a7, 0x90c3,
0x90de, 0x90fa, 0x9115, 0x9130, 0x914b, 0x9166, 0x917f, 0x9190,
0x91a3, 0x91bf, 0x91dc, 0x91fc, 0x921a, 0x9236, 0x9249, 0x9259,
0x926b, 0x927c, 0x928f, 0x92b0, 0x92d5, 0x92e6, 0x92f8, 0x930e,
0x9323, 0x9358, 0x936f, 0x9380, 0x93a1, 0x93b3, 0x93c4, 0x93e0,
0x93fd, 0x941a, 0x9433, 0x9446, 0x9457, 0x9468, 0x947a, 0x948b,
// Entry 57C0 - 57FF
0x94a4, 0x94be, 0x94e1, 0x94fd, 0x9518, 0x9535, 0x9550, 0x956a,
0x9587, 0x95a3, 0x95bd, 0x95d8, 0x95f9, 0x9614, 0x9640, 0x965a,
0x9676, 0x969b, 0x96c5, 0x96df, 0x96fb, 0x9716, 0x9730, 0x974b,
0x9765, 0x9780, 0x979a, 0x97b4, 0x97ce, 0x97f0, 0x9812, 0x9834,
0x984e, 0x9873, 0x988d, 0x98a8, 0x98c2, 0x98dc, 0x98f6, 0x9911,
0x992c, 0x9947, 0x9963, 0x997e, 0x9999, 0x99b6, 0x99d1, 0x99ea,
0x9a04, 0x9a1e, 0x9a43, 0x9a5e, 0x9a78, 0x9a8a, 0x9aa9, 0x9abb,
0x9ace, 0x9ae1, 0x9af4, 0x9b07, 0x9b24, 0x9b36, 0x9b57, 0x9b69,
// Entry 5800 - 583F
0x9b85, 0x9ba4, 0x9bb7, 0x9bca, 0x9bdf, 0x9c15, 0x9c57, 0x9c6b,
0x9c7c, 0x9c97, 0x9cb0, 0x9cca, 0x9cdc, 0x9cee, 0x9d02, 0x9d15,
0x9d2a, 0x9d4b, 0x9d5c, 0x9d96, 0x9da8, 0x9dba, 0x9dd9, 0x9deb,
0x9dfd, 0x9e14, 0x9e26, 0x9e38, 0x9e57, 0x9e6c, 0x9e81, 0x9e92,
0x9ea6, 0x9ec2, 0x9eee, 0x9f13, 0x9f38, 0x9f55, 0x9f72, 0x9f9a,
0x9fb8, 0x9fd5, 0x9ff3, 0xa010, 0xa02d, 0xa04b, 0xa069, 0xa090,
0xa0ad, 0xa0cb, 0xa0f2, 0xa115, 0xa132, 0xa157, 0xa17c, 0xa199,
0xa1b7, 0xa1d5, 0xa1f3, 0xa220, 0xa240, 0xa25f, 0xa27c, 0xa29a,
// Entry 5840 - 587F
0xa2b7, 0xa2dc, 0xa2fb, 0xa318, 0xa33f, 0xa374, 0xa3a3, 0xa3c2,
0xa3eb, 0xa409, 0xa427, 0xa446, 0xa47a, 0xa496, 0xa4b9, 0xa4e3,
0xa509, 0xa526, 0xa544, 0xa560, 0xa574, 0xa592, 0xa5b9, 0xa5d2,
0xa5ff, 0xa614, 0xa626, 0xa642, 0xa654, 0xa670, 0xa694, 0xa6a5,
0xa6b7, 0xa6cc, 0xa6df, 0xa6f0, 0xa70b, 0xa71d, 0xa738, 0xa754,
0xa771, 0xa793, 0xa7b5, 0xa7da, 0xa7f5, 0xa812, 0xa82f, 0xa855,
0xa870, 0xa894, 0xa8b2, 0xa8d5, 0xa8f0, 0xa90b, 0xa92f, 0xa954,
0xa971, 0xa988, 0xa9a7, 0xa9c6, 0xa9e0, 0xa9fa, 0xaa0c, 0xaa20,
// Entry 5880 - 58BF
0xaa3f, 0xaa62, 0xaa7e, 0xaa90, 0xaaa2, 0xaab4, 0xaacf, 0xaaf7,
0xab08, 0xab24, 0xab3a, 0xab4c, 0xab5e, 0xab70, 0xab83, 0xab97,
0xaba8, 0xabba, 0xabcb, 0xabdd, 0xabee, 0xac07, 0xac19, 0xac30,
0xac45, 0xac5a, 0xac6d, 0xac88, 0xaca5, 0xacc1, 0xacde, 0xad0b,
0xad2c, 0xad40, 0xad5c, 0xad80, 0xad9d, 0xadb6, 0xadc7, 0xadd9,
0xadec, 0xae08, 0xae2a, 0xae4b, 0xae5f, 0xae79, 0xae8b, 0xae9e,
0xaeaf, 0xaec8, 0xaee2, 0xaefb, 0xaf0c, 0xaf25, 0xaf37, 0xaf49,
0xaf6b, 0xaf96, 0xafab, 0xafc9, 0xafe8, 0xb010, 0xb02f, 0xb05c,
// Entry 58C0 - 58FF
0xb07a, 0xb099, 0xb0b8, 0xb0e1, 0xb109, 0xb13a, 0xb161, 0xb180,
0xb194, 0xb1a5, 0xb1b8, 0xb1ca, 0xb1ec, 0xb20f, 0xb231, 0xb26c,
0xb28e, 0xb2a5, 0xb2c0, 0xb2df, 0xb30f, 0xb323, 0xb348, 0xb369,
0xb38b, 0xb3ad, 0xb3d4, 0xb3f7, 0xb418, 0xb439, 0xb45d, 0xb47e,
0xb4a2, 0xb4c8, 0xb4d9, 0xb4eb, 0xb4fd, 0xb50f, 0xb523, 0xb534,
0xb54d, 0xb567, 0xb581, 0xb59b, 0xb5b4, 0xb5cd, 0xb5e7, 0xb600,
0xb61a, 0xb637, 0xb64b, 0xb669, 0xb686, 0xb6a3, 0xb6c6, 0xb6d7,
0xb6e9, 0xb6fa, 0xb70b, 0xb71c, 0xb736, 0xb748, 0xb762, 0xb77d,
// Entry 5900 - 593F
0xb799, 0xb7b4, 0xb7d0, 0xb7ec, 0xb808, 0xb823, 0xb83f, 0xb85b,
0xb878, 0xb894, 0xb8af, 0xb8ca, 0xb8e5, 0xb900, 0xb91c, 0xb937,
0xb94e, 0xb960, 0xb983, 0xb998, 0xb9aa, 0xb9bc, 0xb9cf, 0xb9ea,
0xba07, 0xba25, 0xba41, 0xba5f, 0xba7c, 0xba97, 0xbab9, 0xbacc,
0xbae0, 0xbaf4, 0xbb06, 0xbb1b, 0xbb50, 0xbb85, 0xbb99, 0xbbac,
0xbbc0, 0xbbd5, 0xbbec, 0xbbff, 0xbc1a, 0xbc36, 0xbc49, 0xbc64,
0xbc81, 0xbca0, 0xbcbd, 0xbcda, 0xbcf7, 0xbd19, 0xbd39, 0xbd56,
0xbd73, 0xbd90, 0xbda5, 0xbdb8, 0xbdd0, 0xbdfa, 0xbe0e, 0xbe20,
// Entry 5940 - 597F
0xbe44, 0xbe57, 0xbe6c, 0xbe7d, 0xbe93, 0xbea5, 0xbeb8, 0xbeda,
0xbeed, 0xbf01, 0xbf12, 0xbf2b, 0xbf3d, 0xbf50, 0xbf64, 0xbf76,
0xbf8b, 0xbf9d, 0xbfb0, 0xbfc1, 0xbfdb, 0xbff5, 0xc00f, 0xc025,
0xc037, 0xc06c, 0xc086, 0xc098, 0xc0b3, 0xc0cf, 0xc0eb, 0xc107,
0xc124, 0xc13f, 0xc152, 0xc164, 0xc175, 0xc18b, 0xc19c, 0xc1b2,
0xc1c4, 0xc1d6, 0xc1f3, 0xc20e, 0xc243, 0xc254, 0xc267, 0xc279,
0xc28b, 0xc29d, 0xc2c3, 0xc2d3, 0xc2e7, 0xc2fb, 0xc32a, 0xc34e,
0xc380, 0xc391, 0xc3a2, 0xc3b3, 0xc3cb, 0xc3e6, 0xc400, 0xc427,
// Entry 5980 - 59BF
0xc453, 0xc469, 0xc482, 0xc4a5, 0xc4b8, 0xc4c9, 0xc4e6, 0xc508,
0xc524, 0xc53d, 0xc551, 0xc564, 0xc584, 0xc5a0, 0xc5b1, 0xc5c7,
0xc5d8, 0xc5f5, 0xc60e, 0xc620, 0xc642, 0xc664, 0xc67f, 0xc69a,
0xc6b6, 0xc6d1, 0xc6f5, 0xc718, 0xc72a, 0xc73c, 0xc74f, 0xc761,
0xc77b, 0xc79a, 0xc7b6, 0xc7d2, 0xc7ed, 0xc809, 0xc82b, 0xc847,
0xc862, 0xc87d, 0xc899, 0xc8b4, 0xc8d0, 0xc8eb, 0xc907, 0xc923,
0xc93e, 0xc95a, 0xc977, 0xc992, 0xc9b5, 0xc9d0, 0xc9ee, 0xca02,
0xca1e, 0xca30, 0xca4a, 0xca65, 0xca81, 0xca9e, 0xcab1, 0xcac4,
// Entry 59C0 - 59FF
0xcad9, 0xcaed, 0xcaff, 0xcb1e, 0xcb30, 0xcb41, 0xcb57, 0xcb7a,
0xcb8c, 0xcb9f, 0xcbb1, 0xcbc2, 0xcbdb, 0xcbed, 0xcbff, 0xcc1b,
0xcc2d, 0xcc40, 0xcc51, 0xcc63, 0xcc7d, 0xcc91, 0xcca3, 0xccbd,
0xccd8, 0xccf2, 0xcd0f, 0xcd3b, 0xcd4e, 0xcd6a, 0xcd86, 0xcda3,
0xcdc0, 0xcdeb, 0xce08, 0xce1b, 0xce2d, 0xce40, 0xce5d, 0xce79,
0xce95, 0xceb0, 0xced5, 0xcef0, 0xcf0a, 0xcf26, 0xcf40, 0xcf5b,
0xcf78, 0xcf9c, 0xcfc2, 0xcfde, 0xcff1, 0xd00e, 0xd020, 0xd032,
0xd045, 0xd064, 0xd082, 0xd0ac, 0xd0c9, 0xd0dc, 0xd0fd, 0xd10f,
// Entry 5A00 - 5A3F
0xd129, 0xd13b, 0xd159, 0xd179, 0xd198, 0xd1b7, 0xd1d5, 0xd1f5,
0xd215, 0xd234, 0xd255, 0xd275, 0xd295, 0xd2b4, 0xd2d5, 0xd2f6,
0xd316, 0xd333, 0xd350, 0xd36c, 0xd38a, 0xd3a8, 0xd3c5, 0xd3e5,
0xd405, 0xd427, 0xd448, 0xd469, 0xd489, 0xd4ab, 0xd4cd, 0xd4ee,
0xd50e, 0xd52e, 0xd550, 0xd571, 0xd592, 0xd5b2, 0xd5d4, 0xd603,
0xd624, 0xd645, 0xd665, 0xd687, 0xd6a9, 0xd6ca, 0xd6ea, 0xd70a,
0xd72c, 0xd75b, 0xd77c, 0xd79d, 0xd7cd, 0xd7fc, 0xd81b, 0xd83a,
0xd85b, 0xd889, 0xd8a9, 0xd8c9, 0xd8f8, 0xd927, 0xd955, 0xd984,
// Entry 5A40 - 5A7F
0xd9b4, 0xd9e4, 0xda10, 0xda3f, 0xda6f, 0xda9f, 0xdacd, 0xdafc,
0xdb2b, 0xdb5b, 0xdb8b, 0xdbbc, 0xdbdf, 0xdc04, 0xdc28, 0xdc4c,
0xdc6f, 0xdc8e, 0xdcad, 0xdcce, 0xdcee, 0xdd1b, 0xdd3b, 0xdd68,
0xdd88, 0xdda8, 0xddc8, 0xdde8, 0xde0d, 0xde33, 0xde5a, 0xde89,
0xdeb9, 0xdede, 0xdf04, 0xdf31, 0xdf60, 0xdf86, 0xdfa9, 0xdfd1,
0xdffa, 0xe01e, 0xe042, 0xe06c, 0xe096, 0xe0bf, 0xe0ea, 0xe115,
0xe13f, 0xe173, 0xe19c, 0xe1c5, 0xe1f1, 0xe21e, 0xe23e, 0xe25a,
0xe276, 0xe298, 0xe2b7, 0xe2d5, 0xe2f3, 0xe316, 0xe332, 0xe34e,
// Entry 5A80 - 5ABF
0xe36a, 0xe388, 0xe3a4, 0xe3c2, 0xe3de, 0xe402, 0xe41e, 0xe43a,
0xe458, 0xe473, 0xe48e, 0xe4b0, 0xe4cd, 0xe4e8, 0xe503, 0xe524,
0xe543, 0xe55f, 0xe57e, 0xe5a9, 0xe5c9, 0xe5e5, 0xe60b, 0xe631,
0xe64e, 0xe66a, 0xe685, 0xe6a0, 0xe6bb, 0xe6d7, 0xe6f7, 0xe712,
0xe72d, 0xe743, 0xe764, 0xe789, 0xe7ad, 0xe7d7, 0xe7fb, 0xe820,
0xe844, 0xe869, 0xe88d, 0xe8a9, 0xe8c8, 0xe8e9, 0xe914, 0xe93d,
0xe95a, 0xe975, 0xe999, 0xe9bd, 0xe9df, 0xea0a, 0xea26, 0xea4c,
0xea68, 0xea85, 0xeaa0, 0xeac3, 0xeae6, 0xeb03, 0xeb20, 0xeb4a,
// Entry 5AC0 - 5AFF
0xeb68, 0xeb94, 0xebb5, 0xebdc, 0xebf7, 0xec24, 0xec3e, 0xec58,
0xec75, 0xec8f, 0xecb4, 0xecca, 0xece0, 0xecf6, 0xed0c, 0xed22,
0xed38, 0xed4e, 0xed76, 0xed8c, 0xedaf, 0xedc5, 0xeddb, 0xedf1,
0xee07, 0xee1d, 0xee33, 0xee49, 0xee5f, 0xee75, 0xee8b, 0xeea1,
0xeeb7, 0xeecd, 0xeee3, 0xeef9, 0xef0f, 0xef25, 0xef3b, 0xef51,
0xef70, 0xef90, 0xefb9, 0xefeb, 0xf012, 0xf028, 0xf03e, 0xf054,
0xf06a, 0xf080, 0xf096, 0xf0ac, 0xf0c2, 0xf0d8, 0xf0ee, 0xf104,
0xf124, 0xf144, 0xf16f, 0xf18f, 0xf1ae, 0xf1ce, 0xf1ed, 0xf20c,
// Entry 5B00 - 5B3F
0xf22b, 0xf24d, 0xf263, 0xf279, 0xf299, 0xf2b8, 0xf2d8, 0xf2fd,
0xf31c, 0xf34e, 0xf378, 0xf397, 0xf3b9, 0xf3cf, 0xf3e5, 0xf406,
0xf423, 0xf43f, 0xf45b, 0xf489, 0xf4a6, 0xf4c0, 0xf4e6, 0xf50d,
0xf531, 0xf551, 0xf570, 0xf58e, 0xf5af, 0xf5d2, 0xf5f2, 0xf61a,
0xf637, 0xf65b, 0xf67c, 0xf69c, 0xf6b7, 0xf6db, 0xf6f8, 0xf710,
0xf72b, 0xf747, 0xf763, 0xf77e, 0xf7a3, 0xf7c7, 0xf7e3, 0xf7ff,
0xf821, 0xf844, 0xf85f, 0xf87a, 0xf898, 0xf8b8, 0xf8d4, 0xf8e6,
0xf908, 0xf930, 0xf947, 0xf95e, 0xf975, 0xf98c, 0xf9a3, 0xf9ba,
// Entry 5B40 - 5B7F
0xf9d1, 0xf9e8, 0xf9ff, 0xfa16, 0xfa2d, 0xfa45, 0xfa5c, 0xfa73,
0xfa8a, 0xfaa1, 0xfab8, 0xfacf, 0xfae6, 0xfafd, 0xfb14, 0xfb2b,
0xfb42, 0xfb59, 0xfb70, 0xfb87, 0xfb9e, 0xfbb5, 0xfbcc, 0xfbe3,
0xfbfa, 0xfc11, 0xfc28, 0xfc3f, 0xfc56, 0xfc6d, 0xfc84, 0xfc9b,
0xfcb2, 0xfcc9, 0xfce0, 0xfcf7, 0xfd0e, 0xfd25, 0xfd3c, 0xfd53,
0xfd6a, 0xfd81, 0xfd98, 0xfdaf, 0xfdc6, 0xfddd, 0xfdf4, 0xfe0b,
0xfe22, 0xfe39, 0xfe50, 0xfe67, 0xfe7e, 0xfe95, 0xfeac, 0xfec3,
0xfedb, 0xfef2, 0xff09, 0xff20, 0xff37, 0xff4e, 0xff65, 0xff7c,
// Entry 5B80 - 5BBF
0xff93, 0xffaa, 0xffc1, 0xffd8, 0xffef, 0x0006, 0x001d, 0x0034,
0x004b, 0x0062, 0x0079, 0x0090, 0x00a7, 0x00be, 0x00d5, 0x00ec,
0x0103, 0x011a, 0x0131, 0x0148, 0x015f, 0x0176, 0x018d, 0x01a4,
0x01bb, 0x01d2, 0x01e9, 0x0200, 0x0217, 0x022f, 0x0247, 0x025f,
0x0277, 0x028f, 0x02a8, 0x02c0, 0x02d9, 0x02f2, 0x030a, 0x0322,
0x033a, 0x0352, 0x036a, 0x0382, 0x039a, 0x03b2, 0x03cb, 0x03e3,
0x03fb, 0x0413, 0x042c, 0x0444, 0x045c, 0x0474, 0x048c, 0x04a4,
0x04bc, 0x04d4, 0x04ec, 0x0504, 0x051c, 0x0534, 0x054c, 0x0564,
// Entry 5BC0 - 5BFF
0x057c, 0x0594, 0x05ad, 0x05c5, 0x05dd, 0x05f5, 0x060d, 0x0625,
0x063d, 0x0655, 0x066d, 0x0686, 0x069e, 0x06b6, 0x06cf, 0x06e7,
0x0700, 0x0718, 0x0730, 0x0749, 0x0761, 0x0779, 0x0791, 0x07a9,
0x07c1, 0x07d9, 0x07f1, 0x0809, 0x0821, 0x0839, 0x0851, 0x0869,
0x0881, 0x0899, 0x08b1, 0x08c9, 0x08e1, 0x08f9, 0x0911, 0x0929,
0x0941, 0x0959, 0x0971, 0x0989, 0x09a1, 0x09b9, 0x09d1, 0x09e9,
0x0a01, 0x0a19, 0x0a32, 0x0a4a, 0x0a62, 0x0a7a, 0x0a92, 0x0aaa,
0x0ac2, 0x0adb, 0x0af4, 0x0b0d, 0x0b25, 0x0b3d, 0x0b55, 0x0b6d,
// Entry 5C00 - 5C3F
0x0b85, 0x0b9d, 0x0bb5, 0x0bcd, 0x0be6, 0x0bfe, 0x0c16, 0x0c2e,
0x0c46, 0x0c5e, 0x0c76, 0x0c8e, 0x0ca6, 0x0cbe, 0x0cd6, 0x0cee,
0x0d06, 0x0d1e, 0x0d36, 0x0d4e, 0x0d66, 0x0d7e, 0x0d96, 0x0dae,
0x0dc6, 0x0dde, 0x0df6, 0x0e0f, 0x0e27, 0x0e3f, 0x0e57, 0x0e6f,
0x0e87, 0x0e9f, 0x0eb7, 0x0ecf, 0x0ee7, 0x0eff, 0x0f17, 0x0f2f,
0x0f47, 0x0f5f, 0x0f77, 0x0f8f, 0x0fa7, 0x0fbf, 0x0fd7, 0x0ff0,
0x1008, 0x1020, 0x1038, 0x1050, 0x1069, 0x1081, 0x1099, 0x10b1,
0x10ca, 0x10e2, 0x10fa, 0x1112, 0x112a, 0x1142, 0x115a, 0x1172,
// Entry 5C40 - 5C7F
0x118a, 0x11a2, 0x11ba, 0x11d2, 0x11ea, 0x1203, 0x121b, 0x1233,
0x124c, 0x1264, 0x127c, 0x1295, 0x12ae, 0x12c7, 0x12e0, 0x12f9,
0x1312, 0x132b, 0x1344, 0x135d, 0x1375, 0x138d, 0x13a6, 0x13be,
0x13d6, 0x13ef, 0x1407, 0x141f, 0x1437, 0x144f, 0x1467, 0x147f,
0x1497, 0x14af, 0x14c7, 0x14df, 0x14f7, 0x150f, 0x1527, 0x1540,
0x1559, 0x1572, 0x158b, 0x15a4, 0x15bd, 0x15d6, 0x15ef, 0x1607,
0x161f, 0x1637, 0x164f, 0x1667, 0x167f, 0x1697, 0x16af, 0x16c8,
0x16e0, 0x16f9, 0x1711, 0x1729, 0x1741, 0x1759, 0x1771, 0x1789,
// Entry 5C80 - 5CBF
0x17a1, 0x17ba, 0x17d2, 0x17eb, 0x1803, 0x181b, 0x1833, 0x184c,
0x1864, 0x187c, 0x1894, 0x18ac, 0x18c4, 0x18dc, 0x18f4, 0x190c,
0x1925, 0x193d, 0x1955, 0x196d, 0x1985, 0x199d, 0x19b5, 0x19ce,
0x19e6, 0x19fe, 0x1a16, 0x1a2e, 0x1a47, 0x1a5f, 0x1a77, 0x1a8f,
0x1aa7, 0x1abf, 0x1ad7, 0x1aef, 0x1b07, 0x1b1f, 0x1b37, 0x1b4f,
0x1b67, 0x1b80, 0x1b98, 0x1bb0, 0x1bc8, 0x1be0, 0x1bf8, 0x1c10,
0x1c28, 0x1c40, 0x1c59, 0x1c71, 0x1c89, 0x1ca1, 0x1cb9, 0x1cd1,
0x1ce9, 0x1d01, 0x1d19, 0x1d31, 0x1d49, 0x1d62, 0x1d7a, 0x1d92,
// Entry 5CC0 - 5CFF
0x1daa, 0x1dc2, 0x1dda, 0x1df2, 0x1e0b, 0x1e23, 0x1e3c, 0x1e54,
0x1e6c, 0x1e84, 0x1e9c, 0x1eb4, 0x1ecc, 0x1ee4, 0x1efd, 0x1f15,
0x1f2e, 0x1f46, 0x1f5f, 0x1f77, 0x1f8f, 0x1fa7, 0x1fbf, 0x1fd8,
0x1ff1, 0x200a, 0x2022, 0x203a, 0x2052, 0x206a, 0x2082, 0x209a,
0x20b2, 0x20ca, 0x20e3, 0x20fb, 0x2114, 0x212d, 0x2145, 0x215d,
0x2175, 0x218d, 0x21a6, 0x21be, 0x21d6, 0x21ee, 0x2206, 0x221e,
0x2236, 0x224e, 0x2266, 0x227e, 0x2297, 0x22af, 0x22c7, 0x22df,
0x22f7, 0x230f, 0x2327, 0x2340, 0x2358, 0x2370, 0x2388, 0x23a0,
// Entry 5D00 - 5D3F
0x23b8, 0x23d0, 0x23e8, 0x2400, 0x2418, 0x2430, 0x2449, 0x2461,
0x247a, 0x2492, 0x24aa, 0x24c2, 0x24da, 0x24f2, 0x250a, 0x2523,
0x253b, 0x2553, 0x256c, 0x2584, 0x259c, 0x25b4, 0x25cc, 0x25e4,
0x25fc, 0x2614, 0x262c, 0x2644, 0x265c, 0x2674, 0x268c, 0x26a4,
0x26bc, 0x26d4, 0x26ed, 0x2705, 0x271d, 0x2735, 0x274d, 0x2765,
0x277d, 0x2795, 0x27ae, 0x27c6, 0x27de, 0x27f6, 0x280e, 0x2827,
0x283f, 0x2858, 0x2870, 0x2889, 0x28a1, 0x28b9, 0x28d1, 0x28e9,
0x2901, 0x2919, 0x2931, 0x2949, 0x2961, 0x2979, 0x2991, 0x29a9,
// Entry 5D40 - 5D7F
0x29c1, 0x29d9, 0x29f2, 0x2a0a, 0x2a22, 0x2a3a, 0x2a52, 0x2a6b,
0x2a83, 0x2a9b, 0x2ab3, 0x2acc, 0x2ae5, 0x2afd, 0x2b15, 0x2b2e,
0x2b46, 0x2b5e, 0x2b76, 0x2b8e, 0x2ba6, 0x2bbe, 0x2bd6, 0x2bef,
0x2c07, 0x2c1f, 0x2c38, 0x2c51, 0x2c6a, 0x2c83, 0x2c9c, 0x2cb5,
0x2cce, 0x2ce7, 0x2cff, 0x2d17, 0x2d2f, 0x2d48, 0x2d60, 0x2d79,
0x2d91, 0x2daa, 0x2dc2, 0x2dda, 0x2df2, 0x2e0a, 0x2e22, 0x2e3b,
0x2e53, 0x2e6b, 0x2e84, 0x2e9c, 0x2eb4, 0x2ecc, 0x2ee4, 0x2efd,
0x2f15, 0x2f2d, 0x2f45, 0x2f5e, 0x2f76, 0x2f8e, 0x2fa7, 0x2fc0,
// Entry 5D80 - 5DBF
0x2fd8, 0x2ff0, 0x3008, 0x3020, 0x3038, 0x3050, 0x3068, 0x3081,
0x3099, 0x30b1, 0x30c9, 0x30e1, 0x30f9, 0x3111, 0x3129, 0x3141,
0x3159, 0x3171, 0x3189, 0x31a1, 0x31b9, 0x31d1, 0x31e9, 0x3201,
0x3219, 0x3231, 0x3249, 0x3261, 0x3279, 0x3291, 0x32aa, 0x32c3,
0x32db, 0x32f3, 0x330b, 0x3323, 0x333b, 0x3353, 0x336b, 0x3384,
0x339c, 0x33b4, 0x33cc, 0x33e4, 0x33fc, 0x3414, 0x342c, 0x3444,
0x345d, 0x3475, 0x348e, 0x34a6, 0x34bf, 0x34d7, 0x34ef, 0x3508,
0x3520, 0x3538, 0x3550, 0x3568, 0x3580, 0x3599, 0x35b2, 0x35cb,
// Entry 5DC0 - 5DFF
0x35e4, 0x35fd, 0x3617, 0x3630, 0x3649, 0x3662, 0x367b, 0x3694,
0x36ad, 0x36c6, 0x36df, 0x36f8, 0x3711, 0x372a, 0x3743, 0x375d,
0x3776, 0x378f, 0x37a8, 0x37c1, 0x37da, 0x37f3, 0x380c, 0x3825,
0x383e, 0x3857, 0x3870, 0x3889, 0x38a2, 0x38bc, 0x38d5, 0x38ef,
0x3908, 0x3921, 0x393a, 0x3953, 0x396c, 0x3985, 0x399e, 0x39b8,
0x39d1, 0x39ea, 0x3a03, 0x3a1c, 0x3a36, 0x3a4e, 0x3a67, 0x3a7f,
0x3a97, 0x3aaf, 0x3ac7, 0x3ae0, 0x3af8, 0x3b11, 0x3b2a, 0x3b43,
0x3b5c, 0x3b75, 0x3b8e, 0x3ba6, 0x3bbe, 0x3bd6, 0x3bee, 0x3c07,
// Entry 5E00 - 5E3F
0x3c20, 0x3c39, 0x3c51, 0x3c69, 0x3c81, 0x3c99, 0x3cb1, 0x3cc9,
0x3ce1, 0x3cf9, 0x3d11, 0x3d2a, 0x3d42, 0x3d5b, 0x3d73, 0x3d8b,
0x3da3, 0x3dbb, 0x3dd4, 0x3dec, 0x3e05, 0x3e1d, 0x3e35, 0x3e4d,
0x3e65, 0x3e7e, 0x3e96, 0x3eaf, 0x3ec7, 0x3edf, 0x3ef7, 0x3f10,
0x3f28, 0x3f40, 0x3f58, 0x3f71, 0x3f8a, 0x3fa3, 0x3fbc, 0x3fd4,
0x3fec, 0x4004, 0x401c, 0x4034, 0x404c, 0x4064, 0x407c, 0x4094,
0x40ac, 0x40c4, 0x40dc, 0x40f4, 0x410c, 0x4125, 0x413e, 0x4156,
0x416e, 0x4187, 0x419f, 0x41b7, 0x41d0, 0x41e8, 0x4200, 0x4218,
// Entry 5E40 - 5E7F
0x4230, 0x4248, 0x4260, 0x4278, 0x4290, 0x42a8, 0x42c0, 0x42d8,
0x42f0, 0x4308, 0x4320, 0x4338, 0x4350, 0x4368, 0x4381, 0x4399,
0x43b2, 0x43cb, 0x43e3, 0x43fb, 0x4413, 0x442b, 0x4443, 0x445b,
0x4473, 0x448c, 0x44a4, 0x44bc, 0x44d4, 0x44ec, 0x4504, 0x451c,
0x4535, 0x454d, 0x4565, 0x457d, 0x4595, 0x45ad, 0x45c5, 0x45dd,
0x45f5, 0x460d, 0x4625, 0x463d, 0x4655, 0x466d, 0x4685, 0x469d,
0x46b6, 0x46ce, 0x46e6, 0x46fe, 0x4716, 0x472f, 0x4747, 0x475f,
0x4777, 0x478f, 0x47a7, 0x47bf, 0x47d7, 0x47ef, 0x4808, 0x4821,
// Entry 5E80 - 5EBF
0x4839, 0x4851, 0x4869, 0x4882, 0x489a, 0x48b2, 0x48ca, 0x48e2,
0x48fa, 0x4912, 0x492a, 0x4942, 0x495a, 0x4973, 0x498c, 0x49a4,
0x49bc, 0x49d4, 0x49ec, 0x4a04, 0x4a1c, 0x4a34, 0x4a4c, 0x4a64,
0x4a7d, 0x4a95, 0x4aad, 0x4ac5, 0x4add, 0x4af5, 0x4b0d, 0x4b25,
0x4b3d, 0x4b55, 0x4b6d, 0x4b85, 0x4b9d, 0x4bb5, 0x4bcd, 0x4be6,
0x4bfe, 0x4c16, 0x4c2e, 0x4c46, 0x4c5f, 0x4c77, 0x4c90, 0x4ca8,
0x4cc1, 0x4cd9, 0x4cf1, 0x4d0a, 0x4d22, 0x4d3a, 0x4d52, 0x4d6a,
0x4d82, 0x4d9b, 0x4db3, 0x4dcb, 0x4de3, 0x4dfb, 0x4e13, 0x4e2b,
// Entry 5EC0 - 5EFF
0x4e43, 0x4e5b, 0x4e73, 0x4e8b, 0x4ea3, 0x4ebb, 0x4ed3, 0x4eeb,
0x4f03, 0x4f1b, 0x4f34, 0x4f4c, 0x4f65, 0x4f7d, 0x4f95, 0x4fad,
0x4fc5, 0x4fdd, 0x4ff5, 0x500d, 0x5025, 0x503d, 0x5056, 0x506f,
0x5087, 0x509f, 0x50b7, 0x50cf, 0x50e7, 0x50ff, 0x5117, 0x512f,
0x5147, 0x515f, 0x5177, 0x518f, 0x51a7, 0x51bf, 0x51d7, 0x51ef,
0x5207, 0x5220, 0x5238, 0x5250, 0x5268, 0x5280, 0x5298, 0x52b0,
0x52c9, 0x52e1, 0x52f9, 0x5311, 0x532a, 0x5342, 0x535a, 0x5372,
0x538a, 0x53a2, 0x53ba, 0x53d2, 0x53ea, 0x5402, 0x541a, 0x5432,
// Entry 5F00 - 5F3F
0x544b, 0x5464, 0x547d, 0x5496, 0x54af, 0x54c8, 0x54e1, 0x54fa,
0x5513, 0x552b, 0x5544, 0x555c, 0x5574, 0x558c, 0x55a4, 0x55bc,
0x55d5, 0x55ee, 0x5606, 0x561e, 0x5636, 0x564e, 0x5667, 0x5680,
0x5699, 0x56b1, 0x56ca, 0x56e3, 0x56fb, 0x5713, 0x572b, 0x5743,
0x575b, 0x5773, 0x578b, 0x57a3, 0x57bc, 0x57d5, 0x57ee, 0x5807,
0x5820, 0x5839, 0x5852, 0x586b, 0x5884, 0x589d, 0x58b6, 0x58cf,
0x58e7, 0x58ff, 0x5917, 0x5930, 0x5948, 0x5960, 0x5978, 0x5990,
0x59a8, 0x59c1, 0x59d9, 0x59f2, 0x5a0a, 0x5a23, 0x5a3b, 0x5a54,
// Entry 5F40 - 5F7F
0x5a6c, 0x5a84, 0x5a9d, 0x5ab5, 0x5acd, 0x5ae5, 0x5afd, 0x5b16,
0x5b2e, 0x5b46, 0x5b5e, 0x5b77, 0x5b8f, 0x5ba7, 0x5bbf, 0x5bd8,
0x5bf0, 0x5c08, 0x5c20, 0x5c38, 0x5c50, 0x5c68, 0x5c81, 0x5c99,
0x5cb2, 0x5cca, 0x5ce2, 0x5cfa, 0x5d12, 0x5d2b, 0x5d43, 0x5d5b,
0x5d73, 0x5d8c, 0x5da4, 0x5dbd, 0x5dd5, 0x5ded, 0x5e05, 0x5e1d,
0x5e35, 0x5e4d, 0x5e66, 0x5e7e, 0x5e96, 0x5eae, 0x5ec6, 0x5ede,
0x5ef7, 0x5f10, 0x5f28, 0x5f40, 0x5f59, 0x5f71, 0x5f89, 0x5fa2,
0x5fba, 0x5fd3, 0x5feb, 0x6003, 0x601b, 0x6033, 0x604b, 0x6063,
// Entry 5F80 - 5FBF
0x607b, 0x6093, 0x60ab, 0x60c4, 0x60dd, 0x60f6, 0x610f, 0x6127,
0x6140, 0x6159, 0x6171, 0x618a, 0x61a2, 0x61bb, 0x61d3, 0x61eb,
0x6203, 0x621b, 0x6233, 0x624b, 0x6263, 0x627b, 0x6293, 0x62ab,
0x62c4, 0x62dd, 0x62f6, 0x630f, 0x6328, 0x6341, 0x635a, 0x6373,
0x638c, 0x63a4, 0x63bd, 0x63d6, 0x63ef, 0x6408, 0x6421, 0x643a,
0x6453, 0x646c, 0x6485, 0x649e, 0x64b7, 0x64d0, 0x64e9, 0x6502,
0x651b, 0x6535, 0x654f, 0x6568, 0x6581, 0x659a, 0x65b3, 0x65cc,
0x65e5, 0x65fe, 0x6617, 0x6630, 0x6649, 0x6662, 0x667b, 0x6694,
// Entry 5FC0 - 5FFF
0x66ad, 0x66c6, 0x66df, 0x66f8, 0x6711, 0x672a, 0x6743, 0x675c,
0x6775, 0x678e, 0x67a7, 0x67c0, 0x67d9, 0x67fc, 0x6821, 0x6848,
0x6872, 0x6897, 0x68bf, 0x68e1, 0x6902, 0x6921, 0x6945, 0x6966,
0x698a, 0x69ad, 0x69ce, 0x69f8, 0x6a20, 0x6a47, 0x6a65, 0x6a83,
0x6aa0, 0x6ac2, 0x6ae4, 0x6b06, 0x6b37, 0x6b6b, 0x6b98, 0x6bc7,
0x6bf2, 0x6c32, 0x6c67, 0x6c99, 0x6cd9, 0x6d07, 0x6d3f, 0x6d6a,
0x6d9d, 0x6dd3, 0x6df7, 0x6e10, 0x6e29, 0x6e42, 0x6e5b, 0x6e74,
0x6e8d, 0x6ea6, 0x6ebf, 0x6ed8, 0x6ef1, 0x6f0a, 0x6f23, 0x6f3c,
// Entry 6000 - 603F
0x6f55, 0x6f6e, 0x6f87, 0x6fa0, 0x6fb9, 0x6fd2, 0x6feb, 0x7004,
0x701d, 0x7036, 0x704f, 0x7068, 0x7081, 0x709a, 0x70b3, 0x70cc,
0x70e5, 0x70fe, 0x7117, 0x7130, 0x7149, 0x7162, 0x717b, 0x7194,
0x71ad, 0x71c6, 0x71df, 0x71f8, 0x7211, 0x722a, 0x7243, 0x725c,
0x7275, 0x728e, 0x72a7, 0x72c0, 0x72d9, 0x72f2, 0x730b, 0x7324,
0x733d, 0x7356, 0x736f, 0x7388, 0x73a1, 0x73ba, 0x73d3, 0x73ec,
0x7405, 0x741e, 0x7437, 0x7450, 0x7469, 0x7482, 0x749b, 0x74b4,
0x74cd, 0x74e6, 0x74ff, 0x7518, 0x7531, 0x754a, 0x7563, 0x757c,
// Entry 6040 - 607F
0x7595, 0x75ae, 0x75c7, 0x75e0, 0x75f9, 0x7612, 0x762b, 0x7644,
0x765d, 0x7676, 0x768f, 0x76a8, 0x76c1, 0x76da, 0x76f3, 0x770c,
0x7725, 0x773e, 0x7757, 0x7770, 0x7789, 0x77a2, 0x77bb, 0x77d4,
0x77ed, 0x7806, 0x781f, 0x7838, 0x7851, 0x786a, 0x7883, 0x789c,
0x78b5, 0x78ce, 0x78e7, 0x7900, 0x7919, 0x7932, 0x794b, 0x7964,
0x797d, 0x7996, 0x79af, 0x79c8, 0x79e1, 0x79fa, 0x7a13, 0x7a2c,
0x7a45, 0x7a5e, 0x7a77, 0x7a90, 0x7aa9, 0x7ac2, 0x7adb, 0x7af4,
0x7b0d, 0x7b26, 0x7b3f, 0x7b58, 0x7b71, 0x7b8a, 0x7ba3, 0x7bbc,
// Entry 6080 - 60BF
0x7bd5, 0x7bee, 0x7c07, 0x7c20, 0x7c39, 0x7c52, 0x7c6b, 0x7c84,
0x7c9d, 0x7cb6, 0x7ccf, 0x7ce8, 0x7d01, 0x7d1a, 0x7d33, 0x7d4c,
0x7d65, 0x7d7e, 0x7d97, 0x7db0, 0x7dc9, 0x7de2, 0x7dfb, 0x7e14,
0x7e2d, 0x7e46, 0x7e5f, 0x7e78, 0x7e91, 0x7eaa, 0x7ec3, 0x7edc,
0x7ef5, 0x7f0e, 0x7f27, 0x7f40, 0x7f59, 0x7f72, 0x7f8b, 0x7fa4,
0x7fbd, 0x7fd6, 0x7fef, 0x8008, 0x8021, 0x803a, 0x8053, 0x806c,
0x8085, 0x809e, 0x80b7, 0x80d0, 0x80e9, 0x8102, 0x811b, 0x8134,
0x814d, 0x8166, 0x817f, 0x8198, 0x81b1, 0x81ca, 0x81e3, 0x81fc,
// Entry 60C0 - 60FF
0x8215, 0x822e, 0x8247, 0x8260, 0x8279, 0x8292, 0x82ab, 0x82c4,
0x82dd, 0x82f6, 0x830f, 0x8328, 0x8341, 0x835a, 0x8373, 0x838c,
0x83a5, 0x83be, 0x83d7, 0x83f0, 0x8409, 0x8422, 0x843b, 0x8454,
0x846d, 0x8486, 0x849f, 0x84b8, 0x84d1, 0x84ea, 0x8503, 0x851c,
0x8535, 0x854e, 0x8567, 0x8580, 0x8599, 0x85b2, 0x85cb, 0x85e4,
0x85fd, 0x8616, 0x862f, 0x8648, 0x8661, 0x867a, 0x8693, 0x86ac,
0x86c5, 0x86de, 0x86f7, 0x8710, 0x8729, 0x8742, 0x875b, 0x8774,
0x878d, 0x87a6, 0x87bf, 0x87d8, 0x87f1, 0x880a, 0x8823, 0x883c,
// Entry 6100 - 613F
0x8855, 0x886e, 0x8887, 0x88a0, 0x88b9, 0x88d2, 0x88eb, 0x8904,
0x891d, 0x8936, 0x894f, 0x8968, 0x8981, 0x899a, 0x89b3, 0x89cc,
0x89e5, 0x89fe, 0x8a17, 0x8a30, 0x8a49, 0x8a62, 0x8a7b, 0x8a94,
0x8aad, 0x8ac6, 0x8adf, 0x8af8, 0x8b11, 0x8b2a, 0x8b43, 0x8b5c,
0x8b75, 0x8b8e, 0x8ba7, 0x8bc0, 0x8bd9, 0x8bf2, 0x8c0b, 0x8c24,
0x8c3d, 0x8c56, 0x8c6f, 0x8c88, 0x8ca1, 0x8cba, 0x8cd3, 0x8cec,
0x8d05, 0x8d1e, 0x8d37, 0x8d50, 0x8d69, 0x8d82, 0x8d9b, 0x8db4,
0x8dcd, 0x8de6, 0x8dff, 0x8e18, 0x8e31, 0x8e4a, 0x8e63, 0x8e7c,
// Entry 6140 - 617F
0x8e95, 0x8eae, 0x8ec7, 0x8ee0, 0x8ef9, 0x8f12, 0x8f2b, 0x8f44,
0x8f5d, 0x8f76, 0x8f8f, 0x8fa8, 0x8fc1, 0x8fda, 0x8ff3, 0x900c,
0x9025, 0x903e, 0x9057, 0x9070, 0x9089, 0x90a2, 0x90bb, 0x90d4,
0x90ed, 0x9106, 0x911f, 0x9138, 0x9151, 0x916a, 0x9183, 0x919c,
0x91b5, 0x91ce, 0x91e7, 0x9200, 0x9219, 0x9232, 0x924b, 0x9264,
0x927d, 0x9296, 0x92af, 0x92c8, 0x92e1, 0x92fa, 0x9313, 0x932c,
0x9345, 0x935e, 0x9377, 0x9390, 0x93a9, 0x93c2, 0x93db, 0x93f4,
0x940d, 0x9426, 0x943f, 0x9458, 0x9471, 0x948a, 0x94a3, 0x94bc,
// Entry 6180 - 61BF
0x94d5, 0x94ee, 0x9507, 0x9520, 0x9539, 0x9552, 0x956b, 0x9584,
0x959d, 0x95b6, 0x95cf, 0x95e8, 0x9601, 0x961a, 0x9633, 0x964c,
0x9665, 0x967e, 0x9697, 0x96b0, 0x96c9, 0x96e2, 0x96fb, 0x9714,
0x972d, 0x9746, 0x975f, 0x9778, 0x9791, 0x97aa, 0x97c3, 0x97dc,
0x97f5, 0x980e, 0x9827, 0x9840, 0x9859, 0x9872, 0x988b, 0x98a4,
0x98bd, 0x98d6, 0x98ef, 0x9908, 0x9921, 0x993a, 0x9953, 0x996c,
0x9985, 0x999e, 0x99b7, 0x99d0, 0x99e9, 0x9a02, 0x9a1b, 0x9a34,
0x9a4d, 0x9a66, 0x9a7f, 0x9a98, 0x9ab1, 0x9aca, 0x9ae3, 0x9afc,
// Entry 61C0 - 61FF
0x9b15, 0x9b2e, 0x9b47, 0x9b60, 0x9b79, 0x9b92, 0x9bab, 0x9bc4,
0x9bdd, 0x9bf6, 0x9c0f, 0x9c28, 0x9c41, 0x9c5a, 0x9c73, 0x9c8c,
0x9ca5, 0x9cbe, 0x9cd7, 0x9cf0, 0x9d09, 0x9d22, 0x9d3b, 0x9d54,
0x9d6d, 0x9d86, 0x9d9f, 0x9db8, 0x9dd1, 0x9dea, 0x9e03, 0x9e1c,
0x9e35, 0x9e4e, 0x9e67, 0x9e80, 0x9e99, 0x9eb2, 0x9ecb, 0x9ee4,
0x9efd, 0x9f16, 0x9f2f, 0x9f48, 0x9f61, 0x9f7a, 0x9f93, 0x9fac,
0x9fc5, 0x9fde, 0x9ff7, 0xa010, 0xa029, 0xa042, 0xa05b, 0xa074,
0xa08d, 0xa0a6, 0xa0bf, 0xa0d8, 0xa0f1, 0xa10a, 0xa123, 0xa13c,
// Entry 6200 - 623F
0xa155, 0xa16e, 0xa187, 0xa1a0, 0xa1b9, 0xa1d2, 0xa1eb, 0xa204,
0xa21d, 0xa236, 0xa24f, 0xa268, 0xa281, 0xa29a, 0xa2b3, 0xa2cc,
0xa2e5, 0xa2fe, 0xa317, 0xa330, 0xa349, 0xa362, 0xa37b, 0xa394,
0xa3ad, 0xa3c6, 0xa3df, 0xa3f8, 0xa411, 0xa42a, 0xa443, 0xa45c,
0xa475, 0xa48e, 0xa4a7, 0xa4c0, 0xa4d9, 0xa4f2, 0xa50b, 0xa524,
0xa53d, 0xa556, 0xa56f, 0xa588, 0xa5a1, 0xa5ba, 0xa5d3, 0xa5ec,
0xa605, 0xa61e, 0xa637, 0xa650, 0xa669, 0xa682, 0xa69b, 0xa6b4,
0xa6cd, 0xa6e6, 0xa6ff, 0xa718, 0xa731, 0xa74a, 0xa763, 0xa77c,
// Entry 6240 - 627F
0xa795, 0xa7ae, 0xa7c7, 0xa7e0, 0xa7f9, 0xa812, 0xa82b, 0xa844,
0xa85d, 0xa876, 0xa88f, 0xa8a8, 0xa8c1, 0xa8da, 0xa8f3, 0xa90c,
0xa925, 0xa93e, 0xa957, 0xa970, 0xa989, 0xa9a2, 0xa9bb, 0xa9d4,
0xa9ed, 0xaa06, 0xaa1f, 0xaa38, 0xaa51, 0xaa6a, 0xaa83, 0xaa9c,
0xaab5, 0xaace, 0xaae7, 0xab00, 0xab19, 0xab32, 0xab4b, 0xab64,
0xab7d, 0xab96, 0xabaf, 0xabc8, 0xabe1, 0xabfa, 0xac13, 0xac2c,
0xac45, 0xac5e, 0xac77, 0xac90, 0xaca9, 0xacc2, 0xacdb, 0xacf4,
0xad0d, 0xad26, 0xad3f, 0xad58, 0xad71, 0xad8a, 0xada3, 0xadbc,
// Entry 6280 - 62BF
0xadd5, 0xadee, 0xae07, 0xae20, 0xae39, 0xae52, 0xae6b, 0xae84,
0xae9d, 0xaeb6, 0xaecf, 0xaee8, 0xaf01, 0xaf1a, 0xaf33, 0xaf4c,
0xaf65, 0xaf7e, 0xaf97, 0xafb0, 0xafc9, 0xafe2, 0xaffb, 0xb014,
0xb02d, 0xb046, 0xb05f, 0xb078, 0xb091, 0xb0aa, 0xb0c3, 0xb0dc,
0xb0f5, 0xb10e, 0xb127, 0xb140, 0xb159, 0xb172, 0xb18b, 0xb1a4,
0xb1bd, 0xb1d6, 0xb1ef, 0xb208, 0xb221, 0xb23a, 0xb253, 0xb26c,
0xb285, 0xb29e, 0xb2b7, 0xb2d0, 0xb2e9, 0xb302, 0xb31b, 0xb334,
0xb34d, 0xb366, 0xb37f, 0xb398, 0xb3b1, 0xb3ca, 0xb3e3, 0xb3fc,
// Entry 62C0 - 62FF
0xb415, 0xb42e, 0xb447, 0xb460, 0xb479, 0xb492, 0xb4ab, 0xb4c4,
0xb4dd, 0xb4f6, 0xb50f, 0xb528, 0xb541, 0xb55a, 0xb573, 0xb58c,
0xb5a5, 0xb5be, 0xb5d7, 0xb5f0, 0xb609, 0xb622, 0xb63b, 0xb654,
0xb66d, 0xb686, 0xb69f, 0xb6b8, 0xb6d1, 0xb6ea, 0xb703, 0xb71c,
0xb735, 0xb74e, 0xb767, 0xb780, 0xb799, 0xb7b2, 0xb7cb, 0xb7e4,
0xb7fd, 0xb816, 0xb82f, 0xb848, 0xb861, 0xb87a, 0xb893, 0xb8ac,
0xb8c5, 0xb8de, 0xb8f7, 0xb910, 0xb929, 0xb942, 0xb95b, 0xb974,
0xb98d, 0xb9a6, 0xb9bf, 0xb9d8, 0xb9f1, 0xba0a, 0xba23, 0xba3c,
// Entry 6300 - 633F
0xba55, 0xba6e, 0xba87, 0xbaa0, 0xbab9, 0xbad2, 0xbaeb, 0xbb04,
0xbb1d, 0xbb36, 0xbb4f, 0xbb68, 0xbb81, 0xbb9a, 0xbbb3, 0xbbcc,
0xbbe5, 0xbbfe, 0xbc17, 0xbc30, 0xbc49, 0xbc62, 0xbc7b, 0xbc94,
0xbcad, 0xbcc6, 0xbcdf, 0xbcf8, 0xbd11, 0xbd2a, 0xbd43, 0xbd5c,
0xbd75, 0xbd8e, 0xbda7, 0xbdc0, 0xbdd9, 0xbdf2, 0xbe0b, 0xbe24,
0xbe3d, 0xbe56, 0xbe6f, 0xbe88, 0xbea1, 0xbeba, 0xbed3, 0xbeec,
0xbf05, 0xbf1e, 0xbf37, 0xbf50, 0xbf69, 0xbf82, 0xbf9b, 0xbfb4,
0xbfcd, 0xbfe6, 0xbfff, 0xc018, 0xc031, 0xc04a, 0xc063, 0xc07c,
// Entry 6340 - 637F
0xc095, 0xc0ae, 0xc0c7, 0xc0e0, 0xc0f9, 0xc112, 0xc12b, 0xc144,
0xc15d, 0xc176, 0xc18f, 0xc1a8, 0xc1c1, 0xc1da, 0xc1f3, 0xc20c,
0xc225, 0xc23e, 0xc257, 0xc270, 0xc289, 0xc2a2, 0xc2bb, 0xc2d4,
0xc2ed, 0xc306, 0xc31f, 0xc338, 0xc351, 0xc36a, 0xc383, 0xc39c,
0xc3b5, 0xc3ce, 0xc3e7, 0xc400, 0xc419, 0xc432, 0xc44b, 0xc464,
0xc47d, 0xc496, 0xc4af, 0xc4c8, 0xc4e1, 0xc4fa, 0xc513, 0xc52c,
0xc545, 0xc55e, 0xc577, 0xc590, 0xc5a9, 0xc5c2, 0xc5db, 0xc5f4,
0xc60d, 0xc626, 0xc63f, 0xc658, 0xc671, 0xc68a, 0xc6a3, 0xc6bc,
// Entry 6380 - 63BF
0xc6d5, 0xc6ee, 0xc707, 0xc720, 0xc739, 0xc752, 0xc76b, 0xc784,
0xc79d, 0xc7b6, 0xc7cf, 0xc7e8, 0xc801, 0xc81a, 0xc833, 0xc84c,
0xc865, 0xc87e, 0xc897, 0xc8b0, 0xc8c9, 0xc8e2, 0xc8fb, 0xc914,
0xc92d, 0xc946, 0xc95f, 0xc978, 0xc991, 0xc9aa, 0xc9c3, 0xc9dc,
0xc9f5, 0xca0e, 0xca27, 0xca40, 0xca59, 0xca72, 0xca8b, 0xcaa4,
0xcabd, 0xcad6, 0xcaef, 0xcb08, 0xcb21, 0xcb3a, 0xcb53, 0xcb6c,
0xcb85, 0xcb9e, 0xcbb7, 0xcbd0, 0xcbe9, 0xcc02, 0xcc1b, 0xcc34,
0xcc4d, 0xcc66, 0xcc7f, 0xcc98, 0xccb1, 0xccca, 0xcce3, 0xccfc,
// Entry 63C0 - 63FF
0xcd15, 0xcd2e, 0xcd47, 0xcd60, 0xcd79, 0xcd92, 0xcdab, 0xcdc4,
0xcddd, 0xcdf6, 0xce0f, 0xce28, 0xce41, 0xce5a, 0xce73, 0xce8c,
0xcea5, 0xcebe, 0xced7, 0xcef0, 0xcf09, 0xcf22, 0xcf3b, 0xcf54,
0xcf6d, 0xcf86, 0xcf9f, 0xcfb8, 0xcfd1, 0xcfea, 0xd003, 0xd01c,
0xd035, 0xd04e, 0xd067, 0xd080, 0xd099, 0xd0b2, 0xd0cb, 0xd0e4,
0xd0fd, 0xd116, 0xd12f, 0xd148, 0xd161, 0xd17a, 0xd193, 0xd1ac,
0xd1c5, 0xd1de, 0xd1f7, 0xd210, 0xd229, 0xd242, 0xd25b, 0xd274,
0xd28d, 0xd2a6, 0xd2bf, 0xd2d8, 0xd2f1, 0xd30a, 0xd323, 0xd33c,
// Entry 6400 - 643F
0xd355, 0xd36e, 0xd387, 0xd3a0, 0xd3b9, 0xd3d2, 0xd3eb, 0xd404,
0xd41d, 0xd436, 0xd44f, 0xd468, 0xd481, 0xd49a, 0xd4b3, 0xd4cc,
0xd4e5, 0xd4fe, 0xd517, 0xd530, 0xd549, 0xd562, 0xd57b, 0xd594,
0xd5ad, 0xd5c6, 0xd5df, 0xd5f8, 0xd611, 0xd62a, 0xd643, 0xd65c,
0xd675, 0xd68e, 0xd6a7, 0xd6c0, 0xd6d9, 0xd6f2, 0xd70b, 0xd724,
0xd73d, 0xd756, 0xd76f, 0xd788, 0xd7a1, 0xd7ba, 0xd7d3, 0xd7ec,
0xd805, 0xd81e, 0xd837, 0xd850, 0xd869, 0xd882, 0xd89b, 0xd8b4,
0xd8cd, 0xd8e6, 0xd8ff, 0xd918, 0xd931, 0xd94a, 0xd963, 0xd97c,
// Entry 6440 - 647F
0xd995, 0xd9ae, 0xd9c7, 0xd9e0, 0xd9f9, 0xda12, 0xda2b, 0xda44,
0xda5d, 0xda76, 0xda8f, 0xdaa8, 0xdac1, 0xdada, 0xdaf3, 0xdb0c,
0xdb25, 0xdb3e, 0xdb57, 0xdb70, 0xdb89, 0xdba2, 0xdbbb, 0xdbd4,
0xdbed, 0xdc06, 0xdc1f, 0xdc38, 0xdc51, 0xdc6a, 0xdc83, 0xdc9c,
0xdcb5, 0xdcce, 0xdce7, 0xdd00, 0xdd19, 0xdd32, 0xdd4b, 0xdd64,
0xdd7d, 0xdd96, 0xddaf, 0xddc8, 0xdde1, 0xddfa, 0xde13, 0xde2c,
0xde45, 0xde5e, 0xde77, 0xde90, 0xdea9, 0xdec2, 0xdedb, 0xdef4,
0xdf0d, 0xdf26, 0xdf3f, 0xdf58, 0xdf71, 0xdf8a, 0xdfa3, 0xdfbc,
// Entry 6480 - 64BF
0xdfd5, 0xdfee, 0xe007, 0xe020, 0xe039, 0xe052, 0xe06b, 0xe084,
0xe09d, 0xe0b6, 0xe0cf, 0xe0e8, 0xe101, 0xe11a, 0xe133, 0xe14c,
0xe165, 0xe17e, 0xe197, 0xe1b0, 0xe1c9, 0xe1e2, 0xe1fb, 0xe214,
0xe22d, 0xe246, 0xe25f, 0xe278, 0xe291, 0xe2aa, 0xe2c3, 0xe2dc,
0xe2f5, 0xe30e, 0xe327, 0xe340, 0xe359, 0xe372, 0xe38b, 0xe3a4,
0xe3bd, 0xe3d6, 0xe3ef, 0xe408, 0xe421, 0xe43a, 0xe453, 0xe46c,
0xe485, 0xe49e, 0xe4b7, 0xe4d0, 0xe4e9, 0xe502, 0xe51b, 0xe534,
0xe54d, 0xe566, 0xe57f, 0xe598, 0xe5b1, 0xe5ca, 0xe5e3, 0xe5fc,
// Entry 64C0 - 64FF
0xe615, 0xe62e, 0xe647, 0xe660, 0xe679, 0xe692, 0xe6ab, 0xe6c4,
0xe6dd, 0xe6f6, 0xe70f, 0xe728, 0xe741, 0xe75a, 0xe773, 0xe78c,
0xe7a5, 0xe7be, 0xe7d7, 0xe7f0, 0xe809, 0xe822, 0xe83b, 0xe854,
0xe86d, 0xe886, 0xe89f, 0xe8b8, 0xe8d1, 0xe8ea, 0xe903, 0xe91c,
0xe935, 0xe94e, 0xe967, 0xe980, 0xe999, 0xe9b2, 0xe9cb, 0xe9e4,
0xe9fd, 0xea16, 0xea2f, 0xea48, 0xea61, 0xea7a, 0xea93, 0xeaac,
0xeac5, 0xeade, 0xeaf7, 0xeb10, 0xeb29, 0xeb42, 0xeb5b, 0xeb74,
0xeb8d, 0xeba6, 0xebbf, 0xebd8, 0xebf1, 0xec0a, 0xec23, 0xec3c,
// Entry 6500 - 653F
0xec55, 0xec6e, 0xec87, 0xeca0, 0xecb9, 0xecd2, 0xeceb, 0xed04,
0xed1d, 0xed36, 0xed4f, 0xed68, 0xed81, 0xed9a, 0xedb3, 0xedcc,
0xede5, 0xedfe, 0xee17, 0xee30, 0xee49, 0xee62, 0xee7b, 0xee94,
0xeead, 0xeec6, 0xeedf, 0xeef8, 0xef11, 0xef2a, 0xef43, 0xef5c,
0xef75, 0xef8e, 0xefa7, 0xefc0, 0xefd9, 0xeff2, 0xf00b, 0xf024,
0xf03d, 0xf056, 0xf06f, 0xf088, 0xf0a1, 0xf0ba, 0xf0d3, 0xf0ec,
0xf105, 0xf11e, 0xf137, 0xf150, 0xf169, 0xf182, 0xf19b, 0xf1b4,
0xf1cd, 0xf1e6, 0xf1ff, 0xf218, 0xf231, 0xf24a, 0xf263, 0xf27c,
// Entry 6540 - 657F
0xf295, 0xf2ae, 0xf2c7, 0xf2e0, 0xf2f9, 0xf312, 0xf32b, 0xf344,
0xf35d, 0xf376, 0xf38f, 0xf3a8, 0xf3c1, 0xf3da, 0xf3f3, 0xf40c,
0xf425, 0xf43e, 0xf457, 0xf470, 0xf489, 0xf4a2, 0xf4bb, 0xf4d4,
0xf4ed, 0xf506, 0xf51f, 0xf538, 0xf551, 0xf56a, 0xf583, 0xf59c,
0xf5b5, 0xf5ce, 0xf5e7, 0xf600, 0xf619, 0xf632, 0xf64b, 0xf664,
0xf67d, 0xf696, 0xf6af, 0xf6c8, 0xf6e1, 0xf6fa, 0xf713, 0xf72c,
0xf745, 0xf75e, 0xf777, 0xf790, 0xf7a9, 0xf7c2, 0xf7db, 0xf7f4,
0xf80d, 0xf826, 0xf83f, 0xf858, 0xf871, 0xf88a, 0xf8a3, 0xf8bc,
// Entry 6580 - 65BF
0xf8d5, 0xf8ee, 0xf907, 0xf920, 0xf939, 0xf952, 0xf96b, 0xf984,
0xf99d, 0xf9b6, 0xf9cf, 0xf9e8, 0xfa01, 0xfa1a, 0xfa33, 0xfa4c,
0xfa65, 0xfa7e, 0xfa97, 0xfab0, 0xfac9, 0xfae2, 0xfafb, 0xfb14,
0xfb2d, 0xfb46, 0xfb5f, 0xfb78, 0xfb91, 0xfbaa, 0xfbc3, 0xfbdc,
0xfbf5, 0xfc0e, 0xfc27, 0xfc40, 0xfc59, 0xfc72, 0xfc8b, 0xfca4,
0xfcbd, 0xfcd6, 0xfcef, 0xfd08, 0xfd21, 0xfd3a, 0xfd53, 0xfd6c,
0xfd85, 0xfd9e, 0xfdb7, 0xfdd0, 0xfde9, 0xfe02, 0xfe1b, 0xfe34,
0xfe4d, 0xfe66, 0xfe7f, 0xfe98, 0xfeb1, 0xfeca, 0xfee3, 0xfefc,
// Entry 65C0 - 65FF
0xff15, 0xff2e, 0xff47, 0xff60, 0xff79, 0xff92, 0xffab, 0xffc4,
0xffdd, 0xfff6, 0x000f, 0x0028, 0x0041, 0x005a, 0x0073, 0x008c,
0x00a5, 0x00be, 0x00d7, 0x00f0, 0x0109, 0x0122, 0x013b, 0x0154,
0x016d, 0x0186, 0x019f, 0x01b8, 0x01d1, 0x01ea, 0x0203, 0x021c,
0x0235, 0x024e, 0x0267, 0x0280, 0x0299, 0x02b2, 0x02cb, 0x02e4,
0x02fd, 0x0316, 0x032f, 0x0348, 0x0361, 0x037a, 0x0393, 0x03ac,
0x03c5, 0x03de, 0x03f7, 0x0410, 0x0429, 0x0442, 0x045b, 0x0474,
0x048d, 0x04a6, 0x04bf, 0x04d8, 0x04f1, 0x050a, 0x0523, 0x053c,
// Entry 6600 - 663F
0x0555, 0x056e, 0x0587, 0x05a0, 0x05b9, 0x05d2, 0x05eb, 0x0604,
0x061d, 0x0636, 0x064f, 0x0668, 0x0681, 0x069a, 0x06b3, 0x06cc,
0x06e5, 0x06fe, 0x0717, 0x0730, 0x0749, 0x0762, 0x077b, 0x0794,
0x07ad, 0x07c6, 0x07df, 0x07f8, 0x0811, 0x082a, 0x0843, 0x085c,
0x0875, 0x088e, 0x08a7, 0x08c0, 0x08d9, 0x08f2, 0x090b, 0x0924,
0x093d, 0x0956, 0x096f, 0x0988, 0x09a1, 0x09ba, 0x09d3, 0x09ec,
0x0a05, 0x0a1e, 0x0a37, 0x0a50, 0x0a69, 0x0a82, 0x0a9b, 0x0ab4,
0x0acd, 0x0ae6, 0x0aff, 0x0b18, 0x0b31, 0x0b4a, 0x0b63, 0x0b7c,
// Entry 6640 - 667F
0x0b95, 0x0bae, 0x0bc7, 0x0be0, 0x0bf9, 0x0c12, 0x0c2b, 0x0c44,
0x0c5d, 0x0c76, 0x0c8f, 0x0ca8, 0x0cc1, 0x0cda, 0x0cf3, 0x0d0c,
0x0d25, 0x0d3e, 0x0d57, 0x0d70, 0x0d89, 0x0da2, 0x0dbb, 0x0dd4,
0x0ded, 0x0e06, 0x0e1f, 0x0e38, 0x0e51, 0x0e6a, 0x0e83, 0x0e9c,
0x0eb5, 0x0ece, 0x0ee7, 0x0f00, 0x0f19, 0x0f32, 0x0f4b, 0x0f64,
0x0f7d, 0x0f96, 0x0faf, 0x0fc8, 0x0fe1, 0x0ffa, 0x1013, 0x102c,
0x1045, 0x105e, 0x1077, 0x1090, 0x10a9, 0x10c2, 0x10db, 0x10f4,
0x110d, 0x1126, 0x113f, 0x1158, 0x1171, 0x118a, 0x11a3, 0x11bc,
// Entry 6680 - 66BF
0x11d5, 0x11ee, 0x1207, 0x1220, 0x1239, 0x1252, 0x126b, 0x1284,
0x129d, 0x12b6, 0x12cf, 0x12e8, 0x1301, 0x131a, 0x1333, 0x134c,
0x1365, 0x137e, 0x1397, 0x13b0, 0x13c9, 0x13e2, 0x13fb, 0x1414,
0x142d, 0x1446, 0x145f, 0x1478, 0x1491, 0x14aa, 0x14c3, 0x14dc,
0x14f5, 0x150e, 0x1527, 0x1540, 0x1559, 0x1572, 0x158b, 0x15a4,
0x15bd, 0x15d6, 0x15ef, 0x1608, 0x1621, 0x163a, 0x1653, 0x166c,
0x1685, 0x169e, 0x16b7, 0x16d0, 0x16e9, 0x1702, 0x171b, 0x1734,
0x174d, 0x1766, 0x177f, 0x1798, 0x17b1, 0x17ca, 0x17e3, 0x17fc,
// Entry 66C0 - 66FF
0x1815, 0x182e, 0x1847, 0x1860, 0x1879, 0x1892, 0x18ab, 0x18c4,
0x18dd, 0x18f6, 0x190f, 0x1928, 0x1941, 0x195a, 0x1973, 0x198c,
0x19a5, 0x19be, 0x19d7, 0x19f0, 0x1a09, 0x1a22, 0x1a3b, 0x1a54,
0x1a6d, 0x1a86, 0x1a9f, 0x1ab8, 0x1ad1, 0x1aea, 0x1b03, 0x1b1c,
0x1b35, 0x1b4e, 0x1b67, 0x1b80, 0x1b99, 0x1bb2, 0x1bcb, 0x1be4,
0x1bfd, 0x1c16, 0x1c2f, 0x1c48, 0x1c61, 0x1c7a, 0x1c93, 0x1cac,
0x1cc5, 0x1cde, 0x1cf7, 0x1d10, 0x1d29, 0x1d42, 0x1d5b, 0x1d74,
0x1d8d, 0x1da6, 0x1dbf, 0x1dd8, 0x1df1, 0x1e0a, 0x1e23, 0x1e3c,
// Entry 6700 - 673F
0x1e55, 0x1e6e, 0x1e87, 0x1ea0, 0x1eb9, 0x1ed2, 0x1eeb, 0x1f04,
0x1f1d, 0x1f36, 0x1f4f, 0x1f68, 0x1f81, 0x1f9a, 0x1fb3, 0x1fcc,
0x1fe5, 0x1ffe, 0x2017, 0x2030, 0x2049, 0x2062, 0x207b, 0x2094,
0x20ad, 0x20c6, 0x20df, 0x20f8, 0x2111, 0x212a, 0x2143, 0x215c,
0x2175, 0x218e, 0x21a7, 0x21c0, 0x21d9, 0x21f2, 0x220b, 0x2224,
0x223d, 0x2256, 0x226f, 0x2288, 0x22a1, 0x22ba, 0x22d3, 0x22ec,
0x2305, 0x231e, 0x2337, 0x2350, 0x2369, 0x2382, 0x239b, 0x23b4,
0x23cd, 0x23e6, 0x23ff, 0x2418, 0x2431, 0x244a, 0x2463, 0x247c,
// Entry 6740 - 677F
0x2495, 0x24ae, 0x24c7, 0x24e0, 0x24f9, 0x2512, 0x252b, 0x2544,
0x255d, 0x2576, 0x258f, 0x25a8, 0x25c1, 0x25da, 0x25f3, 0x260c,
0x2625, 0x263e, 0x2657, 0x2670, 0x2689, 0x26a2, 0x26bb, 0x26d4,
0x26ed, 0x2706, 0x271f, 0x2738, 0x2751, 0x276a, 0x2783, 0x279c,
0x27b5, 0x27ce, 0x27e7, 0x2800, 0x2819, 0x2832, 0x284b, 0x2864,
0x287d, 0x2896, 0x28af, 0x28c8, 0x28e1, 0x28fa, 0x2913, 0x292c,
0x2945, 0x295e, 0x2977, 0x2990, 0x29a9, 0x29c2, 0x29db, 0x29f4,
0x2a0d, 0x2a26, 0x2a3f, 0x2a58, 0x2a71, 0x2a8a, 0x2aa3, 0x2abc,
// Entry 6780 - 67BF
0x2ad5, 0x2aee, 0x2b07, 0x2b20, 0x2b39, 0x2b52, 0x2b6b, 0x2b84,
0x2b9d, 0x2bb6, 0x2bcf, 0x2be8, 0x2c01, 0x2c1a, 0x2c33, 0x2c4c,
0x2c65, 0x2c7e, 0x2c97, 0x2cb0, 0x2cc9, 0x2ce2, 0x2cfb, 0x2d14,
0x2d2d, 0x2d46, 0x2d5f, 0x2d78, 0x2d91, 0x2daa, 0x2dc3, 0x2ddc,
0x2df5, 0x2e0e, 0x2e27, 0x2e40, 0x2e59, 0x2e72, 0x2e8b, 0x2ea4,
0x2ebd, 0x2ed6, 0x2eef, 0x2f08, 0x2f21, 0x2f3a, 0x2f53, 0x2f6c,
0x2f85, 0x2f9e, 0x2fb7, 0x2fd0, 0x2fe9, 0x3002, 0x301b, 0x3034,
0x304d, 0x3066, 0x307f, 0x3098, 0x30b1, 0x30ca, 0x30e3, 0x30fc,
// Entry 67C0 - 67FF
0x3115, 0x312e, 0x3147, 0x3160, 0x3179, 0x3192, 0x31ab, 0x31c4,
0x31dd, 0x31f6, 0x320f, 0x3228, 0x3241, 0x325a, 0x3273, 0x328c,
0x32a5, 0x32be, 0x32d7, 0x32f0, 0x3309, 0x3322, 0x333b, 0x3354,
0x336d, 0x3386, 0x339f, 0x33b8, 0x33d1, 0x33ea, 0x3403, 0x341c,
0x3435, 0x344e, 0x3467, 0x3480, 0x3499, 0x34b2, 0x34cb, 0x34e4,
0x34fd, 0x3516, 0x352f, 0x3548, 0x3561, 0x357a, 0x3593, 0x35ac,
0x35c5, 0x35de, 0x35f7, 0x3610, 0x3629, 0x3642, 0x365b, 0x3674,
0x368d, 0x36a6, 0x36bf, 0x36d8, 0x36f1, 0x370a, 0x3723, 0x373c,
// Entry 6800 - 683F
0x3755, 0x376e, 0x3787, 0x37a0, 0x37b9, 0x37d2, 0x37eb, 0x3804,
0x381d, 0x3836, 0x384f, 0x3868, 0x3881, 0x389a, 0x38b3, 0x38cc,
0x38e5, 0x38fe, 0x3917, 0x3930, 0x3949, 0x3962, 0x397b, 0x3994,
0x39ad, 0x39c6, 0x39df, 0x39f8, 0x3a11, 0x3a2a, 0x3a43, 0x3a5c,
0x3a75, 0x3a8e, 0x3aa7, 0x3ac0, 0x3ad9, 0x3af2, 0x3b0b, 0x3b24,
0x3b3d, 0x3b56, 0x3b6f, 0x3b88, 0x3ba1, 0x3bba, 0x3bd3, 0x3bec,
0x3c05, 0x3c1e, 0x3c37, 0x3c50, 0x3c69, 0x3c82, 0x3c9b, 0x3cb4,
0x3ccd, 0x3ce6, 0x3cff, 0x3d18, 0x3d31, 0x3d4a, 0x3d63, 0x3d7c,
// Entry 6840 - 687F
0x3d95, 0x3dae, 0x3dc7, 0x3de0, 0x3df9, 0x3e12, 0x3e2b, 0x3e44,
0x3e5d, 0x3e76, 0x3e8f, 0x3ea8, 0x3ec1, 0x3eda, 0x3ef3, 0x3f0c,
0x3f25, 0x3f3e, 0x3f57, 0x3f70, 0x3f89, 0x3fa2, 0x3fbb, 0x3fd4,
0x3fed, 0x4006, 0x401f, 0x4038, 0x4051, 0x406a, 0x4083, 0x409c,
0x40b5, 0x40ce, 0x40e7, 0x4100, 0x4119, 0x4132, 0x414b, 0x4164,
0x417d, 0x4196, 0x41af, 0x41c8, 0x41e1, 0x41fa, 0x4213, 0x422c,
0x4245, 0x425e, 0x4277, 0x4290, 0x42a9, 0x42c2, 0x42db, 0x42f4,
0x430d, 0x4326, 0x433f, 0x4358, 0x4371, 0x438a, 0x43a3, 0x43bc,
// Entry 6880 - 68BF
0x43d5, 0x43ee, 0x4407, 0x4420, 0x4439, 0x4452, 0x446b, 0x4484,
0x449d, 0x44b6, 0x44cf, 0x44e8, 0x4501, 0x451a, 0x4533, 0x454c,
0x4565, 0x457e, 0x4597, 0x45b0, 0x45c9, 0x45e2, 0x45fb, 0x4614,
0x462d, 0x4646, 0x465f, 0x4678, 0x4691, 0x46aa, 0x46c3, 0x46dc,
0x46f5, 0x470e, 0x4727, 0x4740, 0x4759, 0x4772, 0x478b, 0x47a4,
0x47bd, 0x47d6, 0x47ef, 0x4808, 0x4821, 0x483a, 0x4853, 0x486c,
0x4885, 0x489e, 0x48b7, 0x48d0, 0x48e9, 0x4902, 0x491b, 0x4934,
0x494d, 0x4966, 0x497f, 0x4998, 0x49b1, 0x49ca, 0x49e3, 0x49fc,
// Entry 68C0 - 68FF
0x4a15, 0x4a2e, 0x4a47, 0x4a60, 0x4a79, 0x4a92, 0x4aab, 0x4ac4,
0x4add, 0x4af6, 0x4b0f, 0x4b28, 0x4b41, 0x4b5a, 0x4b73, 0x4b8c,
0x4ba5, 0x4bbe, 0x4bd7, 0x4bf0, 0x4c09, 0x4c22, 0x4c3b, 0x4c54,
0x4c6d, 0x4c86, 0x4c9f, 0x4cb8, 0x4cd1, 0x4cea, 0x4d03, 0x4d1c,
0x4d35, 0x4d4e, 0x4d67, 0x4d80, 0x4d99, 0x4db2, 0x4dcb, 0x4de4,
0x4dfd, 0x4e16, 0x4e2f, 0x4e48, 0x4e61, 0x4e7a, 0x4e93, 0x4eac,
0x4ec5, 0x4ede, 0x4ef7, 0x4f10, 0x4f29, 0x4f42, 0x4f5b, 0x4f74,
0x4f8d, 0x4fa6, 0x4fbf, 0x4fd8, 0x4ff1, 0x500a, 0x5023, 0x503c,
// Entry 6900 - 693F
0x5055, 0x506e, 0x5087, 0x50a0, 0x50b9, 0x50d2, 0x50eb, 0x5104,
0x511d, 0x5136, 0x514f, 0x5168, 0x5181, 0x519a, 0x51b3, 0x51cc,
0x51e5, 0x51fe, 0x5217, 0x5230, 0x5249, 0x5262, 0x527b, 0x5294,
0x52ad, 0x52c6, 0x52df, 0x52f8, 0x5311, 0x532a, 0x5343, 0x535c,
0x5375, 0x538e, 0x53a7, 0x53c0, 0x53d9, 0x53f2, 0x540b, 0x5424,
0x543d, 0x5456, 0x546f, 0x5488, 0x54a1, 0x54ba, 0x54d3, 0x54ec,
0x5505, 0x551e, 0x5537, 0x5550, 0x5569, 0x5582, 0x559b, 0x55b4,
0x55cd, 0x55e6, 0x55ff, 0x5618, 0x5631, 0x564a, 0x5663, 0x567c,
// Entry 6940 - 697F
0x5695, 0x56ae, 0x56c7, 0x56e0, 0x56f9, 0x5712, 0x572b, 0x5744,
0x575d, 0x5776, 0x578f, 0x57a8, 0x57c1, 0x57da, 0x57f3, 0x580c,
0x5825, 0x583e, 0x5857, 0x5870, 0x5889, 0x58a2, 0x58bb, 0x58d4,
0x58ed, 0x5906, 0x591f, 0x5938, 0x5951, 0x596a, 0x5983, 0x599c,
0x59b5, 0x59ce, 0x59e7, 0x5a00, 0x5a19, 0x5a32, 0x5a4b, 0x5a64,
0x5a7d, 0x5a96, 0x5aaf, 0x5ac8, 0x5ae1, 0x5afa, 0x5b13, 0x5b2c,
0x5b45, 0x5b5e, 0x5b77, 0x5b90, 0x5ba9, 0x5bc2, 0x5bdb, 0x5bf4,
0x5c0d, 0x5c26, 0x5c3f, 0x5c58, 0x5c71, 0x5c8a, 0x5ca3, 0x5cbc,
// Entry 6980 - 69BF
0x5cd5, 0x5cee, 0x5d07, 0x5d20, 0x5d39, 0x5d52, 0x5d6b, 0x5d84,
0x5d9d, 0x5db6, 0x5dcf, 0x5de8, 0x5e01, 0x5e1a, 0x5e33, 0x5e4c,
0x5e65, 0x5e7e, 0x5e97, 0x5eb0, 0x5ec9, 0x5ee2, 0x5efb, 0x5f14,
0x5f2d, 0x5f46, 0x5f5f, 0x5f78, 0x5f91, 0x5faa, 0x5fc3, 0x5fdc,
0x5ff5, 0x600e, 0x6027, 0x6040, 0x6059, 0x6072, 0x608b, 0x60a4,
0x60bd, 0x60d6, 0x60ef, 0x6108, 0x6121, 0x613a, 0x6153, 0x616c,
0x6185, 0x619e, 0x61b7, 0x61d0, 0x61e9, 0x6202, 0x621b, 0x6234,
0x624d, 0x6266, 0x627f, 0x6298, 0x62b1, 0x62ca, 0x62e3, 0x62fc,
// Entry 69C0 - 69FF
0x6315, 0x632e, 0x6347, 0x6360, 0x6379, 0x6392, 0x63ab, 0x63c4,
0x63dd, 0x63f6, 0x640f, 0x6428, 0x6441, 0x645a, 0x6473, 0x648c,
0x64a5, 0x64be, 0x64d7, 0x64f0, 0x6509, 0x6522, 0x653b, 0x6554,
0x656d, 0x6586, 0x659f, 0x65b8, 0x65d1, 0x65ea, 0x6603, 0x661c,
0x6635, 0x664e, 0x6667, 0x6680, 0x6699, 0x66b2, 0x66cb, 0x66e4,
0x66fd, 0x6716, 0x672f, 0x6748, 0x6761, 0x677a, 0x6793, 0x67ac,
0x67c5, 0x67de, 0x67f7, 0x6810, 0x6829, 0x6842, 0x685b, 0x6874,
0x688d, 0x68a6, 0x68bf, 0x68d8, 0x68f1, 0x690a, 0x6923, 0x693c,
// Entry 6A00 - 6A3F
0x6955, 0x696e, 0x6987, 0x69a0, 0x69b9, 0x69d2, 0x69eb, 0x6a04,
0x6a1d, 0x6a36, 0x6a4f, 0x6a68, 0x6a81, 0x6a9a, 0x6ab3, 0x6acc,
0x6ae5, 0x6afe, 0x6b17, 0x6b30, 0x6b49, 0x6b62, 0x6b7b, 0x6b94,
0x6bad, 0x6bc6, 0x6bdf, 0x6bf8, 0x6c11, 0x6c2a, 0x6c43, 0x6c5c,
0x6c75, 0x6c8e, 0x6ca7, 0x6cc0, 0x6cd9, 0x6cf2, 0x6d0b, 0x6d24,
0x6d3d, 0x6d56, 0x6d6f, 0x6d88, 0x6da1, 0x6dba, 0x6dd3, 0x6dec,
0x6e05, 0x6e1e, 0x6e37, 0x6e50, 0x6e69, 0x6e82, 0x6e9b, 0x6eb4,
0x6ecd, 0x6ee6, 0x6eff, 0x6f18, 0x6f31, 0x6f4a, 0x6f63, 0x6f7c,
// Entry 6A40 - 6A7F
0x6f95, 0x6fae, 0x6fc7, 0x6fe0, 0x6ff9, 0x7012, 0x702b, 0x7044,
0x705d, 0x7076, 0x708f, 0x70a8, 0x70c1, 0x70da, 0x70f3, 0x710c,
0x7125, 0x713e, 0x7157, 0x7170, 0x7189, 0x71a2, 0x71bb, 0x71d4,
0x71ed, 0x7206, 0x721f, 0x7238, 0x7251, 0x726a, 0x7283, 0x729c,
0x72b5, 0x72ce, 0x72e7, 0x7300, 0x7319, 0x7332, 0x734b, 0x7364,
0x737d, 0x7396, 0x73af, 0x73c8, 0x73e1, 0x73fa, 0x7413, 0x742c,
0x7445, 0x745e, 0x7477, 0x7490, 0x74a9, 0x74c2, 0x74db, 0x74f4,
0x750d, 0x7526, 0x753f, 0x7558, 0x7571, 0x758a, 0x75a3, 0x75bc,
// Entry 6A80 - 6ABF
0x75d5, 0x75ee, 0x7607, 0x7620, 0x7639, 0x7652, 0x766b, 0x7684,
0x769d, 0x76b6, 0x76cf, 0x76e8, 0x7701, 0x771a, 0x7733, 0x774c,
0x7765, 0x777e, 0x7797, 0x77b0, 0x77c9, 0x77e2, 0x77fb, 0x7814,
0x782d, 0x7846, 0x785f, 0x7878, 0x7891, 0x78aa, 0x78c3, 0x78dc,
0x78f5, 0x790e, 0x7927, 0x7940, 0x7959, 0x7972, 0x798b, 0x79a4,
0x79bd, 0x79d6, 0x79ef, 0x7a08, 0x7a21, 0x7a3a, 0x7a53, 0x7a6c,
0x7a85, 0x7a9e, 0x7ab7, 0x7ad0, 0x7ae9, 0x7b02, 0x7b1b, 0x7b34,
0x7b4d, 0x7b66, 0x7b7f, 0x7b98, 0x7bb1, 0x7bca, 0x7be3, 0x7bfc,
// Entry 6AC0 - 6AFF
0x7c15, 0x7c2e, 0x7c47, 0x7c60, 0x7c79, 0x7c92, 0x7cab, 0x7cc4,
0x7cdd, 0x7cf6, 0x7d0f, 0x7d28, 0x7d41, 0x7d5a, 0x7d73, 0x7d8c,
0x7da5, 0x7dbe, 0x7dd7, 0x7df0, 0x7e09, 0x7e22, 0x7e3b, 0x7e54,
0x7e6d, 0x7e86, 0x7e9f, 0x7eb8, 0x7ed1, 0x7eea, 0x7f03, 0x7f1c,
0x7f35, 0x7f4e, 0x7f67, 0x7f80, 0x7f99, 0x7fb2, 0x7fcb, 0x7fe4,
0x7ffd, 0x8016, 0x802f, 0x8048, 0x8061, 0x807a, 0x8093, 0x80ac,
0x80c5, 0x80de, 0x80f7, 0x8110, 0x8129, 0x8142, 0x815b, 0x8174,
0x818d, 0x81a6, 0x81bf, 0x81d8, 0x81f1, 0x820a, 0x8223, 0x823c,
// Entry 6B00 - 6B3F
0x8255, 0x826e, 0x8287, 0x82a0, 0x82b9, 0x82d2, 0x82eb, 0x8304,
0x831d, 0x8336, 0x834f, 0x8368, 0x8381, 0x839a, 0x83b3, 0x83cc,
0x83e5, 0x83fe, 0x8417, 0x8430, 0x8449, 0x8462, 0x847b, 0x8494,
0x84ad, 0x84c6, 0x84df, 0x84f8, 0x8511, 0x852a, 0x8543, 0x855c,
0x8575, 0x858e, 0x85a7, 0x85c0, 0x85d9, 0x85f2, 0x860b, 0x8624,
0x863d, 0x8656, 0x866f, 0x8688, 0x86a1, 0x86ba, 0x86d3, 0x86ec,
0x8705, 0x871e, 0x8737, 0x8750, 0x8769, 0x8782, 0x879b, 0x87b4,
0x87cd, 0x87e6, 0x87ff, 0x8818, 0x8831, 0x884a, 0x8863, 0x887c,
// Entry 6B40 - 6B7F
0x8895, 0x88ae, 0x88c7, 0x88e0, 0x88f9, 0x8912, 0x892b, 0x8944,
0x895d, 0x8976, 0x898f, 0x89a8, 0x89c1, 0x89da, 0x89f3, 0x8a0c,
0x8a25, 0x8a3e, 0x8a57, 0x8a70, 0x8a89, 0x8aa2, 0x8abb, 0x8ad4,
0x8aed, 0x8b06, 0x8b1f, 0x8b38, 0x8b51, 0x8b6a, 0x8b83, 0x8b9c,
0x8bb5, 0x8bce, 0x8be7, 0x8c00, 0x8c19, 0x8c32, 0x8c4b, 0x8c64,
0x8c7d, 0x8c96, 0x8caf, 0x8cc8, 0x8ce1, 0x8cfa, 0x8d13, 0x8d2c,
0x8d45, 0x8d5e, 0x8d77, 0x8d90, 0x8da9, 0x8dc2, 0x8ddb, 0x8df4,
0x8e0d, 0x8e26, 0x8e3f, 0x8e58, 0x8e71, 0x8e8a, 0x8ea3, 0x8ebc,
// Entry 6B80 - 6BBF
0x8ed5, 0x8eee, 0x8f07, 0x8f20, 0x8f39, 0x8f52, 0x8f6b, 0x8f84,
0x8f9d, 0x8fb6, 0x8fcf, 0x8fe8, 0x9001, 0x901a, 0x9033, 0x904c,
0x9065, 0x907e, 0x9097, 0x90b0, 0x90c9, 0x90e2, 0x90fb, 0x9114,
0x912d, 0x9146, 0x915f, 0x9178, 0x9191, 0x91aa, 0x91c3, 0x91dc,
0x91f5, 0x920e, 0x9227, 0x9240, 0x9259, 0x9272, 0x928b, 0x92a4,
0x92bd, 0x92d6, 0x92ef, 0x9308, 0x9321, 0x933a, 0x9353, 0x936c,
0x9385, 0x939e, 0x93b7, 0x93d0, 0x93e9, 0x9402, 0x941b, 0x9434,
0x944d, 0x9466, 0x947f, 0x9498, 0x94b1, 0x94ca, 0x94e3, 0x94fc,
// Entry 6BC0 - 6BFF
0x9515, 0x952e, 0x9547, 0x9560, 0x9579, 0x9592, 0x95ab, 0x95c4,
0x95dd, 0x95f6, 0x960f, 0x9628, 0x9641, 0x965a, 0x9673, 0x968c,
0x96a5, 0x96be, 0x96d7, 0x96f0, 0x9709, 0x9722, 0x973b, 0x9754,
0x976d, 0x9786, 0x979f, 0x97b8, 0x97d1, 0x97ea, 0x9803, 0x981c,
0x9835, 0x984e, 0x9867, 0x9880, 0x9899, 0x98b2, 0x98cb, 0x98e4,
0x98fd, 0x9916, 0x992f, 0x9948, 0x9961, 0x997a, 0x9993, 0x99ac,
0x99c5, 0x99de, 0x99f7, 0x9a10, 0x9a29, 0x9a42, 0x9a5b, 0x9a74,
0x9a8d, 0x9aa6, 0x9abf, 0x9ad8, 0x9af1, 0x9b0a, 0x9b23, 0x9b3c,
// Entry 6C00 - 6C3F
0x9b55, 0x9b6e, 0x9b87, 0x9ba0, 0x9bb9, 0x9bd2, 0x9beb, 0x9c04,
0x9c1d, 0x9c36, 0x9c4f, 0x9c68, 0x9c81, 0x9c9a, 0x9cb3, 0x9ccc,
0x9ce5, 0x9cfe, 0x9d17, 0x9d30, 0x9d49, 0x9d62, 0x9d7b, 0x9d94,
0x9dad, 0x9dc6, 0x9ddf, 0x9df8, 0x9e11, 0x9e2a, 0x9e43, 0x9e5c,
0x9e75, 0x9e8e, 0x9ea7, 0x9ec0, 0x9ed9, 0x9ef2, 0x9f0b, 0x9f24,
0x9f3d, 0x9f56, 0x9f6f, 0x9f88, 0x9fa1, 0x9fba, 0x9fd3, 0x9fec,
0xa005, 0xa01e, 0xa037, 0xa050, 0xa069, 0xa082, 0xa09b, 0xa0b4,
0xa0cd, 0xa0e6, 0xa0ff, 0xa118, 0xa131, 0xa14a, 0xa163, 0xa17c,
// Entry 6C40 - 6C7F
0xa195, 0xa1ae, 0xa1c7, 0xa1e0, 0xa1f9, 0xa212, 0xa22b, 0xa244,
0xa25d, 0xa276, 0xa28f, 0xa2a8, 0xa2c1, 0xa2da, 0xa2f3, 0xa30c,
0xa325, 0xa33e, 0xa357, 0xa370, 0xa389, 0xa3a2, 0xa3bb, 0xa3d4,
0xa3ed, 0xa406, 0xa41f, 0xa438, 0xa451, 0xa46a, 0xa483, 0xa49c,
0xa4b5, 0xa4ce, 0xa4e7, 0xa500, 0xa519, 0xa532, 0xa54b, 0xa564,
0xa57d, 0xa596, 0xa5af, 0xa5c8, 0xa5e1, 0xa5fa, 0xa613, 0xa62c,
0xa645, 0xa65e, 0xa677, 0xa690, 0xa6a9, 0xa6c2, 0xa6db, 0xa6f4,
0xa70d, 0xa726, 0xa73f, 0xa758, 0xa771, 0xa78a, 0xa7a3, 0xa7bc,
// Entry 6C80 - 6CBF
0xa7d5, 0xa7ee, 0xa807, 0xa820, 0xa839, 0xa852, 0xa86b, 0xa884,
0xa89d, 0xa8b6, 0xa8cf, 0xa8e8, 0xa901, 0xa91a, 0xa933, 0xa94c,
0xa965, 0xa97e, 0xa997, 0xa9b0, 0xa9c9, 0xa9e2, 0xa9fb, 0xaa14,
0xaa2d, 0xaa46, 0xaa5f, 0xaa78, 0xaa91, 0xaaaa, 0xaac3, 0xaadc,
0xaaf5, 0xab0e, 0xab27, 0xab40, 0xab59, 0xab72, 0xab8b, 0xaba4,
0xabbd, 0xabd6, 0xabef, 0xac08, 0xac21, 0xac3a, 0xac53, 0xac6c,
0xac85, 0xac9e, 0xacb7, 0xacd0, 0xace9, 0xad02, 0xad1b, 0xad34,
0xad4d, 0xad66, 0xad7f, 0xad98, 0xadb1, 0xadca, 0xade3, 0xadfc,
// Entry 6CC0 - 6CFF
0xae15, 0xae2e, 0xae47, 0xae60, 0xae79, 0xae92, 0xaeab, 0xaec4,
0xaedd, 0xaef6, 0xaf0f, 0xaf28, 0xaf41, 0xaf5a, 0xaf73, 0xaf8c,
0xafa5, 0xafbe, 0xafd7, 0xaff0, 0xb009, 0xb022, 0xb03b, 0xb054,
0xb06d, 0xb086, 0xb09f, 0xb0b8, 0xb0d1, 0xb0ea, 0xb103, 0xb11c,
0xb135, 0xb14e, 0xb167, 0xb180, 0xb199, 0xb1b2, 0xb1cb, 0xb1e4,
0xb1fd, 0xb216, 0xb22f, 0xb248, 0xb261, 0xb27a, 0xb293, 0xb2ac,
0xb2c5, 0xb2de, 0xb2f7, 0xb310, 0xb329, 0xb342, 0xb35b, 0xb374,
0xb38d, 0xb3a6, 0xb3bf, 0xb3d8, 0xb3f1, 0xb40a, 0xb423, 0xb43c,
// Entry 6D00 - 6D3F
0xb455, 0xb46e, 0xb487, 0xb4a0, 0xb4b9, 0xb4d2, 0xb4eb, 0xb504,
0xb51d, 0xb536, 0xb54f, 0xb568, 0xb581, 0xb59a, 0xb5b3, 0xb5cc,
0xb5e5, 0xb5fe, 0xb617, 0xb630, 0xb649, 0xb662, 0xb67b, 0xb694,
0xb6ad, 0xb6c6, 0xb6df, 0xb6f8, 0xb711, 0xb72a, 0xb743, 0xb75c,
0xb775, 0xb78e, 0xb7a7, 0xb7c0, 0xb7d9, 0xb7f2, 0xb80b, 0xb824,
0xb83d, 0xb856, 0xb86f, 0xb888, 0xb8a1, 0xb8ba, 0xb8d3, 0xb8ec,
0xb905, 0xb91e, 0xb937, 0xb950, 0xb969, 0xb982, 0xb99b, 0xb9b4,
0xb9cd, 0xb9e6, 0xb9ff, 0xba18, 0xba31, 0xba4a, 0xba63, 0xba7c,
// Entry 6D40 - 6D7F
0xba95, 0xbaae, 0xbac7, 0xbae0, 0xbaf9, 0xbb12, 0xbb2b, 0xbb44,
0xbb5d, 0xbb76, 0xbb8f, 0xbba8, 0xbbc1, 0xbbda, 0xbbf3, 0xbc0c,
0xbc25, 0xbc3e, 0xbc57, 0xbc70, 0xbc89, 0xbca2, 0xbcbb, 0xbcd4,
0xbced, 0xbd06, 0xbd1f, 0xbd38, 0xbd51, 0xbd6a, 0xbd83, 0xbd9c,
0xbdb5, 0xbdce, 0xbde7, 0xbe00, 0xbe19, 0xbe32, 0xbe4b, 0xbe64,
0xbe7d, 0xbe96, 0xbeaf, 0xbec8, 0xbee1, 0xbefa, 0xbf13, 0xbf2c,
0xbf45, 0xbf5e, 0xbf77, 0xbf90, 0xbfa9, 0xbfc2, 0xbfdb, 0xbff4,
0xc00d, 0xc026, 0xc03f, 0xc058, 0xc071, 0xc08a, 0xc0a3, 0xc0bc,
// Entry 6D80 - 6DBF
0xc0d5, 0xc0ee, 0xc107, 0xc120, 0xc139, 0xc152, 0xc16b, 0xc184,
0xc19d, 0xc1b6, 0xc1cf, 0xc1e8, 0xc201, 0xc21a, 0xc233, 0xc24c,
0xc265, 0xc27e, 0xc297, 0xc2b0, 0xc2c9, 0xc2e2, 0xc2fb, 0xc314,
0xc32d, 0xc346, 0xc35f, 0xc378, 0xc391, 0xc3aa, 0xc3c3, 0xc3dc,
0xc3f5, 0xc40e, 0xc427, 0xc440, 0xc459, 0xc472, 0xc48b, 0xc4a4,
0xc4bd, 0xc4d6, 0xc4ef, 0xc508, 0xc521, 0xc53a, 0xc553, 0xc56c,
0xc585, 0xc59e, 0xc5b7, 0xc5d0, 0xc5e9, 0xc602, 0xc61b, 0xc634,
0xc64d, 0xc666, 0xc67f, 0xc698, 0xc6b1, 0xc6ca, 0xc6e3, 0xc6fc,
// Entry 6DC0 - 6DFF
0xc715, 0xc72e, 0xc747, 0xc760, 0xc779, 0xc792, 0xc7ab, 0xc7c4,
0xc7dd, 0xc7f6, 0xc80f, 0xc828, 0xc841, 0xc85a, 0xc873, 0xc88c,
0xc8a5, 0xc8be, 0xc8d7, 0xc8f0, 0xc909, 0xc922, 0xc93b, 0xc954,
0xc96d, 0xc986, 0xc99f, 0xc9b8, 0xc9d1, 0xc9ea, 0xca03, 0xca1c,
0xca35, 0xca4e, 0xca67, 0xca80, 0xca99, 0xcab2, 0xcacb, 0xcae4,
0xcafd, 0xcb16, 0xcb2f, 0xcb48, 0xcb61, 0xcb7a, 0xcb93, 0xcbac,
0xcbc5, 0xcbde, 0xcbf7, 0xcc10, 0xcc29, 0xcc42, 0xcc5b, 0xcc74,
0xcc8d, 0xcca6, 0xccbf, 0xccd8, 0xccf1, 0xcd0a, 0xcd23, 0xcd3c,
// Entry 6E00 - 6E3F
0xcd55, 0xcd6e, 0xcd87, 0xcda0, 0xcdb9, 0xcdd2, 0xcdeb, 0xce04,
0xce1d, 0xce36, 0xce4f, 0xce68, 0xce81, 0xce9a, 0xceb3, 0xcecc,
0xcee5, 0xcefe, 0xcf17, 0xcf30, 0xcf49, 0xcf62, 0xcf7b, 0xcf94,
0xcfad, 0xcfc6, 0xcfdf, 0xcff8, 0xd011, 0xd02a, 0xd043, 0xd05c,
0xd075, 0xd08e, 0xd0a7, 0xd0c0, 0xd0d9, 0xd0f2, 0xd10b, 0xd124,
0xd13d, 0xd156, 0xd16f, 0xd188, 0xd1a1, 0xd1ba, 0xd1d3, 0xd1ec,
0xd205, 0xd21e, 0xd237, 0xd250, 0xd269, 0xd282, 0xd29b, 0xd2b4,
0xd2cd, 0xd2e6, 0xd2ff, 0xd318, 0xd331, 0xd34a, 0xd363, 0xd37c,
// Entry 6E40 - 6E7F
0xd395, 0xd3ae, 0xd3c7, 0xd3e0, 0xd3f9, 0xd412, 0xd42b, 0xd444,
0xd45d, 0xd476, 0xd48f, 0xd4a8, 0xd4c1, 0xd4da, 0xd4f3, 0xd50c,
0xd525, 0xd53e, 0xd557, 0xd570, 0xd589, 0xd5a2, 0xd5bb, 0xd5d4,
0xd5ed, 0xd606, 0xd61f, 0xd638, 0xd651, 0xd66a, 0xd683, 0xd69c,
0xd6b5, 0xd6ce, 0xd6e7, 0xd700, 0xd719, 0xd732, 0xd74b, 0xd764,
0xd77d, 0xd796, 0xd7af, 0xd7c8, 0xd7e1, 0xd7fa, 0xd813, 0xd82c,
0xd845, 0xd85e, 0xd877, 0xd890, 0xd8a9, 0xd8c2, 0xd8db, 0xd8f4,
0xd90d, 0xd926, 0xd93f, 0xd958, 0xd971, 0xd98a, 0xd9a3, 0xd9bc,
// Entry 6E80 - 6EBF
0xd9d5, 0xd9ee, 0xda07, 0xda20, 0xda39, 0xda52, 0xda6b, 0xda84,
0xda9d, 0xdab6, 0xdacf, 0xdae8, 0xdb01, 0xdb1a, 0xdb33, 0xdb4c,
0xdb65, 0xdb7e, 0xdb97, 0xdbb0, 0xdbc9, 0xdbe2, 0xdbfb, 0xdc14,
0xdc2d, 0xdc46, 0xdc5f, 0xdc78, 0xdc91, 0xdcaa, 0xdcc3, 0xdcdc,
0xdcf5, 0xdd0e, 0xdd27, 0xdd40, 0xdd59, 0xdd72, 0xdd8b, 0xdda4,
0xddbd, 0xddd6, 0xddef, 0xde08, 0xde21, 0xde3a, 0xde53, 0xde6c,
0xde85, 0xde9e, 0xdeb7, 0xded0, 0xdee9, 0xdf02, 0xdf1b, 0xdf34,
0xdf4d, 0xdf66, 0xdf7f, 0xdf98, 0xdfb1, 0xdfca, 0xdfe3, 0xdffc,
// Entry 6EC0 - 6EFF
0xe015, 0xe02e, 0xe047, 0xe060, 0xe079, 0xe092, 0xe0ab, 0xe0c4,
0xe0dd, 0xe0f6, 0xe10f, 0xe128, 0xe141, 0xe15a, 0xe173, 0xe18c,
0xe1a5, 0xe1be, 0xe1d7, 0xe1f0, 0xe209, 0xe222, 0xe23b, 0xe254,
0xe26d, 0xe286, 0xe29f, 0xe2b8, 0xe2d1, 0xe2ea, 0xe303, 0xe31c,
0xe335, 0xe34e, 0xe367, 0xe380, 0xe399, 0xe3b2, 0xe3cb, 0xe3e4,
0xe3fd, 0xe416, 0xe42f, 0xe448, 0xe461, 0xe47a, 0xe493, 0xe4ac,
0xe4c5, 0xe4de, 0xe4f7, 0xe510, 0xe529, 0xe542, 0xe55b, 0xe574,
0xe58d, 0xe5a6, 0xe5bf, 0xe5d8, 0xe5f1, 0xe60a, 0xe623, 0xe63c,
// Entry 6F00 - 6F3F
0xe655, 0xe66e, 0xe687, 0xe6a0, 0xe6b9, 0xe6d2, 0xe6eb, 0xe704,
0xe71d, 0xe736, 0xe74f, 0xe768, 0xe781, 0xe79a, 0xe7b3, 0xe7cc,
0xe7e5, 0xe7fe, 0xe817, 0xe830, 0xe849, 0xe862, 0xe87b, 0xe894,
0xe8ad, 0xe8c6, 0xe8df, 0xe8f8, 0xe911, 0xe92a, 0xe943, 0xe95c,
0xe975, 0xe98e, 0xe9a7, 0xe9c0, 0xe9d9, 0xe9f2, 0xea0b, 0xea24,
0xea3d, 0xea56, 0xea6f, 0xea88, 0xeaa1, 0xeaba, 0xead3, 0xeaec,
0xeb05, 0xeb1e, 0xeb37, 0xeb50, 0xeb69, 0xeb82, 0xeb9b, 0xebb4,
0xebcd, 0xebe6, 0xebff, 0xec18, 0xec31, 0xec4a, 0xec63, 0xec7c,
// Entry 6F40 - 6F7F
0xec95, 0xecae, 0xecc7, 0xece0, 0xecf9, 0xed12, 0xed2b, 0xed44,
0xed5d, 0xed76, 0xed8f, 0xeda8, 0xedc1, 0xedda, 0xedf3, 0xee0c,
0xee25, 0xee3e, 0xee57, 0xee70, 0xee89, 0xeea2, 0xeebb, 0xeed4,
0xeeed, 0xef06, 0xef1f, 0xef38, 0xef51, 0xef6a, 0xef83, 0xef9c,
0xefb5, 0xefce, 0xefe7, 0xf000, 0xf019, 0xf032, 0xf04b, 0xf064,
0xf07d, 0xf096, 0xf0af, 0xf0c8, 0xf0e1, 0xf0fa, 0xf113, 0xf12c,
0xf145, 0xf15e, 0xf177, 0xf190, 0xf1a9, 0xf1c2, 0xf1db, 0xf1f4,
0xf20d, 0xf226, 0xf23f, 0xf258, 0xf271, 0xf28a, 0xf2a3, 0xf2bc,
// Entry 6F80 - 6FBF
0xf2d5, 0xf2ee, 0xf307, 0xf320, 0xf339, 0xf352, 0xf36b, 0xf384,
0xf39d, 0xf3b6, 0xf3cf, 0xf3e8, 0xf401, 0xf41a, 0xf433, 0xf44c,
0xf465, 0xf47e, 0xf497, 0xf4b0, 0xf4c9, 0xf4e2, 0xf4fb, 0xf514,
0xf52e, 0xf547, 0xf560, 0xf579, 0xf592, 0xf5ab, 0xf5c4, 0xf5dd,
0xf5f6, 0xf60f, 0xf628, 0xf641, 0xf65a, 0xf673, 0xf68c, 0xf6a5,
0xf6be, 0xf6d8, 0xf6f1, 0xf70a, 0xf723, 0xf73c, 0xf755, 0xf76e,
0xf787, 0xf7a0, 0xf7b9, 0xf7d2, 0xf7eb, 0xf804, 0xf81d, 0xf837,
0xf850, 0xf869, 0xf883, 0xf89c, 0xf8b5, 0xf8ce, 0xf8e7, 0xf901,
// Entry 6FC0 - 6FFF
0xf91a, 0xf934, 0xf94e, 0xf967, 0xf980, 0xf999, 0xf9b2, 0xf9cb,
0xf9e4, 0xf9fd, 0xfa16, 0xfa2f, 0xfa48, 0xfa61, 0xfa7a, 0xfa93,
0xfaac, 0xfac5, 0xfade, 0xfaf7, 0xfb10, 0xfb29, 0xfb42, 0xfb5c,
0xfb76, 0xfb90, 0xfba9, 0xfbc2, 0xfbdb, 0xfbf4, 0xfc0d, 0xfc26,
0xfc3f, 0xfc58, 0xfc71, 0xfc8a, 0xfca3, 0xfcbc, 0xfcd5, 0xfcee,
0xfd07, 0xfd20, 0xfd39, 0xfd52, 0xfd6b, 0xfd84, 0xfd9d, 0xfdb6,
0xfdcf, 0xfde8, 0xfe01, 0xfe1a, 0xfe33, 0xfe4c, 0xfe65, 0xfe7e,
0xfe97, 0xfeb1, 0xfeca, 0xfee4, 0xfefd, 0xff16, 0xff30, 0xff49,
// Entry 7000 - 703F
0xff63, 0xff7c, 0xff96, 0xffaf, 0xffc8, 0xffe2, 0xfffc, 0x0016,
0x002f, 0x0049, 0x0063, 0x007c, 0x0095, 0x00af, 0x00c9, 0x00e3,
0x00fc, 0x0115, 0x012e, 0x0148, 0x0162, 0x017b, 0x0194, 0x01ad,
0x01c6, 0x01df, 0x01f9, 0x0212, 0x022b, 0x0244, 0x025d, 0x0276,
0x028f, 0x02a8, 0x02c1, 0x02da, 0x02f3, 0x030d, 0x0326, 0x033f,
0x0358, 0x0371, 0x038a, 0x03a3, 0x03bc, 0x03d5, 0x03ee, 0x0407,
0x0421, 0x043a, 0x0453, 0x046c, 0x0485, 0x049e, 0x04b7, 0x04d0,
0x04e9, 0x0502, 0x051b, 0x0534, 0x054d, 0x0566, 0x057f, 0x0598,
// Entry 7040 - 707F
0x05b1, 0x05ca, 0x05e3, 0x05fc, 0x0615, 0x062e, 0x0647, 0x0660,
0x0679, 0x0692, 0x06ab, 0x06c4, 0x06dd, 0x06f6, 0x070f, 0x0728,
0x0741, 0x075a, 0x0773, 0x078c, 0x07a5, 0x07be, 0x07d7, 0x07f0,
0x0809, 0x0822, 0x083b, 0x0854, 0x086d, 0x0886, 0x089f, 0x08b8,
0x08d1, 0x08ea, 0x0903, 0x091c, 0x0935, 0x094e, 0x0967, 0x0980,
0x0999, 0x09b2, 0x09cb, 0x09e4, 0x09fd, 0x0a16, 0x0a2f, 0x0a48,
0x0a61, 0x0a7a, 0x0a93, 0x0aac, 0x0ac6, 0x0ae0, 0x0af9, 0x0b12,
0x0b2b, 0x0b44, 0x0b5d, 0x0b77, 0x0b90, 0x0ba9, 0x0bc3, 0x0bdc,
// Entry 7080 - 70BF
0x0bf5, 0x0c0e, 0x0c27, 0x0c40, 0x0c59, 0x0c73, 0x0c8c, 0x0ca6,
0x0cbf, 0x0cd8, 0x0cf1, 0x0d0a, 0x0d23, 0x0d3c, 0x0d55, 0x0d6e,
0x0d87, 0x0da0, 0x0db9, 0x0dd3, 0x0dec, 0x0e05, 0x0e1e, 0x0e37,
0x0e50, 0x0e69, 0x0e82, 0x0e9b, 0x0eb4, 0x0ecd, 0x0ee6, 0x0eff,
0x0f18, 0x0f31, 0x0f4a, 0x0f63, 0x0f7c, 0x0f95, 0x0fae, 0x0fc7,
0x0fe0, 0x0ff9, 0x1012, 0x102b, 0x1044, 0x105d, 0x1076, 0x108f,
0x10a8, 0x10c1, 0x10da, 0x10f3, 0x110c, 0x1125, 0x113e, 0x1157,
0x1170, 0x1189, 0x11a2, 0x11bb, 0x11d5, 0x11ee, 0x1207, 0x1220,
// Entry 70C0 - 70FF
0x1239, 0x1252, 0x126b, 0x1284, 0x129d, 0x12b6, 0x12cf, 0x12e8,
0x1301, 0x131a, 0x1333, 0x134c, 0x1365, 0x137e, 0x1397, 0x13b0,
0x13c9, 0x13e2, 0x13fb, 0x1415, 0x142e, 0x1447, 0x1460, 0x1479,
0x1492, 0x14ac, 0x14c5, 0x14de, 0x14f7, 0x1510, 0x1529, 0x1543,
0x155c, 0x1575, 0x158e, 0x15a7, 0x15c0, 0x15d9, 0x15f2, 0x160b,
0x1624, 0x163d, 0x1657, 0x1670, 0x1689, 0x16a2, 0x16bb, 0x16d4,
0x16ed, 0x1706, 0x171f, 0x1738, 0x1751, 0x176a, 0x1783, 0x179c,
0x17b5, 0x17ce, 0x17e7, 0x1800, 0x1819, 0x1832, 0x184b, 0x1865,
// Entry 7100 - 713F
0x187e, 0x1897, 0x18b1, 0x18cb, 0x18e5, 0x18fe, 0x1917, 0x1930,
0x1949, 0x1963, 0x197d, 0x1997, 0x19b0, 0x19c9, 0x19e2, 0x19fb,
0x1a14, 0x1a2d, 0x1a46, 0x1a5f, 0x1a78, 0x1a91, 0x1aaa, 0x1ac3,
0x1adc, 0x1af5, 0x1b0e, 0x1b27, 0x1b40, 0x1b59, 0x1b72, 0x1b8b,
0x1ba4, 0x1bbd, 0x1bd6, 0x1bf0, 0x1c09, 0x1c22, 0x1c3b, 0x1c54,
0x1c6d, 0x1c87, 0x1ca0, 0x1cb9, 0x1cd2, 0x1ceb, 0x1d05, 0x1d1e,
0x1d37, 0x1d50, 0x1d6a, 0x1d83, 0x1d9c, 0x1db5, 0x1dce, 0x1de7,
0x1e00, 0x1e19, 0x1e32, 0x1e4b, 0x1e64, 0x1e7e, 0x1e97, 0x1eb9,
// Entry 7140 - 717F
0x1ed3, 0x1eec, 0x1f05, 0x1f1e, 0x1f38, 0x1f51, 0x1f6a, 0x1f83,
0x1f9c, 0x1fb5, 0x1fce, 0x1fed, 0x2006, 0x201f, 0x2038, 0x2051,
0x206a, 0x2083, 0x209c, 0x20b5, 0x20ce, 0x20e7, 0x2100, 0x2119,
0x2132, 0x214b, 0x2164, 0x217d, 0x21aa, 0x21d6, 0x21ef, 0x2208,
0x2221, 0x223a, 0x2253, 0x226c, 0x2285, 0x229e, 0x22b7, 0x22d0,
0x22e9, 0x2302, 0x231b, 0x2334, 0x234d, 0x2366, 0x237f, 0x2398,
0x23b1, 0x23ca, 0x23e3, 0x23fc, 0x2415, 0x242e, 0x2447, 0x2460,
0x2479, 0x2492, 0x24ab, 0x24c4, 0x24dd, 0x24f6, 0x250f, 0x2528,
// Entry 7180 - 71BF
0x2541, 0x255a, 0x2573, 0x258c, 0x25a5, 0x25be, 0x25d8, 0x25f1,
0x260a, 0x2623, 0x263c, 0x2655, 0x266e, 0x2687, 0x26a1, 0x26ba,
0x26d3, 0x26ec, 0x2705, 0x271e, 0x2737, 0x2750, 0x2769, 0x2782,
0x279b, 0x27b4, 0x27cd, 0x27e6, 0x27ff, 0x2818, 0x2831, 0x284a,
0x2863, 0x287c, 0x2895, 0x28ae, 0x28c7, 0x28e0, 0x28f9, 0x2912,
0x292b, 0x2944, 0x295d, 0x2976, 0x298f, 0x29a8, 0x29c1, 0x29da,
0x29f3, 0x2a0c, 0x2a25, 0x2a3e, 0x2a57, 0x2a70, 0x2a89, 0x2aa2,
0x2abb, 0x2ad4, 0x2aed, 0x2b06, 0x2b1f, 0x2b38, 0x2b51, 0x2b6a,
// Entry 71C0 - 71FF
0x2b83, 0x2b9c, 0x2bb5, 0x2bce, 0x2be7, 0x2c00, 0x2c19, 0x2c32,
0x2c4b, 0x2c64, 0x2c7d, 0x2c96, 0x2caf, 0x2cc8, 0x2ce1, 0x2cfa,
0x2d13, 0x2d2c, 0x2d45, 0x2d5e, 0x2d77, 0x2d8c, 0x2da2, 0x2db9,
0x2dcf, 0x2de6, 0x2dfd, 0x2e13, 0x2e2a, 0x2e40, 0x2e57, 0x2e6d,
0x2e84, 0x2e9c, 0x2eb3, 0x2ecb, 0x2ee1, 0x2ef7, 0x2f0e, 0x2f24,
0x2f3b, 0x2f51, 0x2f67, 0x2f7e, 0x2f94, 0x2fab, 0x2fc1, 0x2fd7,
0x2fed, 0x3003, 0x3019, 0x3033, 0x304c, 0x3066, 0x307f, 0x3099,
0x30b2, 0x30cc, 0x30e6, 0x30ff, 0x3119, 0x3133, 0x3151, 0x3176,
// Entry 7200 - 723F
0x319b, 0x31c0, 0x31da, 0x31ff, 0x3219, 0x3230, 0x3246, 0x325c,
0x3274, 0x328b, 0x32a2, 0x32b8, 0x32d0, 0x32e8, 0x32ff, 0x331e,
0x333c, 0x3365, 0x338b, 0x33a8, 0x33c7, 0x33e5, 0x3402, 0x3424,
0x344f, 0x3477, 0x3496, 0x34b4, 0x34cf, 0x34ec, 0x3508, 0x3527,
0x3543, 0x355f, 0x357e, 0x3599, 0x35b1, 0x35d0, 0x35ea, 0x3606,
0x3624, 0x3640, 0x365b, 0x3679, 0x3695, 0x36b6, 0x36d4, 0x36f2,
0x3713, 0x3731, 0x374a, 0x3765, 0x3786, 0x37a2, 0x37bb, 0x37db,
0x37fc, 0x3814, 0x3831, 0x384a, 0x3862, 0x387c, 0x3896, 0x38b1,
// Entry 7240 - 727F
0x38cf, 0x38ea, 0x3902, 0x3923, 0x393c, 0x3958, 0x3971, 0x398c,
0x39a5, 0x39bd, 0x39d6, 0x39ee, 0x3a0c, 0x3a27, 0x3a40, 0x3a63,
0x3a87, 0x3aa2, 0x3abe, 0x3ada, 0x3af4, 0x3b0e, 0x3b27, 0x3b42,
0x3b5b, 0x3b76, 0x3b8e, 0x3ba7, 0x3bc2, 0x3bdb, 0x3bf3, 0x3c0b,
0x3c24, 0x3c3c, 0x3c53, 0x3c6b, 0x3c83, 0x3c9c, 0x3cb7, 0x3cd8,
0x3cf1, 0x3d0c, 0x3d2a, 0x3d49, 0x3d63, 0x3d7e, 0x3d9a, 0x3db2,
0x3dcd, 0x3def, 0x3e12, 0x3e33, 0x3e50, 0x3e70, 0x3e88, 0x3ea5,
0x3ec3, 0x3ee1, 0x3f01, 0x3f22, 0x3f40, 0x3f5b, 0x3f78, 0x3f94,
// Entry 7280 - 72BF
0x3faf, 0x3fc9, 0x3fe2, 0x4003, 0x4021, 0x403b, 0x4057, 0x4070,
0x4089, 0x40a4, 0x40c5, 0x40e0, 0x40f8, 0x4113, 0x4130, 0x414c,
0x4168, 0x4188, 0x41a1, 0x41bb, 0x41d3, 0x41ee, 0x420e, 0x422b,
0x4243, 0x425e, 0x4277, 0x428e, 0x42a6, 0x42bf, 0x42e0, 0x42f8,
0x4310, 0x432d, 0x4347, 0x4365, 0x437f, 0x439a, 0x43b7, 0x43d1,
0x43f7, 0x4414, 0x442e, 0x444a, 0x4465, 0x448b, 0x44aa, 0x44c3,
0x44de, 0x44fc, 0x4516, 0x452f, 0x454b, 0x4564, 0x457d, 0x4598,
0x45b0, 0x45c9, 0x45e3, 0x45ff, 0x4619, 0x4636, 0x4650, 0x4671,
// Entry 72C0 - 72FF
0x468a, 0x46a7, 0x46c6, 0x46df, 0x46fa, 0x4712, 0x472f, 0x474b,
0x4768, 0x4784, 0x479e, 0x47b6, 0x47d0, 0x47e8, 0x4802, 0x481b,
0x4838, 0x4853, 0x486a, 0x4884, 0x489c, 0x48b8, 0x48d7, 0x48f2,
0x490a, 0x4923, 0x493d, 0x4958, 0x496f, 0x4987, 0x49a0, 0x49b9,
0x49d1, 0x49ed, 0x4a06, 0x4a1f, 0x4a40, 0x4a59, 0x4a72, 0x4a8f,
0x4aa7, 0x4ac0, 0x4ada, 0x4af5, 0x4b0d, 0x4b28, 0x4b43, 0x4b5f,
0x4b79, 0x4b92, 0x4bb2, 0x4bcc, 0x4be6, 0x4bff, 0x4c18, 0x4c31,
0x4c4d, 0x4c6d, 0x4c86, 0x4c9e, 0x4cb6, 0x4cce, 0x4ce6, 0x4cfe,
// Entry 7300 - 733F
0x4d17, 0x4d2f, 0x4d47, 0x4d60, 0x4d7a, 0x4d93, 0x4dad, 0x4dc7,
0x4de4, 0x4dfd, 0x4e17, 0x4e31, 0x4e4a, 0x4e64, 0x4e83, 0x4e9c,
0x4eb7, 0x4ed0, 0x4ee8, 0x4f00, 0x4f1c, 0x4f35, 0x4f4d, 0x4f67,
0x4f81, 0x4f9d, 0x4fb6, 0x4fd1, 0x4fe9, 0x5005, 0x5025, 0x5041,
0x5058, 0x5071, 0x508c, 0x50aa, 0x50c3, 0x50df, 0x50fa, 0x5113,
0x512c, 0x5147, 0x5160, 0x517b, 0x5193, 0x51ab, 0x51c6, 0x51df,
0x51f9, 0x5212, 0x522d, 0x5245, 0x525f, 0x5278, 0x5291, 0x52ab,
0x52c8, 0x52e3, 0x52fe, 0x5317, 0x532f, 0x534a, 0x5363, 0x537b,
// Entry 7340 - 737F
0x5396, 0x53b0, 0x53cc, 0x53e5, 0x53fd, 0x5416, 0x542f, 0x5449,
0x5462, 0x547a, 0x5495, 0x54b0, 0x54c9, 0x54e2, 0x54fa, 0x5513,
0x552c, 0x5548, 0x5562, 0x557b, 0x5596, 0x55b0, 0x55ca, 0x55e5,
0x55fc, 0x5618, 0x5630, 0x5648, 0x5660, 0x5678, 0x5692, 0x56ac,
0x56c2, 0x56da, 0x56f1, 0x570a, 0x5724, 0x573d, 0x5754, 0x576c,
0x5785, 0x579d, 0x57b4, 0x57cd, 0x57e5, 0x57fe, 0x5816, 0x5833,
0x584a, 0x5863, 0x5882, 0x589a, 0x58b2, 0x58cb, 0x58e4, 0x58fe,
0x5916, 0x592e, 0x5947, 0x595f, 0x5977, 0x598f, 0x59aa, 0x59c3,
// Entry 7380 - 73BF
0x59dc, 0x59f4, 0x5a0d, 0x5a27, 0x5a3f, 0x5a57, 0x5a74, 0x5a8d,
0x5aa5, 0x5abe, 0x5ad6, 0x5af1, 0x5b0a, 0x5b23, 0x5b3e, 0x5b57,
0x5b71, 0x5b8c, 0x5ba6, 0x5bbf, 0x5bd7, 0x5bf3, 0x5c0c, 0x5c26,
0x5c43, 0x5c5f, 0x5c77, 0x5c90, 0x5cac, 0x5cc5, 0x5ce4, 0x5cfc,
0x5d14, 0x5d36, 0x5d5a, 0x5d73, 0x5d8d, 0x5da6, 0x5dc0, 0x5dd7,
0x5df1, 0x5e0b, 0x5e25, 0x5e40, 0x5e5a, 0x5e73, 0x5e8c, 0x5ea3,
0x5ebc, 0x5ed8, 0x5ef5, 0x5f11, 0x5f2b, 0x5f44, 0x5f5d, 0x5f76,
0x5f8f, 0x5fa7, 0x5fc0, 0x5fd8, 0x5ff8, 0x6010, 0x602a, 0x6044,
// Entry 73C0 - 73FF
0x605e, 0x6077, 0x6092, 0x60aa, 0x60c4, 0x60de, 0x60f6, 0x610e,
0x612a, 0x6143, 0x615a, 0x6173, 0x618c, 0x61a5, 0x61c1, 0x61e1,
0x61fa, 0x6213, 0x622c, 0x6245, 0x625d, 0x6276, 0x6291, 0x62aa,
0x62c2, 0x62db, 0x62f5, 0x630d, 0x6326, 0x633f, 0x635a, 0x6374,
0x6392, 0x63ae, 0x63c6, 0x63df, 0x63f5, 0x640d, 0x6423, 0x6439,
0x6451, 0x646f, 0x6487, 0x649f, 0x64c1, 0x64da, 0x64f3, 0x650d,
0x6527, 0x6548, 0x6566, 0x657e, 0x6596, 0x65af, 0x65c8, 0x65e7,
0x65ff, 0x6617, 0x662f, 0x6647, 0x665e, 0x6675, 0x668e, 0x66a6,
// Entry 7400 - 743F
0x66c1, 0x66d9, 0x66f1, 0x670a, 0x6728, 0x673f, 0x6756, 0x676e,
0x6785, 0x679d, 0x67b4, 0x67cc, 0x67e4, 0x67fb, 0x6813, 0x682b,
0x6843, 0x685c, 0x6873, 0x6889, 0x68a0, 0x68b7, 0x68cf, 0x68e7,
0x68ff, 0x6916, 0x692e, 0x6947, 0x6961, 0x6979, 0x6992, 0x69ac,
0x69c2, 0x69da, 0x69f3, 0x6a0a, 0x6a23, 0x6a3c, 0x6a54, 0x6a6d,
0x6a84, 0x6a9e, 0x6ab6, 0x6ace, 0x6ae5, 0x6afe, 0x6b17, 0x6b30,
0x6b48, 0x6b60, 0x6b77, 0x6b8e, 0x6ba7, 0x6bbf, 0x6bdb, 0x6bf4,
0x6c0c, 0x6c25, 0x6c3d, 0x6c54, 0x6c6b, 0x6c83, 0x6c9a, 0x6cb3,
// Entry 7440 - 747F
0x6ccb, 0x6ce2, 0x6cf9, 0x6d12, 0x6d2a, 0x6d42, 0x6d5c, 0x6d75,
0x6d82, 0x6d90, 0x6d9d, 0x6dab, 0x6db8, 0x6dc5, 0x6dd1, 0x6ddf,
0x6dee, 0x6dfc, 0x6e0a, 0x6e18, 0x6e28, 0x6e35, 0x6e44, 0x6e52,
0x6e5f, 0x6e6c, 0x6e78, 0x6e85, 0x6e93, 0x6ea2, 0x6eaf, 0x6ebc,
0x6ec8, 0x6ed5, 0x6ee3, 0x6ef0, 0x6efe, 0x6f0b, 0x6f19, 0x6f27,
0x6f34, 0x6f41, 0x6f50, 0x6f5e, 0x6f6c, 0x6f79, 0x6f88, 0x6f97,
0x6fa5, 0x6fae, 0x6fbe, 0x6fce, 0x6fde, 0x6fee, 0x6ffe, 0x700e,
0x701e, 0x702e, 0x703e, 0x704e, 0x705e, 0x706e, 0x707e, 0x708e,
// Entry 7480 - 74BF
0x709e, 0x70ae, 0x70be, 0x70ce, 0x70de, 0x70ee, 0x70fe, 0x710e,
0x711e, 0x712e, 0x713e, 0x714f, 0x7160, 0x7171, 0x7182, 0x7193,
0x71a4, 0x71b5, 0x71c6, 0x71dc, 0x71f2, 0x7209, 0x7220, 0x7231,
0x7242, 0x7253, 0x7264, 0x7276, 0x7288, 0x729a, 0x72ac, 0x72bc,
0x72cc, 0x72dc, 0x72ec, 0x72fc, 0x730d, 0x731d, 0x732e, 0x733e,
0x734e, 0x735e, 0x736e, 0x737f, 0x7390, 0x73a0, 0x73b0, 0x73c0,
0x73d0, 0x73e0, 0x73f1, 0x7401, 0x7411, 0x7421, 0x7432, 0x7443,
0x7453, 0x7464, 0x7475, 0x7487, 0x7498, 0x74a8, 0x74b8, 0x74c9,
// Entry 74C0 - 74FF
0x74da, 0x74ea, 0x74fb, 0x750b, 0x751b, 0x752d, 0x753e, 0x754f,
0x755f, 0x7571, 0x7583, 0x7594, 0x75a9, 0x75bc, 0x75cf, 0x75e2,
0x75f6, 0x760a, 0x761e, 0x7633, 0x7648, 0x765b, 0x7670, 0x7683,
0x7696, 0x76aa, 0x76bd, 0x76d0, 0x76e4, 0x76f7, 0x770a, 0x771d,
0x7732, 0x7745, 0x775b, 0x776d, 0x777f, 0x7792, 0x77a4, 0x77b7,
0x77c9, 0x77db, 0x77f8, 0x7814, 0x7830, 0x7850, 0x7871, 0x7884,
0x789b, 0x78b2, 0x78c8, 0x78de, 0x78f5, 0x790c, 0x7922, 0x7938,
0x794e, 0x7964, 0x797b, 0x7992, 0x79a9, 0x79c0, 0x79d7, 0x79ee,
// Entry 7500 - 753F
0x7a05, 0x7a1c, 0x7a32, 0x7a48, 0x7a5f, 0x7a76, 0x7a8c, 0x7aa2,
0x7ab8, 0x7ace, 0x7ae5, 0x7afc, 0x7b16, 0x7b32, 0x7b4c, 0x7b66,
0x7b81, 0x7b9b, 0x7bb6, 0x7bd1, 0x7beb, 0x7c06, 0x7c20, 0x7c3b,
0x7c57, 0x7c72, 0x7c8e, 0x7caa, 0x7cc4, 0x7cdd, 0x7cf7, 0x7d11,
0x7d2a, 0x7d42, 0x7d5b, 0x7d75, 0x7d8f, 0x7da8, 0x7dc2, 0x7ddc,
0x7dfc, 0x7e17, 0x7e32, 0x7e4c, 0x7e69, 0x7e84, 0x7e9f, 0x7ebb,
0x7ed5, 0x7ef0, 0x7f0a, 0x7f22, 0x7f38, 0x7f56, 0x7f6d, 0x7f83,
0x7f99, 0x7fb1, 0x7fc8, 0x7fdf, 0x7ff5, 0x800d, 0x8025, 0x803c,
// Entry 7540 - 757F
0x8054, 0x8070, 0x8091, 0x80ad, 0x80d1, 0x80f1, 0x810e, 0x8127,
0x813d, 0x8152, 0x8173, 0x818d, 0x81a3, 0x81b9, 0x81cf, 0x81e5,
0x81f9, 0x8216, 0x8232, 0x8247, 0x825c, 0x8271, 0x8299, 0x82ba,
0x82d4, 0x82f3, 0x8311, 0x832f, 0x834c, 0x8367, 0x8381, 0x839c,
0x83b8, 0x83d2, 0x83ed, 0x8408, 0x8423, 0x843e, 0x8459, 0x8474,
0x848e, 0x84a8, 0x84c2, 0x84dc, 0x84f7, 0x8511, 0x852b, 0x8542,
0x8556, 0x856c, 0x857e, 0x8591, 0x85a5, 0x85b8, 0x85cc, 0x85e0,
0x85f3, 0x8607, 0x861a, 0x862e, 0x8642, 0x8656, 0x866b, 0x867f,
// Entry 7580 - 75BF
0x8694, 0x86a7, 0x86bb, 0x86ce, 0x86e2, 0x86f5, 0x8708, 0x871c,
0x872f, 0x8743, 0x8756, 0x8769, 0x877c, 0x878f, 0x87a2, 0x87b5,
0x87c9, 0x87dc, 0x87f3, 0x8809, 0x881f, 0x8836, 0x884c, 0x8863,
0x8879, 0x8890, 0x88a5, 0x88b8, 0x88cb, 0x88da, 0x88f0, 0x8904,
0x8917, 0x892a, 0x893f, 0x8953, 0x8967, 0x897a, 0x898f, 0x89a4,
0x89b8, 0x89d4, 0x89f0, 0x8a0c, 0x8a28, 0x8a47, 0x8a63, 0x8a80,
0x8a9c, 0x8ab8, 0x8ad4, 0x8af0, 0x8b0c, 0x8b28, 0x8b44, 0x8b60,
0x8b7c, 0x8b98, 0x8bb4, 0x8bd0, 0x8bed, 0x8c09, 0x8c25, 0x8c42,
// Entry 75C0 - 75FF
0x8c5f, 0x8c7b, 0x8c97, 0x8cb4, 0x8cd0, 0x8cec, 0x8d08, 0x8d25,
0x8d41, 0x8d5b, 0x8d75, 0x8d8f, 0x8da9, 0x8dc6, 0x8de0, 0x8dfb,
0x8e15, 0x8e2f, 0x8e49, 0x8e63, 0x8e7d, 0x8e97, 0x8eb1, 0x8ecb,
0x8ee5, 0x8eff, 0x8f19, 0x8f33, 0x8f4e, 0x8f68, 0x8f82, 0x8f9d,
0x8fb8, 0x8fd2, 0x8fec, 0x9007, 0x9021, 0x903b, 0x9055, 0x9070,
0x908a, 0x90a0, 0x90b5, 0x90ca, 0x90e1, 0x90f7, 0x910d, 0x9122,
0x9139, 0x9150, 0x9166, 0x917c, 0x9195, 0x91ae, 0x91c9, 0x91e4,
0x91fe, 0x9218, 0x9234, 0x924f, 0x926a, 0x928e, 0x92b2, 0x92d8,
// Entry 7600 - 763F
0x92e9, 0x92fe, 0x9315, 0x932f, 0x934e, 0x936f, 0x938f, 0x93ab,
0x93ca, 0x93e9, 0x940b, 0x9426, 0x9444, 0x9462, 0x9481, 0x949f,
0x94bd, 0x94da, 0x94f8, 0x9514, 0x9530, 0x954f, 0x9575, 0x9593,
0x95b1, 0x95d3, 0x95ef, 0x960e, 0x962a, 0x9647, 0x9666, 0x9684,
0x969e, 0x96bb, 0x96d8, 0x96f8, 0x9711, 0x972d, 0x9749, 0x9766,
0x9782, 0x979e, 0x97b9, 0x97d5, 0x97ef, 0x9809, 0x9826, 0x984a,
0x9866, 0x9882, 0x98a2, 0x98bc, 0x98d9, 0x98f3, 0x9901, 0x990f,
0x9920, 0x992f, 0x993d, 0x994c, 0x9962, 0x9970, 0x997e, 0x998d,
// Entry 7640 - 767F
0x999b, 0x99a9, 0x99bb, 0x99cc, 0x99db, 0x99ea, 0x99f8, 0x9a07,
0x9a19, 0x9a2f, 0x9a3e, 0x9a4e, 0x9a5c, 0x9a6b, 0x9a7a, 0x9a8a,
0x9a9a, 0x9aaa, 0x9abb, 0x9acc, 0x9ada, 0x9ae8, 0x9af9, 0x9b07,
0x9b16, 0x9b25, 0x9b35, 0x9b4c, 0x9b5a, 0x9b68, 0x9b77, 0x9b87,
0x9b97, 0x9ba7, 0x9bb6, 0x9bc6, 0x9bd6, 0x9be6, 0x9bf9, 0x9c0c,
0x9c25, 0x9c34, 0x9c43, 0x9c52, 0x9c62, 0x9c71, 0x9c80, 0x9c92,
0x9ca0, 0x9cae, 0x9cbd, 0x9ccc, 0x9cdc, 0x9cf3, 0x9d03, 0x9d14,
0x9d22, 0x9d30, 0x9d3f, 0x9d4e, 0x9d5d, 0x9d6d, 0x9d7b, 0x9d8a,
// Entry 7680 - 76BF
0x9d99, 0x9db9, 0x9dd1, 0x9de5, 0x9dff, 0x9e1c, 0x9e2d, 0x9e3f,
0x9e52, 0x9e64, 0x9e77, 0x9e88, 0x9e9a, 0x9eac, 0x9ebd, 0x9ece,
0x9ee0, 0x9ef3, 0x9f06, 0x9f17, 0x9f29, 0x9f3c, 0x9f50, 0x9f62,
0x9f74, 0x9f86, 0x9f98, 0x9fab, 0x9fbc, 0x9fce, 0x9fe1, 0x9ff5,
0xa007, 0xa01a, 0xa02d, 0xa03e, 0xa050, 0xa062, 0xa075, 0xa088,
0xa0a3, 0xa0b5, 0xa0cf, 0xa0e1, 0xa0f3, 0xa105, 0xa117, 0xa128,
0xa13a, 0xa14d, 0xa160, 0xa172, 0xa185, 0xa197, 0xa1a9, 0xa1bb,
0xa1cf, 0xa1e1, 0xa1f0, 0xa203, 0xa212, 0xa221, 0xa233, 0xa245,
// Entry 76C0 - 76FF
0xa257, 0xa269, 0xa27b, 0xa28d, 0xa29f, 0xa2ba, 0xa2d5, 0xa2f0,
0xa30b, 0xa326, 0xa341, 0xa356, 0xa36a, 0xa37f, 0xa399, 0xa3b3,
0xa3d7, 0xa3fd, 0xa418, 0xa434, 0xa44e, 0xa470, 0xa48b, 0xa49f,
0xa4b3, 0xa4c7, 0xa4db, 0xa4ef, 0xa503, 0xa517, 0xa52b, 0xa53f,
0xa553, 0xa567, 0xa57b, 0xa58f, 0xa5a3, 0xa5b7, 0xa5cb, 0xa5df,
0xa5f3, 0xa607, 0xa61b, 0xa62f, 0xa643, 0xa657, 0xa66b, 0xa67f,
0xa693, 0xa6a7, 0xa6bb, 0xa6cf, 0xa6e3, 0xa6f7, 0xa70b, 0xa71f,
0xa733, 0xa747, 0xa75b, 0xa76f, 0xa783, 0xa797, 0xa7ab, 0xa7bf,
// Entry 7700 - 773F
0xa7d3, 0xa7e7, 0xa7fb, 0xa80f, 0xa823, 0xa837, 0xa84b, 0xa85f,
0xa873, 0xa887, 0xa89b, 0xa8af, 0xa8c3, 0xa8d7, 0xa8eb, 0xa8ff,
0xa913, 0xa927, 0xa93b, 0xa94f, 0xa963, 0xa977, 0xa98b, 0xa99f,
0xa9b3, 0xa9c7, 0xa9db, 0xa9ef, 0xaa03, 0xaa17, 0xaa2b, 0xaa3f,
0xaa53, 0xaa67, 0xaa7b, 0xaa8f, 0xaaa3, 0xaab7, 0xaacb, 0xaadf,
0xaaf3, 0xab07, 0xab1b, 0xab2f, 0xab43, 0xab57, 0xab6b, 0xab7f,
0xab93, 0xaba7, 0xabbb, 0xabcf, 0xabe3, 0xabf7, 0xac0b, 0xac1f,
0xac33, 0xac47, 0xac5b, 0xac6f, 0xac83, 0xac97, 0xacab, 0xacbf,
// Entry 7740 - 777F
0xacd3, 0xace7, 0xacfb, 0xad0f, 0xad23, 0xad37, 0xad4b, 0xad5f,
0xad73, 0xad87, 0xad9b, 0xadaf, 0xadc3, 0xadd7, 0xadeb, 0xadff,
0xae13, 0xae27, 0xae3b, 0xae4f, 0xae63, 0xae77, 0xae8b, 0xae9f,
0xaeb3, 0xaec7, 0xaedb, 0xaeef, 0xaf03, 0xaf17, 0xaf2b, 0xaf3f,
0xaf53, 0xaf67, 0xaf7b, 0xaf8f, 0xafa3, 0xafb7, 0xafcb, 0xafdf,
0xaff3, 0xb007, 0xb01b, 0xb02f, 0xb043, 0xb057, 0xb06b, 0xb07f,
0xb093, 0xb0a7, 0xb0bb, 0xb0cf, 0xb0e3, 0xb0f7, 0xb10b, 0xb11f,
0xb133, 0xb147, 0xb15b, 0xb16f, 0xb183, 0xb197, 0xb1ab, 0xb1bf,
// Entry 7780 - 77BF
0xb1d3, 0xb1e7, 0xb1fb, 0xb20f, 0xb223, 0xb237, 0xb24b, 0xb25f,
0xb273, 0xb287, 0xb29b, 0xb2af, 0xb2c3, 0xb2d7, 0xb2eb, 0xb2ff,
0xb313, 0xb327, 0xb33b, 0xb34f, 0xb363, 0xb377, 0xb38b, 0xb39f,
0xb3b3, 0xb3c7, 0xb3db, 0xb3ef, 0xb403, 0xb417, 0xb42b, 0xb43f,
0xb453, 0xb467, 0xb47b, 0xb48f, 0xb4a3, 0xb4b7, 0xb4cb, 0xb4df,
0xb4f3, 0xb507, 0xb51b, 0xb52f, 0xb543, 0xb557, 0xb56b, 0xb57f,
0xb593, 0xb5a7, 0xb5bb, 0xb5cf, 0xb5e3, 0xb5f7, 0xb60b, 0xb61f,
0xb633, 0xb647, 0xb65b, 0xb66f, 0xb683, 0xb697, 0xb6ab, 0xb6bf,
// Entry 77C0 - 77FF
0xb6d3, 0xb6e7, 0xb6fb, 0xb70f, 0xb723, 0xb737, 0xb74b, 0xb75f,
0xb773, 0xb787, 0xb79b, 0xb7af, 0xb7c3, 0xb7d7, 0xb7eb, 0xb7ff,
0xb813, 0xb827, 0xb83b, 0xb84f, 0xb863, 0xb877, 0xb88b, 0xb89f,
0xb8b3, 0xb8c7, 0xb8db, 0xb8ef, 0xb903, 0xb917, 0xb92b, 0xb93f,
0xb953, 0xb967, 0xb97b, 0xb98f, 0xb9a3, 0xb9b7, 0xb9cb, 0xb9df,
0xb9f3, 0xba07, 0xba1b, 0xba2f, 0xba43, 0xba57, 0xba6b, 0xba7f,
0xba93, 0xbaa7, 0xbabb, 0xbacf, 0xbae3, 0xbaf7, 0xbb0b, 0xbb1f,
0xbb33, 0xbb47, 0xbb5b, 0xbb6f, 0xbb83, 0xbb97, 0xbbab, 0xbbbf,
// Entry 7800 - 783F
0xbbd3, 0xbbe7, 0xbbfb, 0xbc0f, 0xbc23, 0xbc37, 0xbc4b, 0xbc5f,
0xbc73, 0xbc87, 0xbc9b, 0xbcaf, 0xbcc3, 0xbcd7, 0xbceb, 0xbcff,
0xbd13, 0xbd27, 0xbd3b, 0xbd4f, 0xbd63, 0xbd77, 0xbd8b, 0xbd9f,
0xbdb3, 0xbdc7, 0xbddb, 0xbdef, 0xbe03, 0xbe17, 0xbe2b, 0xbe3f,
0xbe53, 0xbe67, 0xbe7b, 0xbe8f, 0xbea3, 0xbeb7, 0xbecb, 0xbedf,
0xbef3, 0xbf07, 0xbf1b, 0xbf2f, 0xbf43, 0xbf57, 0xbf6b, 0xbf7f,
0xbf93, 0xbfa7, 0xbfbb, 0xbfcf, 0xbfe3, 0xbff7, 0xc00b, 0xc01f,
0xc033, 0xc047, 0xc05b, 0xc06f, 0xc083, 0xc097, 0xc0ab, 0xc0bf,
// Entry 7840 - 787F
0xc0d3, 0xc0e7, 0xc0fb, 0xc10f, 0xc123, 0xc137, 0xc14b, 0xc15f,
0xc173, 0xc187, 0xc19b, 0xc1af, 0xc1c3, 0xc1d7, 0xc1eb, 0xc1ff,
0xc213, 0xc227, 0xc23b, 0xc24f, 0xc263, 0xc277, 0xc28b, 0xc29f,
0xc2b3, 0xc2c7, 0xc2db, 0xc2ef, 0xc303, 0xc317, 0xc32b, 0xc33f,
0xc353, 0xc367, 0xc37b, 0xc38f, 0xc3a3, 0xc3b7, 0xc3cb, 0xc3df,
0xc3f3, 0xc407, 0xc41b, 0xc42f, 0xc443, 0xc457, 0xc46b, 0xc47f,
0xc493, 0xc4a7, 0xc4bb, 0xc4cf, 0xc4e3, 0xc4f7, 0xc50b, 0xc51f,
0xc533, 0xc547, 0xc55b, 0xc56f, 0xc583, 0xc597, 0xc5ab, 0xc5bf,
// Entry 7880 - 78BF
0xc5d3, 0xc5e7, 0xc5fb, 0xc60f, 0xc623, 0xc637, 0xc64b, 0xc65f,
0xc673, 0xc687, 0xc69b, 0xc6af, 0xc6c3, 0xc6d7, 0xc6eb, 0xc6ff,
0xc713, 0xc727, 0xc73b, 0xc74f, 0xc763, 0xc777, 0xc78b, 0xc79f,
0xc7b3, 0xc7c7, 0xc7db, 0xc7ef, 0xc803, 0xc817, 0xc82b, 0xc83f,
0xc853, 0xc867, 0xc87b, 0xc88f, 0xc8a3, 0xc8b7, 0xc8cb, 0xc8df,
0xc8f3, 0xc907, 0xc91b, 0xc92f, 0xc943, 0xc957, 0xc96b, 0xc97f,
0xc993, 0xc9a7, 0xc9bb, 0xc9cf, 0xc9e3, 0xc9f7, 0xca0b, 0xca1f,
0xca33, 0xca47, 0xca5b, 0xca6f, 0xca83, 0xca97, 0xcaab, 0xcabf,
// Entry 78C0 - 78FF
0xcad3, 0xcae7, 0xcafb, 0xcb0f, 0xcb23, 0xcb37, 0xcb4b, 0xcb5f,
0xcb73, 0xcb87, 0xcb9b, 0xcbaf, 0xcbc3, 0xcbd7, 0xcbeb, 0xcbff,
0xcc13, 0xcc27, 0xcc3b, 0xcc4f, 0xcc63, 0xcc77, 0xcc8b, 0xcc9f,
0xccb3, 0xccc7, 0xccdb, 0xccef, 0xcd03, 0xcd17, 0xcd2b, 0xcd3f,
0xcd53, 0xcd67, 0xcd7b, 0xcd8f, 0xcda3, 0xcdb7, 0xcdcb, 0xcddf,
0xcdf3, 0xce07, 0xce1b, 0xce2f, 0xce43, 0xce57, 0xce6b, 0xce7f,
0xce93, 0xcea7, 0xcebb, 0xcecf, 0xcee3, 0xcef7, 0xcf0b, 0xcf1f,
0xcf33, 0xcf47, 0xcf5b, 0xcf6f, 0xcf83, 0xcf97, 0xcfab, 0xcfbf,
// Entry 7900 - 793F
0xcfd3, 0xcfe7, 0xcffb, 0xd00f, 0xd023, 0xd037, 0xd04b, 0xd05f,
0xd073, 0xd087, 0xd09b, 0xd0af, 0xd0c3, 0xd0d7, 0xd0eb, 0xd0ff,
0xd113, 0xd127, 0xd13b, 0xd14f, 0xd163, 0xd177, 0xd18b, 0xd19f,
0xd1b3, 0xd1c7, 0xd1db, 0xd1ef, 0xd203, 0xd217, 0xd22b, 0xd23f,
0xd253, 0xd267, 0xd27b, 0xd28f, 0xd2a3, 0xd2b7, 0xd2cb, 0xd2df,
0xd2f3, 0xd307, 0xd31b, 0xd32f, 0xd343, 0xd357, 0xd36b, 0xd37f,
0xd393, 0xd3a7, 0xd3bb, 0xd3cf, 0xd3e3, 0xd3f7, 0xd40b, 0xd41f,
0xd433, 0xd447, 0xd45b, 0xd46f, 0xd483, 0xd497, 0xd4ab, 0xd4bf,
// Entry 7940 - 797F
0xd4d3, 0xd4e7, 0xd4fb, 0xd50f, 0xd523, 0xd537, 0xd54b, 0xd55f,
0xd573, 0xd587, 0xd59b, 0xd5af, 0xd5c3, 0xd5d7, 0xd5eb, 0xd5ff,
0xd613, 0xd627, 0xd63b, 0xd64f, 0xd663, 0xd677, 0xd68b, 0xd69f,
0xd6b3, 0xd6c7, 0xd6db, 0xd6ef, 0xd703, 0xd717, 0xd72b, 0xd73f,
0xd753, 0xd767, 0xd77b, 0xd78f, 0xd7a3, 0xd7b7, 0xd7cb, 0xd7df,
0xd7f3, 0xd807, 0xd81b, 0xd82f, 0xd843, 0xd857, 0xd86b, 0xd87f,
0xd893, 0xd8a7, 0xd8bb, 0xd8cf, 0xd8e3, 0xd8f7, 0xd90b, 0xd91f,
0xd933, 0xd947, 0xd95b, 0xd96f, 0xd983, 0xd997, 0xd9ab, 0xd9bf,
// Entry 7980 - 79BF
0xd9d3, 0xd9e7, 0xd9fb, 0xda0f, 0xda23, 0xda37, 0xda4b, 0xda5f,
0xda73, 0xda87, 0xda9b, 0xdaaf, 0xdac3, 0xdad7, 0xdaeb, 0xdaff,
0xdb13, 0xdb27, 0xdb3b, 0xdb4f, 0xdb63, 0xdb77, 0xdb8b, 0xdb9f,
0xdbb3, 0xdbc7, 0xdbdb, 0xdbef, 0xdc03, 0xdc17, 0xdc2b, 0xdc3f,
0xdc53, 0xdc67, 0xdc7b, 0xdc8f, 0xdca3, 0xdcb7, 0xdccb, 0xdcdf,
0xdcf3, 0xdd07, 0xdd1b, 0xdd2f, 0xdd43, 0xdd57, 0xdd6b, 0xdd7f,
0xdd93, 0xdda7, 0xddbb, 0xddcf, 0xdde3, 0xddf7, 0xde0b, 0xde1f,
0xde33, 0xde47, 0xde5b, 0xde6f, 0xde83, 0xde97, 0xdeab, 0xdebf,
// Entry 79C0 - 79FF
0xded3, 0xdee7, 0xdefb, 0xdf0f, 0xdf23, 0xdf37, 0xdf4b, 0xdf5f,
0xdf73, 0xdf87, 0xdf9b, 0xdfaf, 0xdfc3, 0xdfd7, 0xdfeb, 0xdfff,
0xe013, 0xe027, 0xe03b, 0xe04f, 0xe063, 0xe077, 0xe08b, 0xe0ae,
0xe0d1, 0xe0f4, 0xe117, 0xe13a, 0xe15d, 0xe180, 0xe1a3, 0xe1c6,
0xe1e9, 0xe20c, 0xe22f, 0xe252, 0xe275, 0xe298, 0xe2bb, 0xe2de,
0xe301, 0xe324, 0xe347, 0xe36a, 0xe38d, 0xe3b0, 0xe3d3, 0xe3f6,
0xe419, 0xe43c, 0xe45f, 0xe482, 0xe4a5, 0xe4c8, 0xe4eb, 0xe50e,
0xe531, 0xe554, 0xe577, 0xe59a, 0xe5bd, 0xe5e0, 0xe603, 0xe626,
// Entry 7A00 - 7A3F
0xe649, 0xe66c, 0xe68f, 0xe6b2, 0xe6d5, 0xe6f8, 0xe71b, 0xe73e,
0xe761, 0xe784, 0xe7a7, 0xe7ca, 0xe7ed, 0xe810, 0xe833, 0xe856,
0xe879, 0xe89c, 0xe8bf, 0xe8e2, 0xe905, 0xe928, 0xe94b, 0xe96e,
0xe991, 0xe9b4, 0xe9d7, 0xe9fa, 0xea1d, 0xea40, 0xea63, 0xea86,
0xeaa9, 0xeacc, 0xeaef, 0xeb12, 0xeb35, 0xeb58, 0xeb7b, 0xeb9e,
0xebc1, 0xebe4, 0xec07, 0xec2a, 0xec4d, 0xec70, 0xec93, 0xecb6,
0xecd9, 0xecfc, 0xed1f, 0xed42, 0xed65, 0xed88, 0xedab, 0xedce,
0xedf1, 0xee14, 0xee37, 0xee5a, 0xee7d, 0xeea0, 0xeec3, 0xeee6,
// Entry 7A40 - 7A7F
0xef09, 0xef2c, 0xef4f, 0xef72, 0xef95, 0xefb8, 0xefdb, 0xeffe,
0xf021, 0xf044, 0xf067, 0xf08a, 0xf0ad, 0xf0d0, 0xf0f3, 0xf116,
0xf139, 0xf15c, 0xf17f, 0xf1a2, 0xf1c5, 0xf1e8, 0xf20b, 0xf22e,
0xf251, 0xf274, 0xf297, 0xf2ba, 0xf2dd, 0xf300, 0xf323, 0xf346,
0xf369, 0xf38c, 0xf3af, 0xf3d2, 0xf3f5, 0xf418, 0xf43b, 0xf45e,
0xf481, 0xf4a4, 0xf4c7, 0xf4ea, 0xf50d, 0xf530, 0xf553, 0xf576,
0xf599, 0xf5bc, 0xf5df, 0xf602, 0xf625, 0xf648, 0xf66b, 0xf68e,
0xf6b1, 0xf6d4, 0xf6f7, 0xf71a, 0xf73d, 0xf760, 0xf783, 0xf7a6,
// Entry 7A80 - 7ABF
0xf7c9, 0xf7ec, 0xf80f, 0xf832, 0xf855, 0xf878, 0xf89b, 0xf8be,
0xf8e1, 0xf904, 0xf927, 0xf94a, 0xf96d, 0xf990, 0xf9b3, 0xf9d6,
0xf9f9, 0xfa1c, 0xfa3f, 0xfa62, 0xfa85, 0xfaa8, 0xfacb, 0xfaee,
0xfb11, 0xfb34, 0xfb57, 0xfb7a, 0xfb9d, 0xfbc0, 0xfbe3, 0xfc06,
0xfc29, 0xfc4c, 0xfc6f, 0xfc92, 0xfcb5, 0xfcd8, 0xfcfb, 0xfd1e,
0xfd41, 0xfd64, 0xfd87, 0xfdaa, 0xfdcd, 0xfdf0, 0xfe13, 0xfe36,
0xfe59, 0xfe7c, 0xfe9f, 0xfec2, 0xfee5, 0xff08, 0xff2b, 0xff4e,
0xff71, 0xff94, 0xffb7, 0xffda, 0xfffd, 0x0020, 0x0043, 0x0066,
// Entry 7AC0 - 7AFF
0x0089, 0x00ac, 0x00cf, 0x00f2, 0x0115, 0x0138, 0x015b, 0x017e,
0x01a1, 0x01c4, 0x01e7, 0x020a, 0x022d, 0x0250, 0x0273, 0x0296,
0x02b9, 0x02dc, 0x02ff, 0x0322, 0x0345, 0x0368, 0x038b, 0x03ae,
0x03d1, 0x03f4, 0x0417, 0x043a, 0x045d, 0x0480, 0x04a3, 0x04c6,
0x04e9, 0x050c, 0x052f, 0x0552, 0x0575, 0x0598, 0x05bb, 0x05de,
0x0601, 0x0624, 0x0647, 0x066a, 0x068d, 0x06b0, 0x06d3, 0x06f6,
0x0719, 0x073c, 0x075f, 0x0782, 0x07a5, 0x07c8, 0x07eb, 0x080e,
0x0831, 0x0854, 0x0877, 0x089a, 0x08bd, 0x08e0, 0x0903, 0x0926,
// Entry 7B00 - 7B3F
0x0949, 0x096c, 0x098f, 0x09b2, 0x09d5, 0x09f8, 0x0a1b, 0x0a3e,
0x0a61, 0x0a84, 0x0aa7, 0x0aca, 0x0aed, 0x0b10, 0x0b33, 0x0b56,
0x0b79, 0x0b9c, 0x0bbf, 0x0be2, 0x0c05, 0x0c28, 0x0c4b, 0x0c6e,
0x0c91, 0x0cb4, 0x0cd7, 0x0cfa, 0x0d1d, 0x0d40, 0x0d63, 0x0d86,
0x0da9, 0x0dcc, 0x0def, 0x0e12, 0x0e35, 0x0e58, 0x0e7b, 0x0e9e,
0x0ec1, 0x0ee4, 0x0f07, 0x0f2a, 0x0f4d, 0x0f70, 0x0f93, 0x0fb6,
0x0fd9, 0x0ffc, 0x101f, 0x1042, 0x1065, 0x1088, 0x10ab, 0x10ce,
0x10f1, 0x1114, 0x1137, 0x115a, 0x117d, 0x11a0, 0x11c3, 0x11e6,
// Entry 7B40 - 7B7F
0x1209, 0x122c, 0x124f, 0x1272, 0x1295, 0x12b8, 0x12db, 0x12fe,
0x1321, 0x1344, 0x1367, 0x138a, 0x13ad, 0x13d0, 0x13f3, 0x1416,
0x1439, 0x145c, 0x147f, 0x14a2, 0x14c5, 0x14e8, 0x150b, 0x152e,
0x1551, 0x1574, 0x1597, 0x15ba, 0x15dd, 0x1600, 0x1623, 0x1646,
0x1669, 0x168c, 0x16af, 0x16d2, 0x16f5, 0x1718, 0x173b, 0x175e,
0x1781, 0x17a4, 0x17c7, 0x17ea, 0x180d, 0x1830, 0x1853, 0x1876,
0x1899, 0x18bc, 0x18df, 0x1902, 0x1925, 0x1948, 0x196b, 0x198e,
0x19b1, 0x19d4, 0x19f7, 0x1a1a, 0x1a3d, 0x1a60, 0x1a83, 0x1aa6,
// Entry 7B80 - 7BBF
0x1ac9, 0x1aec, 0x1b0f, 0x1b32, 0x1b55, 0x1b78, 0x1b9b, 0x1bbe,
0x1be1, 0x1c04, 0x1c27, 0x1c4a, 0x1c6d, 0x1c90, 0x1cb3, 0x1cd6,
0x1cf9, 0x1d1c, 0x1d3f, 0x1d62, 0x1d85, 0x1da8, 0x1dcb, 0x1dee,
0x1e11, 0x1e34, 0x1e57, 0x1e7a, 0x1e9d, 0x1ec0, 0x1ee3, 0x1f06,
0x1f29, 0x1f4c, 0x1f6f, 0x1f92, 0x1fb5, 0x1fd8, 0x1ffb, 0x201e,
0x2041, 0x2064, 0x2087, 0x20aa, 0x20cd, 0x20f0, 0x2104, 0x2118,
0x212c, 0x2140, 0x2154, 0x2168, 0x217c, 0x2190, 0x21a4, 0x21b8,
0x21cc, 0x21e0, 0x21f4, 0x2208, 0x221c, 0x2230, 0x2244, 0x2258,
// Entry 7BC0 - 7BFF
0x226c, 0x2280, 0x2294, 0x22a8, 0x22bc, 0x22d0, 0x22e4, 0x22f8,
0x230c, 0x2320, 0x2334, 0x2348, 0x235c, 0x2370, 0x2384, 0x2398,
0x23ac, 0x23c0, 0x23d4, 0x23e8, 0x23fc, 0x2410, 0x2424, 0x2438,
0x244c, 0x2460, 0x2474, 0x2488, 0x249c, 0x24b0, 0x24c4, 0x24d8,
0x24ec, 0x2500, 0x2514, 0x2528, 0x253c, 0x2550, 0x2564, 0x2578,
0x258c, 0x25a0, 0x25b4, 0x25c8, 0x25dc, 0x25f0, 0x2604, 0x2618,
0x262c, 0x2640, 0x2654, 0x2668, 0x267c, 0x2690, 0x26a4, 0x26b8,
0x26cc, 0x26e0, 0x26f4, 0x2708, 0x271c, 0x2730, 0x2744, 0x2758,
// Entry 7C00 - 7C3F
0x276c, 0x2780, 0x2794, 0x27a8, 0x27bc, 0x27d0, 0x27e4, 0x27f8,
0x280c, 0x2820, 0x2834, 0x2848, 0x285c, 0x2870, 0x2884, 0x2898,
0x28ac, 0x28c0, 0x28d4, 0x28e8, 0x28fc, 0x2910, 0x2924, 0x2938,
0x294c, 0x2960, 0x2974, 0x2988, 0x299c, 0x29b0, 0x29c4, 0x29d8,
0x29ec, 0x2a09, 0x2a26, 0x2a43, 0x2a60, 0x2a7d, 0x2a9a, 0x2ac1,
0x2ae8, 0x2b0f, 0x2b36, 0x2b5d, 0x2b84, 0x2bab, 0x2bc4, 0x2bde,
0x2bf3, 0x2c08, 0x2c1d, 0x2c33, 0x2c48, 0x2c5d, 0x2c72, 0x2c87,
0x2c9c, 0x2cb1, 0x2cc6, 0x2cdb, 0x2cf0, 0x2d05, 0x2d1a, 0x2d2f,
// Entry 7C40 - 7C7F
0x2d44, 0x2d59, 0x2d6e, 0x2d83, 0x2d98, 0x2dae, 0x2dc4, 0x2dda,
0x2df0, 0x2e06, 0x2e1c, 0x2e32, 0x2e48, 0x2e5e, 0x2e75, 0x2e8c,
0x2ea3, 0x2eb9, 0x2ecf, 0x2ee5, 0x2efb, 0x2f11, 0x2f27, 0x2f3d,
0x2f53, 0x2f69, 0x2f7f, 0x2f95, 0x2fab, 0x2fc1, 0x2fd7, 0x2fed,
0x3003, 0x3019, 0x302f, 0x3045, 0x305b, 0x3071, 0x3087, 0x309d,
0x30b3, 0x30ca, 0x30e0, 0x30f6, 0x310c, 0x3122, 0x3138, 0x314e,
0x3164, 0x317a, 0x3190, 0x31a6, 0x31bc, 0x31d2, 0x31e8, 0x31fe,
0x3214, 0x322a, 0x3240, 0x3256, 0x326c, 0x3282, 0x3298, 0x32ae,
// Entry 7C80 - 7CBF
0x32c4, 0x32da, 0x32f0, 0x3306, 0x331c, 0x3332, 0x3348, 0x335e,
0x3374, 0x338a, 0x33a0, 0x33b6, 0x33cc, 0x33e2, 0x33f8, 0x340e,
0x3424, 0x343a, 0x3450, 0x3466, 0x347c, 0x3492, 0x34a8, 0x34be,
0x34d4, 0x34ea, 0x3500, 0x3517, 0x352d, 0x3543, 0x3559, 0x356f,
0x3585, 0x359b, 0x35b1, 0x35c7, 0x35dd, 0x35f3, 0x3609, 0x361f,
0x3635, 0x364b, 0x3661, 0x3678, 0x368e, 0x36a4, 0x36ba, 0x36d0,
0x36e6, 0x36fc, 0x3712, 0x3728, 0x373e, 0x3754, 0x376a, 0x3780,
0x3796, 0x37ac, 0x37c2, 0x37d8, 0x37ef, 0x3805, 0x381b, 0x3831,
// Entry 7CC0 - 7CFF
0x3847, 0x385d, 0x3873, 0x3889, 0x389f, 0x38b5, 0x38cc, 0x38e2,
0x38f8, 0x390e, 0x3924, 0x393a, 0x3950, 0x3966, 0x397c, 0x3992,
0x39a8, 0x39be, 0x39d4, 0x39ea, 0x3a00, 0x3a17, 0x3a2e, 0x3a44,
0x3a5a, 0x3a70, 0x3a86, 0x3a9c, 0x3ab2, 0x3ac8, 0x3ade, 0x3af4,
0x3b0a, 0x3b20, 0x3b36, 0x3b4c, 0x3b62, 0x3b78, 0x3b8e, 0x3ba4,
0x3bba, 0x3bd0, 0x3be6, 0x3bfc, 0x3c12, 0x3c28, 0x3c3e, 0x3c54,
0x3c6a, 0x3c80, 0x3c96, 0x3cac, 0x3cc2, 0x3cd8, 0x3cee, 0x3d04,
0x3d1a, 0x3d30, 0x3d46, 0x3d5c, 0x3d72, 0x3d88, 0x3d9e, 0x3db4,
// Entry 7D00 - 7D3F
0x3dca, 0x3de0, 0x3df6, 0x3e0c, 0x3e23, 0x3e39, 0x3e4f, 0x3e65,
0x3e7b, 0x3e91, 0x3ea7, 0x3ebd, 0x3ed3, 0x3ee9, 0x3eff, 0x3f15,
0x3f2c, 0x3f42, 0x3f58, 0x3f6e, 0x3f84, 0x3f9a, 0x3fb0, 0x3fc6,
0x3fdc, 0x3ff2, 0x4008, 0x401e, 0x4034, 0x404a, 0x4060, 0x4076,
0x408c, 0x40a2, 0x40b8, 0x40ce, 0x40e4, 0x40fa, 0x4110, 0x4126,
0x413c, 0x4152, 0x4168, 0x417e, 0x4194, 0x41aa, 0x41c0, 0x41d6,
0x41ec, 0x4202, 0x4218, 0x422e, 0x4244, 0x425a, 0x4270, 0x4286,
0x429c, 0x42b2, 0x42c8, 0x42de, 0x42f4, 0x430a, 0x4320, 0x4336,
// Entry 7D40 - 7D7F
0x434c, 0x4362, 0x4378, 0x438e, 0x43a4, 0x43ba, 0x43d0, 0x43e6,
0x43fc, 0x4412, 0x4428, 0x4443, 0x445e, 0x4478, 0x4492, 0x44ac,
0x44c6, 0x44de, 0x44f6, 0x450e, 0x4526, 0x453e, 0x4556, 0x456e,
0x4586, 0x459d, 0x45b2, 0x45c7, 0x45dc, 0x45f1, 0x4606, 0x461b,
0x4630, 0x4645, 0x465a, 0x466f, 0x4684, 0x4699, 0x46ae, 0x46c3,
0x46d8, 0x46ed, 0x4702, 0x4717, 0x472c, 0x4741, 0x4756, 0x476b,
0x4780, 0x4795, 0x47aa, 0x47bf, 0x47d4, 0x47e9, 0x47fe, 0x4813,
0x4828, 0x483d, 0x4852, 0x4867, 0x487c, 0x4891, 0x48a6, 0x48bb,
// Entry 7D80 - 7DBF
0x48d0, 0x48e5, 0x48fa, 0x490f, 0x4924, 0x4939, 0x494e, 0x4963,
0x4978, 0x498d, 0x49a2, 0x49b7, 0x49cc, 0x49e1, 0x49f6, 0x4a0b,
0x4a20, 0x4a35, 0x4a4a, 0x4a5f, 0x4a74, 0x4a89, 0x4a9e, 0x4ab3,
0x4ac8, 0x4add, 0x4af2, 0x4b07, 0x4b1c, 0x4b31, 0x4b46, 0x4b5b,
0x4b70, 0x4b85, 0x4b9a, 0x4baf, 0x4bc4, 0x4bd9, 0x4bee, 0x4c03,
0x4c18, 0x4c2d, 0x4c42, 0x4c57, 0x4c6c, 0x4c81, 0x4c96, 0x4cab,
0x4cc0, 0x4cd5, 0x4cea, 0x4cff, 0x4d14, 0x4d29, 0x4d3e, 0x4d53,
0x4d68, 0x4d7d, 0x4d92, 0x4da7, 0x4dbc, 0x4dd1, 0x4de6, 0x4dfb,
// Entry 7DC0 - 7DFF
0x4e10, 0x4e25, 0x4e3a, 0x4e4f, 0x4e64, 0x4e79, 0x4e8e, 0x4ea3,
0x4eb8, 0x4ecd, 0x4ee2, 0x4ef7, 0x4f0c, 0x4f21, 0x4f36, 0x4f4b,
0x4f60, 0x4f75, 0x4f8a, 0x4f9f, 0x4fb4, 0x4fc9, 0x4fde, 0x4ff3,
0x5008, 0x501d, 0x5032, 0x5047, 0x505c, 0x5071, 0x5086, 0x509b,
0x50b0, 0x50c5, 0x50da, 0x50ef, 0x5104, 0x5119, 0x512e, 0x5143,
0x5158, 0x516d, 0x5182, 0x5197, 0x51ac, 0x51c1, 0x51d6, 0x51eb,
0x5200, 0x5215, 0x522a, 0x523f, 0x5254, 0x5269, 0x527e, 0x5293,
0x52a8, 0x52bd, 0x52d2, 0x52e7, 0x52fc, 0x5311, 0x5326, 0x533b,
// Entry 7E00 - 7E3F
0x5350, 0x5365, 0x537a, 0x538f, 0x53a4, 0x53b9, 0x53ce, 0x53e3,
0x53f8, 0x540d, 0x5422, 0x5437, 0x544c, 0x5461, 0x5476, 0x548b,
0x54a0, 0x54b5, 0x54ca, 0x54df, 0x54f4, 0x5509, 0x551e, 0x5533,
0x5548, 0x555d, 0x5572, 0x5587, 0x559c, 0x55b1, 0x55c6, 0x55db,
0x55f0, 0x5605, 0x561a, 0x562f, 0x5644, 0x5659, 0x566e, 0x5683,
0x5698, 0x56ad, 0x56c2, 0x56d7, 0x56ec, 0x5701, 0x5716, 0x572b,
0x5740, 0x5755, 0x576a, 0x577f, 0x5794, 0x57a9, 0x57be, 0x57d3,
0x57e8, 0x57fd, 0x5812, 0x5827, 0x583c, 0x5851, 0x5866, 0x587b,
// Entry 7E40 - 7E7F
0x5890, 0x58a5, 0x58ba, 0x58cf, 0x58e4, 0x58f9, 0x590e, 0x5923,
0x5938, 0x594d, 0x5962, 0x5977, 0x598c, 0x59a1, 0x59b6, 0x59cb,
0x59e0, 0x59f5, 0x5a0a, 0x5a1f, 0x5a34, 0x5a49, 0x5a5e, 0x5a73,
0x5a88, 0x5a9d, 0x5ab2, 0x5ac7, 0x5adc, 0x5af1, 0x5b06, 0x5b1b,
0x5b30, 0x5b45, 0x5b5a, 0x5b6f, 0x5b84, 0x5b99, 0x5bae, 0x5bc3,
0x5bd8, 0x5bed, 0x5c02, 0x5c17, 0x5c2c, 0x5c41, 0x5c56, 0x5c6b,
0x5c80, 0x5c95, 0x5caa, 0x5cbf, 0x5cd4, 0x5ce9, 0x5cfe, 0x5d13,
0x5d28, 0x5d3d, 0x5d52, 0x5d67, 0x5d7c, 0x5d91, 0x5da6, 0x5dbb,
// Entry 7E80 - 7EBF
0x5dd0, 0x5de5, 0x5dfa, 0x5e0f, 0x5e24, 0x5e39, 0x5e4e, 0x5e63,
0x5e78, 0x5e8d, 0x5ea2, 0x5eb7, 0x5ecc, 0x5ee1, 0x5ef6, 0x5f0b,
0x5f20, 0x5f35, 0x5f4a, 0x5f5f, 0x5f74, 0x5f89, 0x5f9e, 0x5fb3,
0x5fc8, 0x5fdd, 0x5ff2, 0x6007, 0x601c, 0x6031, 0x6046, 0x605b,
0x6070, 0x6085, 0x609a, 0x60af, 0x60c4, 0x60d9, 0x60ee, 0x6103,
0x6118, 0x612d, 0x6142, 0x6157, 0x616c, 0x6181, 0x6196, 0x61ab,
0x61c0, 0x61d5, 0x61ea, 0x61ff, 0x6214, 0x6229, 0x623e, 0x6253,
0x6268, 0x627d, 0x6292, 0x62a7, 0x62bc, 0x62d1, 0x62e6, 0x62fb,
// Entry 7EC0 - 7EFF
0x6310, 0x6325, 0x633a, 0x634f, 0x6364, 0x6379, 0x638e, 0x63a3,
0x63b8, 0x63cd, 0x63e2, 0x63f7, 0x640c, 0x6421, 0x6436, 0x644b,
0x6460, 0x6475, 0x648a, 0x649f, 0x64b4, 0x64c9, 0x64de, 0x64f3,
0x6508, 0x651d, 0x6532, 0x6547, 0x655c, 0x6571, 0x6586, 0x659b,
0x65b0, 0x65c5, 0x65da, 0x65ef, 0x6604, 0x6619, 0x662a, 0x663b,
0x664c, 0x665d, 0x666e, 0x667f, 0x6690, 0x66a1, 0x66b2, 0x66c3,
0x66d4, 0x66e5, 0x66f8, 0x670b, 0x671e, 0x6731, 0x6744, 0x6756,
0x676e, 0x6780, 0x6792, 0x67a9, 0x67bb, 0x67cd, 0x67df, 0x67f0,
// Entry 7F00 - 7F3F
0x6801, 0x6812, 0x6823, 0x6836, 0x6849, 0x685c, 0x686f, 0x6889,
0x68a3, 0x68bd, 0x68e9, 0x6903, 0x6923, 0x6936, 0x6949, 0x695c,
0x696f, 0x6984, 0x6999, 0x69ae, 0x69c3, 0x69df, 0x69f2, 0x6a07,
0x6a1a, 0x6a2f, 0x6a42, 0x6a57, 0x6a6a, 0x6a7f, 0x6a90, 0x6aa2,
0x6ab5, 0x6ac8, 0x6adb, 0x6af0, 0x6b05, 0x6b18, 0x6b2d, 0x6b3e,
0x6b56, 0x6b68, 0x6b79, 0x6b8c, 0x6b9d, 0x6bae, 0x6bc0, 0x6bd7,
0x6be9, 0x6bfb, 0x6c13, 0x6c2d, 0x6c45, 0x6c5b, 0x6c6d, 0x6c7e,
0x6c90, 0x6ca2, 0x6cb5, 0x6ccb, 0x6ce5, 0x6cf7, 0x6d0e, 0x6d21,
// Entry 7F40 - 7F7F
0x6d33, 0x6d45, 0x6d57, 0x6d69, 0x6d7b, 0x6d8e, 0x6da1, 0x6db8,
0x6dcf, 0x6de6, 0x6dfd, 0x6e16, 0x6e2f, 0x6e47, 0x6e5f, 0x6e77,
0x6e90, 0x6eb5, 0x6ed9, 0x6eff, 0x6f21, 0x6f43, 0x6f66, 0x6f84,
0x6fb0, 0x6fcf, 0x6feb, 0x7009, 0x7027, 0x704b, 0x7064, 0x7083,
0x709c, 0x70ba, 0x70d1, 0x70eb, 0x7103, 0x711b, 0x7137, 0x714f,
0x716d, 0x7185, 0x71a2, 0x71b8, 0x71d1, 0x71e8, 0x71ff, 0x721a,
0x7232, 0x724c, 0x726a, 0x727e, 0x72a4, 0x72c3, 0x72e6, 0x7300,
0x7318, 0x732b, 0x7341, 0x735b, 0x7376, 0x7390, 0x73ae, 0x73ca,
// Entry 7F80 - 7FBF
0x73e3, 0x73ea, 0x7405, 0x741e, 0x7431, 0x7446, 0x745a, 0x746d,
0x7481, 0x748f, 0x749d, 0x74a7, 0x74bb, 0x74cd, 0x74da, 0x74e8,
0x7502, 0x751c, 0x752d, 0x7552, 0x757f, 0x75ac, 0x75d1, 0x75f9,
0x762f, 0x7665, 0x767f, 0x7699, 0x76b4, 0x76ce, 0x76e9, 0x7704,
0x7720, 0x773a, 0x7755, 0x7770, 0x778c, 0x77a7, 0x77c3, 0x77df,
0x77fc, 0x7815, 0x7835, 0x7856, 0x7870, 0x7890, 0x78a9, 0x78c3,
0x78e4, 0x7904, 0x791d, 0x7937, 0x7958, 0x7971, 0x7991, 0x79b2,
0x79cc, 0x79e2, 0x79f6, 0x7a10, 0x7a28, 0x7a3b, 0x7a50, 0x7a64,
// Entry 7FC0 - 7FFF
0x7a78, 0x7a8c, 0x7aa1, 0x7ab9, 0x7ad4, 0x7aeb, 0x7b04, 0x7b1e,
0x7b3a, 0x7b53, 0x7b6b, 0x7b81, 0x7b94, 0x7ba8, 0x7bbc, 0x7bd5,
0x7bec, 0x7c06, 0x7c1f, 0x7c39, 0x7c56, 0x7c71, 0x7c8e, 0x7cae,
0x7ccc, 0x7ce5, 0x7cfc, 0x7d16, 0x7d2f, 0x7d3d, 0x7d50, 0x7d61,
0x7d75, 0x7d88, 0x7d99, 0x7dab, 0x7dd8, 0x7e06, 0x7e34, 0x7e62,
0x7e74, 0x7e9a, 0x7ebe, 0x7ee5, 0x7f0b, 0x7f33, 0x7f59, 0x7f82,
0x7faa, 0x7fc3, 0x7fda, 0x7ff4, 0x800d, 0x8028, 0x8044, 0x8063,
0x8081, 0x809f, 0x80bb, 0x80da, 0x80f8, 0x8107, 0x8118, 0x8130,
// Entry 8000 - 803F
0x8149, 0x8167, 0x8182, 0x819e, 0x81c0, 0x81cf, 0x81e4, 0x8221,
0x823b, 0x825d, 0x8281, 0x8291, 0x82a2, 0x82c2, 0x82e3, 0x82f0,
0x8308, 0x831e, 0x8337, 0x834f, 0x8364, 0x8377, 0x8387, 0x8399,
0x83ac, 0x83c8, 0x83e5, 0x8405, 0x8426, 0x843d, 0x8455, 0x847c,
0x84a4, 0x84cd, 0x84f7, 0x8517, 0x8538, 0x8558, 0x8579, 0x85a1,
0x85ca, 0x85eb, 0x860d, 0x862b, 0x864a, 0x8668, 0x8687, 0x86a8,
0x86ca, 0x86eb, 0x870d, 0x872b, 0x874a, 0x8768, 0x8787, 0x87a6,
0x87c6, 0x87e5, 0x8805, 0x8823, 0x8842, 0x8860, 0x887f, 0x889f,
// Entry 8040 - 807F
0x88c0, 0x88e0, 0x8901, 0x8921, 0x8942, 0x8962, 0x8983, 0x89a1,
0x89c0, 0x89de, 0x89fd, 0x8a20, 0x8a44, 0x8a67, 0x8a8b, 0x8aaa,
0x8ac9, 0x8ae8, 0x8b07, 0x8b26, 0x8b45, 0x8b64, 0x8b83, 0x8ba2,
0x8bc1, 0x8be0, 0x8bff, 0x8c1e, 0x8c3d, 0x8c5c, 0x8c7b, 0x8c9a,
0x8cb9, 0x8cd8, 0x8cf7, 0x8d16, 0x8d35, 0x8d54, 0x8d73, 0x8d92,
0x8db1, 0x8dc4, 0x8dd6, 0x8de8, 0x8dfc, 0x8e0f, 0x8e22, 0x8e34,
0x8e48, 0x8e5c, 0x8e6f, 0x8e7b, 0x8e8f, 0x8e9a, 0x8ea8, 0x8eb7,
0x8ec7, 0x8ed5, 0x8ee4, 0x8ef4, 0x8f03, 0x8f13, 0x8f23, 0x8f31,
// Entry 8080 - 80BF
0x8f40, 0x8f4f, 0x8f5f, 0x8f6f, 0x8f7f, 0x8f90, 0x8f9f, 0x8faf,
0x8fbf, 0x8fd0, 0x8fe0, 0x8ff1, 0x9002, 0x9014, 0x9022, 0x9031,
0x9040, 0x9050, 0x905f, 0x906f, 0x907f, 0x9090, 0x90a0, 0x90b0,
0x90c1, 0x90d1, 0x90e2, 0x90f3, 0x9105, 0x9114, 0x9124, 0x9134,
0x9145, 0x9155, 0x9166, 0x9177, 0x9189, 0x9199, 0x91aa, 0x91bb,
0x91cd, 0x91de, 0x91f0, 0x9202, 0x9211, 0x9220, 0x9230, 0x923f,
0x924f, 0x925f, 0x9270, 0x927f, 0x928f, 0x929f, 0x92b0, 0x92c0,
0x92d1, 0x92e2, 0x92f4, 0x9304, 0x9314, 0x9325, 0x9335, 0x9346,
// Entry 80C0 - 80FF
0x9358, 0x9368, 0x9379, 0x938b, 0x939c, 0x93ae, 0x93c0, 0x93cf,
0x93df, 0x93ef, 0x9400, 0x9410, 0x9421, 0x9432, 0x9444, 0x9454,
0x9465, 0x9476, 0x9488, 0x9499, 0x94ab, 0x94bd, 0x94d0, 0x94e0,
0x94f1, 0x9502, 0x9514, 0x9525, 0x9537, 0x9549, 0x955c, 0x956d,
0x957f, 0x9591, 0x95a4, 0x95b6, 0x95c9, 0x95dc, 0x95f0, 0x95ff,
0x960e, 0x961e, 0x962d, 0x963d, 0x964d, 0x965e, 0x966d, 0x967d,
0x968d, 0x969e, 0x96ae, 0x96bf, 0x96d0, 0x96e2, 0x96f1, 0x9701,
0x9711, 0x9722, 0x9732, 0x9743, 0x9754, 0x9766, 0x9776, 0x9787,
// Entry 8100 - 813F
0x9798, 0x97aa, 0x97bb, 0x97cd, 0x97df, 0x97f2, 0x9802, 0x9812,
0x9823, 0x9833, 0x9844, 0x9856, 0x9866, 0x9877, 0x9889, 0x989a,
0x98ac, 0x98be, 0x98ce, 0x98df, 0x98f0, 0x9902, 0x9913, 0x9925,
0x9937, 0x994a, 0x995b, 0x996d, 0x997f, 0x9992, 0x99a4, 0x99b7,
0x99ca, 0x99de, 0x99ee, 0x99fe, 0x9a0f, 0x9a1f, 0x9a30, 0x9a41,
0x9a53, 0x9a63, 0x9a74, 0x9a85, 0x9a97, 0x9aa8, 0x9aba, 0x9acc,
0x9adf, 0x9aef, 0x9b00, 0x9b11, 0x9b23, 0x9b34, 0x9b46, 0x9b58,
0x9b6b, 0x9b7c, 0x9b8e, 0x9ba0, 0x9bb3, 0x9bc5, 0x9bd8, 0x9beb,
// Entry 8140 - 817F
0x9bff, 0x9c0f, 0x9c20, 0x9c31, 0x9c43, 0x9c54, 0x9c66, 0x9c78,
0x9c8b, 0x9c9c, 0x9cae, 0x9cc0, 0x9cd3, 0x9ce5, 0x9cf8, 0x9d0b,
0x9d1f, 0x9d31, 0x9d43, 0x9d56, 0x9d68, 0x9d7b, 0x9d8f, 0x9da1,
0x9db4, 0x9dc8, 0x9ddc, 0x9df0, 0x9e08, 0x9e23, 0x9e47, 0x9e6e,
0x9e92, 0x9eb9, 0x9edc, 0x9f02, 0x9f25, 0x9f4b, 0x9f69, 0x9f92,
0x9fbb, 0x9fe4, 0xa00d, 0xa018, 0xa037, 0xa056, 0xa06c, 0xa082,
0xa09c, 0xa0ac, 0xa0be, 0xa0cf, 0xa0e0, 0xa0f1, 0xa116, 0xa13c,
0xa150, 0xa16d, 0xa18a, 0xa1bf, 0xa1eb, 0xa216, 0xa21c, 0xa263,
// Entry 8180 - 81BF
0xa2aa, 0xa2c1, 0xa2d9, 0xa2f9, 0xa31a, 0xa338, 0xa367, 0xa397,
0xa3bc, 0xa3ea, 0xa418, 0xa43b, 0xa464, 0xa490, 0xa4b8, 0xa4e3,
0xa502, 0xa524, 0xa543, 0xa565, 0xa57e, 0xa597, 0xa5c0, 0xa5e7,
0xa60b, 0xa630, 0xa650, 0xa66a, 0xa68d, 0xa6b0, 0xa6d9, 0xa6ee,
0xa723, 0xa748, 0xa76d, 0xa792, 0xa7c0, 0xa7dc, 0xa803, 0xa82a,
0xa846, 0xa862, 0xa88c, 0xa8b2, 0xa8da, 0xa90a, 0xa93d, 0xa962,
0xa985, 0xa9a9, 0xa9c8, 0xa9ea, 0xaa09, 0xaa2b, 0xaa54, 0xaa70,
0xaa97, 0xaab7, 0xaada, 0xab04, 0xab27, 0xab3f, 0xab59, 0xab70,
// Entry 81C0 - 81FF
0xab88, 0xaba1, 0xabbb, 0xabd2, 0xabea, 0xac01, 0xac19, 0xac32,
0xac4b, 0xac65, 0xac7e, 0xac98, 0xacb2, 0xaccd, 0xace6, 0xad00,
0xad1a, 0xad35, 0xad4f, 0xad6a, 0xad85, 0xada1, 0xadba, 0xadd4,
0xadee, 0xae09, 0xae23, 0xae3e, 0xae59, 0xae75, 0xae8f, 0xaeaa,
0xaec5, 0xaee1, 0xaefc, 0xaf18, 0xaf34, 0xaf51, 0xaf6a, 0xaf84,
0xaf9e, 0xafb9, 0xafd3, 0xafee, 0xb009, 0xb025, 0xb03f, 0xb05a,
0xb075, 0xb091, 0xb0ac, 0xb0c8, 0xb0e4, 0xb101, 0xb11b, 0xb136,
0xb151, 0xb16d, 0xb188, 0xb1a4, 0xb1c0, 0xb1dd, 0xb1f8, 0xb214,
// Entry 8200 - 823F
0xb230, 0xb24d, 0xb269, 0xb286, 0xb2a3, 0xb2c1, 0xb2df, 0xb304,
0xb32a, 0xb349, 0xb36e, 0xb39a, 0xb3c7, 0xb3ed, 0xb412, 0xb43e,
0xb46b, 0xb491, 0xb4af, 0xb4d4, 0xb4fa, 0xb519, 0xb53b, 0xb567,
0xb592, 0xb5b3, 0xb5d4, 0xb5ff, 0xb62a, 0xb64b, 0xb66c, 0xb697,
0xb6c3, 0xb6e5, 0xb707, 0xb733, 0xb75f, 0xb781, 0xb797, 0xb79e,
0xb7d8, 0xb7f2, 0xb800, 0xb816, 0xb821, 0xb82d, 0xb83a, 0xb84b,
0xb84f, 0xb853, 0xb858, 0xb85d, 0xb867, 0xb86f, 0xb875, 0xb87a,
0xb881, 0xb887, 0xb88d, 0xb896, 0xb89d, 0xb8c8, 0xb8cf, 0xb8d9,
// Entry 8240 - 827F
0xb8e2, 0xb8fa, 0xb914, 0xb92a, 0xb948, 0xb95f, 0xb97a, 0xb995,
0xb9b4, 0xb9cd, 0xb9e4, 0xb9fc, 0xba13, 0xba31, 0xba46, 0xba65,
0xba79, 0xbaa6, 0xbadd, 0xbb0c, 0xbb31, 0xbb5e, 0xbb83, 0xbba9,
0xbbd5, 0xbbfc, 0xbc22, 0xbc59, 0xbc8b, 0xbcbc, 0xbcf4, 0xbd24,
0xbd4a, 0xbd78, 0xbd9e, 0xbdc5, 0xbdf2, 0xbe1a, 0xbe41, 0xbe79,
0xbeac, 0xbede, 0xbf05, 0xbf33, 0xbf5f, 0xbf88, 0xbfaf, 0xbfd7,
0xc003, 0xc029, 0xc045, 0xc05f, 0xc07c, 0xc09b, 0xc0ba, 0xc0d8,
0xc0f9, 0xc116, 0xc135, 0xc153, 0xc170, 0xc18d, 0xc1ac, 0xc1d1,
// Entry 8280 - 82BF
0xc1fc, 0xc226, 0xc253, 0xc274, 0xc2a1, 0xc2c1, 0xc2e3, 0xc31a,
0xc339, 0xc360, 0xc380, 0xc3a7, 0xc3c5, 0xc3e7, 0xc411, 0xc434,
0xc451, 0xc47f, 0xc4a0, 0xc4c1, 0xc4e9, 0xc508, 0xc525, 0xc539,
0xc553, 0xc56a, 0xc585, 0xc59a, 0xc5b1, 0xc5c8, 0xc5e8, 0xc600,
0xc627, 0xc653, 0xc66c, 0xc680, 0xc698, 0xc6b6, 0xc6d4, 0xc6f4,
0xc713, 0xc735, 0xc755, 0xc776, 0xc796, 0xc7b9, 0xc7e5, 0xc812,
0xc83e, 0xc86d, 0xc88c, 0xc8ae, 0xc8c5, 0xc8db, 0xc8f1, 0xc90a,
0xc92c, 0xc94d, 0xc971, 0xc991, 0xc9b2, 0xc9df, 0xca0d, 0xca39,
// Entry 82C0 - 82FF
0xca67, 0xca95, 0xcac9, 0xcafa, 0xcb12, 0xcb35, 0xcb56, 0xcb78,
0xcb8c, 0xcb9e, 0xcbb1, 0xcbc6, 0xcbdc, 0xcbf1, 0xcc11, 0xcc30,
0xcc5a, 0xcc84, 0xcca3, 0xcccd, 0xccea, 0xcd12, 0xcd40, 0xcd59,
0xcd7d, 0xcd9b, 0xcdbf, 0xcddf, 0xce02, 0xce21, 0xce45, 0xce6b,
0xce96, 0xcebb, 0xcedd, 0xcf07, 0xcf30, 0xcf5e, 0xcf93, 0xcfc7,
0xd001, 0xd01f, 0xd043, 0xd07d, 0xd0a2, 0xd0d1, 0xd0e6, 0xd103,
0xd123, 0xd147, 0xd170, 0xd194, 0xd1b9, 0xd1de, 0xd1f2, 0xd20f,
0xd22f, 0xd257, 0xd280, 0xd2af, 0xd2cf, 0xd2f9, 0xd338, 0xd37d,
// Entry 8300 - 833F
0xd3a6, 0xd3d5, 0xd41a, 0xd44a, 0xd484, 0xd4ac, 0xd4c2, 0xd4d7,
0xd4ea, 0xd4fe, 0xd511, 0xd52f, 0xd54e, 0xd572, 0xd59c, 0xd5c0,
0xd5eb, 0xd610, 0xd631, 0xd653, 0xd677, 0xd699, 0xd6c1, 0xd6e2,
0xd70c, 0xd734, 0xd753, 0xd775, 0xd798, 0xd7c1, 0xd7e1, 0xd7ff,
0xd827, 0xd84f, 0xd86e, 0xd88f, 0xd8ad, 0xd8d3, 0xd8fc, 0xd927,
0xd948, 0xd969, 0xd992, 0xd9ba, 0xd9e3, 0xda0d, 0xda2e, 0xda4d,
0xda6b, 0xda93, 0xdab3, 0xdad8, 0xdaf7, 0xdb20, 0xdb4d, 0xdb78,
0xdb96, 0xdbb4, 0xdbd0, 0xdbed, 0xdc0d, 0xdc2f, 0xdc55, 0xdc7d,
// Entry 8340 - 837F
0xdc9f, 0xdcc9, 0xdcf1, 0xdd12, 0xdd34, 0xdd55, 0xdd7f, 0xdd9f,
0xddcc, 0xddf9, 0xde19, 0xde36, 0xde56, 0xde7c, 0xdea2, 0xdec7,
0xdeec, 0xdf0d, 0xdf30, 0xdf52, 0xdf72, 0xdf93, 0xdfbb, 0xdfe3,
0xe008, 0xe032, 0xe05a, 0xe079, 0xe0a0, 0xe0d1, 0xe0f1, 0xe119,
0xe139, 0xe159, 0xe17d, 0xe1a0, 0xe1c3, 0xe1e9, 0xe208, 0xe22b,
0xe24b, 0xe273, 0xe29b, 0xe2c6, 0xe2e6, 0xe30e, 0xe333, 0xe356,
0xe37a, 0xe398, 0xe3bd, 0xe3de, 0xe401, 0xe426, 0xe44f, 0xe477,
0xe49e, 0xe4c9, 0xe4f5, 0xe51c, 0xe544, 0xe56b, 0xe591, 0xe5be,
// Entry 8380 - 83BF
0xe5e4, 0xe60c, 0xe634, 0xe659, 0xe682, 0xe6a4, 0xe6c6, 0xe6e8,
0xe709, 0xe729, 0xe74c, 0xe773, 0xe79c, 0xe7c1, 0xe7e5, 0xe80a,
0xe827, 0xe845, 0xe864, 0xe885, 0xe8a5, 0xe8d1, 0xe8fc, 0xe929,
0xe959, 0xe988, 0xe9af, 0xe9e5, 0xea18, 0xea39, 0xea76, 0xeab2,
0xeae7, 0xeb09, 0xeb27, 0xeb4a, 0xeb6a, 0xeb92, 0xebb9, 0xebdc,
0xec01, 0xec24, 0xec48, 0xec70, 0xec99, 0xecc7, 0xecfa, 0xed2a,
0xed5f, 0xed8d, 0xedb8, 0xede8, 0xee20, 0xee4f, 0xee7e, 0xeeae,
0xeee2, 0xef10, 0xef3d, 0xef68, 0xef95, 0xefc7, 0xefff, 0xf02b,
// Entry 83C0 - 83FF
0xf058, 0xf087, 0xf0a8, 0xf0cb, 0xf102, 0xf12e, 0xf15c, 0xf186,
0xf1b2, 0xf1e5, 0xf211, 0xf23d, 0xf26e, 0xf29e, 0xf2d5, 0xf30e,
0xf342, 0xf377, 0xf39d, 0xf3c1, 0xf3e6, 0xf40b, 0xf441, 0xf475,
0xf4a0, 0xf4cb, 0xf4f8, 0xf529, 0xf565, 0xf59a, 0xf5d2, 0xf603,
0xf63f, 0xf674, 0xf6ac, 0xf6d2, 0xf6f8, 0xf724, 0xf751, 0xf778,
0xf7a1, 0xf7ca, 0xf7fb, 0xf82d, 0xf861, 0xf889, 0xf8b9, 0xf8ea,
0xf91d, 0xf941, 0xf966, 0xf985, 0xf9a8, 0xf9cc, 0xf9ef, 0xfa12,
0xfa35, 0xfa58, 0xfa7b, 0xfaa6, 0xfacf, 0xfafa, 0xfb23, 0xfb47,
// Entry 8400 - 843F
0xfb6f, 0xfb8c, 0xfba9, 0xfbc5, 0xfbe9, 0xfc06, 0xfc22, 0xfc41,
0xfc61, 0xfc7b, 0xfc93, 0xfca9, 0xfcbd, 0xfcd0, 0xfcf0, 0xfd10,
0xfd30, 0xfd46, 0xfd62, 0xfd7c, 0xfd92, 0xfda6, 0xfdbc, 0xfdd9,
0xfdf6, 0xfe15, 0xfe33, 0xfe51, 0xfe6e, 0xfe91, 0xfeb5, 0xfeca,
0xfeeb, 0xff0d, 0xff22, 0xff37, 0xff58, 0xff7a, 0xff94, 0xffae,
0xffd2, 0xffed, 0x0007, 0x001d, 0x0035, 0x004e, 0x0069, 0x0080,
0x0099, 0x00ba, 0x00da, 0x00f4, 0x010b, 0x0125, 0x0140, 0x0160,
0x0181, 0x019a, 0x01b3, 0x01cb, 0x01e6, 0x0200, 0x021d, 0x023e,
// Entry 8440 - 847F
0x025e, 0x028b, 0x02a4, 0x02c0, 0x02e0, 0x0304, 0x0328, 0x0351,
0x037a, 0x03a5, 0x03d0, 0x03fc, 0x0428, 0x0453, 0x047e, 0x04ad,
0x04dc, 0x04fe, 0x0520, 0x0551, 0x0582, 0x05a5, 0x05c1, 0x05de,
0x05fa, 0x061f, 0x0644, 0x0658, 0x0671, 0x0689, 0x06a4, 0x06be,
0x06db, 0x06fc, 0x071c, 0x0749, 0x0766, 0x0790, 0x07b2, 0x07d4,
0x07f6, 0x0817, 0x0838, 0x0859, 0x0882, 0x08a1, 0x08c0, 0x08df,
0x08fe, 0x091d, 0x0936, 0x094d, 0x0965, 0x097b, 0x0994, 0x09ab,
0x09c6, 0x09df, 0x09fe, 0x0a1f, 0x0a3e, 0x0a64, 0x0a84, 0x0aad,
// Entry 8480 - 84BF
0x0ad5, 0x0af3, 0x0b0f, 0x0b2d, 0x0b4a, 0x0b66, 0x0b83, 0x0ba1,
0x0bbe, 0x0be4, 0x0c0a, 0x0c24, 0x0c39, 0x0c49, 0x0c5d, 0x0c71,
0x0c85, 0x0c9d, 0x0cb7, 0x0cd6, 0x0cf8, 0x0d09, 0x0d1c, 0x0d38,
0x0d51, 0x0d67, 0x0d87, 0x0da7, 0x0dc7, 0x0de7, 0x0e07, 0x0e27,
0x0e47, 0x0e67, 0x0e87, 0x0ea8, 0x0ec9, 0x0ee3, 0x0efd, 0x0f19,
0x0f34, 0x0f55, 0x0f74, 0x0f95, 0x0fbc, 0x0fd5, 0x0ff1, 0x100f,
0x102a, 0x1047, 0x1066, 0x1079, 0x1090, 0x10a5, 0x10b9, 0x10ce,
0x10ed, 0x110c, 0x1121, 0x113c, 0x115b, 0x117a, 0x1193, 0x11ac,
// Entry 84C0 - 84FF
0x11ce, 0x11f2, 0x120c, 0x122a, 0x1244, 0x1262, 0x1299, 0x12d2,
0x1316, 0x134f, 0x138a, 0x13d2, 0x141a, 0x1462, 0x1476, 0x1495,
0x14b4, 0x14cb, 0x14df, 0x14f5, 0x150a, 0x1522, 0x1539, 0x1550,
0x1568, 0x1587, 0x15a6, 0x15c7, 0x15e4, 0x1600, 0x1622, 0x1642,
0x1667, 0x1687, 0x16a6, 0x16d2, 0x16fc, 0x1727, 0x1750, 0x176f,
0x1782, 0x1796, 0x17b3, 0x17d0, 0x17ed, 0x180a, 0x1827, 0x1844,
0x1861, 0x187e, 0x189b, 0x18b9, 0x18d7, 0x18f5, 0x1913, 0x1931,
0x194f, 0x196d, 0x198b, 0x19a9, 0x19c7, 0x19e5, 0x1a03, 0x1a21,
// Entry 8500 - 853F
0x1a3f, 0x1a5d, 0x1a7b, 0x1a99, 0x1ab7, 0x1ad5, 0x1af3, 0x1b17,
0x1b3b, 0x1b5f, 0x1b83, 0x1ba7, 0x1bcb, 0x1bf0, 0x1c15, 0x1c3a,
0x1c5f, 0x1c84, 0x1ca9, 0x1cce, 0x1cf3, 0x1d18, 0x1d3d, 0x1d62,
0x1d87, 0x1dac, 0x1dd1, 0x1df6, 0x1e1b, 0x1e40, 0x1e65, 0x1e8a,
0x1eaf, 0x1ed4, 0x1ef9, 0x1f1e, 0x1f43, 0x1f68, 0x1f8d, 0x1fb2,
0x1fd7, 0x1ffc, 0x2021, 0x2046, 0x2065, 0x2086, 0x20a7, 0x20bb,
0x20d0, 0x20e4, 0x20f8, 0x210e, 0x2123, 0x2138, 0x214c, 0x2162,
0x2178, 0x218d, 0x21a1, 0x21b8, 0x21cf, 0x21e8, 0x2201, 0x2219,
// Entry 8540 - 857F
0x2231, 0x224b, 0x2264, 0x227d, 0x228f, 0x22a0, 0x22b1, 0x22c4,
0x22d6, 0x22e8, 0x22f9, 0x230c, 0x231f, 0x2331, 0x2342, 0x2356,
0x236a, 0x2380, 0x2396, 0x23ab, 0x23c0, 0x23d7, 0x23ed, 0x2403,
0x2415, 0x242e, 0x2444, 0x245d, 0x2475, 0x2485, 0x2499, 0x24b2,
0x24c5, 0x24da, 0x24f5, 0x250e, 0x2522, 0x253a, 0x2555, 0x257e,
0x2596, 0x25b0, 0x25c6, 0x25df, 0x25f2, 0x2607, 0x2621, 0x2636,
0x264d, 0x2662, 0x2677, 0x268f, 0x26a1, 0x26b2, 0x26ca, 0x26e1,
0x26f5, 0x2709, 0x2723, 0x2740, 0x2755, 0x2769, 0x2780, 0x2795,
// Entry 8580 - 85BF
0x27ac, 0x27c2, 0x27d6, 0x27ec, 0x2803, 0x281d, 0x2833, 0x284e,
0x2866, 0x2879, 0x2890, 0x28a9, 0x28be, 0x28d2, 0x28e6, 0x2907,
0x291e, 0x2933, 0x2949, 0x295c, 0x2976, 0x2990, 0x29a9, 0x29c3,
0x29d8, 0x29f2, 0x2a0d, 0x2a20, 0x2a33, 0x2a48, 0x2a5b, 0x2a72,
0x2a89, 0x2a9e, 0x2ab6, 0x2acd, 0x2ae3, 0x2af9, 0x2b11, 0x2b26,
0x2b3b, 0x2b54, 0x2b6c, 0x2b86, 0x2ba0, 0x2bb7, 0x2bce, 0x2be9,
0x2c04, 0x2c21, 0x2c3d, 0x2c59, 0x2c74, 0x2c91, 0x2cae, 0x2cca,
0x2ce5, 0x2d00, 0x2d1d, 0x2d39, 0x2d55, 0x2d70, 0x2d8d, 0x2daa,
// Entry 85C0 - 85FF
0x2dc6, 0x2de0, 0x2dfa, 0x2e16, 0x2e31, 0x2e4c, 0x2e5a, 0x2e69,
0x2e84, 0x2e9f, 0x2eba, 0x2ed5, 0x2ef0, 0x2f0b, 0x2f26, 0x2f41,
0x2f5c, 0x2f77, 0x2f92, 0x2fad, 0x2fc8, 0x2fe3, 0x2ffe, 0x3019,
0x3034, 0x304f, 0x306a, 0x3085, 0x30a0, 0x30bb, 0x30d6, 0x30f1,
0x310c, 0x3127, 0x3140, 0x3159, 0x3172, 0x318b, 0x31a4, 0x31bd,
0x31d6, 0x31ef, 0x3208, 0x3221, 0x323a, 0x3253, 0x326c, 0x3285,
0x329e, 0x32b7, 0x32d0, 0x32e9, 0x3302, 0x331b, 0x3334, 0x334d,
0x3366, 0x337f, 0x3398, 0x33b1, 0x33ce, 0x33eb, 0x3408, 0x3425,
// Entry 8600 - 863F
0x3442, 0x345f, 0x347c, 0x3499, 0x34b6, 0x34d3, 0x34f0, 0x350d,
0x352a, 0x3547, 0x3564, 0x3581, 0x359e, 0x35bb, 0x35d8, 0x35f5,
0x3612, 0x362f, 0x364c, 0x3669, 0x3686, 0x36a3, 0x36be, 0x36d9,
0x36f4, 0x370f, 0x372a, 0x3745, 0x3760, 0x377b, 0x3796, 0x37b1,
0x37cc, 0x37e7, 0x3802, 0x381d, 0x3838, 0x3853, 0x386e, 0x3889,
0x38a4, 0x38bf, 0x38da, 0x38f5, 0x3910, 0x392b, 0x3946, 0x3968,
0x398a, 0x39ac, 0x39ce, 0x39f0, 0x3a12, 0x3a34, 0x3a56, 0x3a78,
0x3a9a, 0x3abc, 0x3ade, 0x3b00, 0x3b22, 0x3b44, 0x3b66, 0x3b88,
// Entry 8640 - 867F
0x3baa, 0x3bcc, 0x3bee, 0x3c10, 0x3c32, 0x3c54, 0x3c76, 0x3c98,
0x3cba, 0x3cda, 0x3cfa, 0x3d1a, 0x3d3a, 0x3d5a, 0x3d7a, 0x3d9a,
0x3dba, 0x3dda, 0x3dfa, 0x3e1a, 0x3e3a, 0x3e5a, 0x3e7a, 0x3e9a,
0x3eba, 0x3eda, 0x3efa, 0x3f1a, 0x3f3a, 0x3f5a, 0x3f7a, 0x3f9a,
0x3fba, 0x3fda, 0x3ffa, 0x4017, 0x4034, 0x4051, 0x406e, 0x408b,
0x40a8, 0x40c5, 0x40e2, 0x40ff, 0x411c, 0x4139, 0x4156, 0x4173,
0x4190, 0x41ad, 0x41ca, 0x41e7, 0x4204, 0x421f, 0x423a, 0x4255,
0x4270, 0x428b, 0x42a6, 0x42c1, 0x42dc, 0x42f7, 0x4312, 0x432d,
// Entry 8680 - 86BF
0x4348, 0x4363, 0x437e, 0x4399, 0x43b4, 0x43cf, 0x43ea, 0x4405,
0x4420, 0x443b, 0x4456, 0x4471, 0x4493, 0x44b5, 0x44d7, 0x44f9,
0x451b, 0x453d, 0x455f, 0x4581, 0x45a3, 0x45c5, 0x45e7, 0x4609,
0x462b, 0x464d, 0x466f, 0x4691, 0x46b3, 0x46d5, 0x46f7, 0x4719,
0x473b, 0x475d, 0x477f, 0x47a1, 0x47c3, 0x47e5, 0x4805, 0x4825,
0x4845, 0x4865, 0x4885, 0x48a5, 0x48c5, 0x48e5, 0x4905, 0x4925,
0x4945, 0x4965, 0x4985, 0x49a5, 0x49c5, 0x49e5, 0x4a05, 0x4a25,
0x4a45, 0x4a65, 0x4a85, 0x4aa5, 0x4ac5, 0x4ae5, 0x4b05, 0x4b25,
// Entry 86C0 - 86FF
0x4b43, 0x4b61, 0x4b7f, 0x4b9d, 0x4bbb, 0x4bd9, 0x4bf7, 0x4c15,
0x4c33, 0x4c51, 0x4c6f, 0x4c8d, 0x4cab, 0x4cc9, 0x4ce7, 0x4d05,
0x4d23, 0x4d41, 0x4d5f, 0x4d7d, 0x4d9b, 0x4db7, 0x4dd3, 0x4def,
0x4e0b, 0x4e27, 0x4e43, 0x4e5f, 0x4e7b, 0x4e97, 0x4eb3, 0x4ecf,
0x4eeb, 0x4f07, 0x4f23, 0x4f3f, 0x4f5b, 0x4f77, 0x4f93, 0x4faf,
0x4fcb, 0x4fe7, 0x5003, 0x501f, 0x503b, 0x5057, 0x5073, 0x5097,
0x50bb, 0x50df, 0x5103, 0x5127, 0x514b, 0x516f, 0x5193, 0x51b7,
0x51db, 0x51ff, 0x5223, 0x5247, 0x526b, 0x528f, 0x52b3, 0x52d7,
// Entry 8700 - 873F
0x52fb, 0x531f, 0x5341, 0x5363, 0x5385, 0x53a7, 0x53c9, 0x53eb,
0x540d, 0x542f, 0x5451, 0x5473, 0x5495, 0x54b7, 0x54d9, 0x54fb,
0x551d, 0x553f, 0x5561, 0x5583, 0x55a5, 0x55c7, 0x55e9, 0x560b,
0x562d, 0x564f, 0x5671, 0x5693, 0x56b6, 0x56d9, 0x56fc, 0x571f,
0x5742, 0x5765, 0x5788, 0x57ab, 0x57ce, 0x57f1, 0x5814, 0x5837,
0x585a, 0x587d, 0x58a0, 0x58c3, 0x58e6, 0x5909, 0x592c, 0x594f,
0x5972, 0x5995, 0x59b8, 0x59db, 0x59fe, 0x5a21, 0x5a42, 0x5a63,
0x5a84, 0x5aa5, 0x5ac6, 0x5ae7, 0x5b08, 0x5b29, 0x5b4a, 0x5b6b,
// Entry 8740 - 877F
0x5b8c, 0x5bad, 0x5bce, 0x5bef, 0x5c10, 0x5c31, 0x5c52, 0x5c73,
0x5c94, 0x5cb5, 0x5cd6, 0x5cf7, 0x5d18, 0x5d39, 0x5d5a, 0x5d7b,
0x5d9c, 0x5dbd, 0x5dde, 0x5dff, 0x5e20, 0x5e41, 0x5e62, 0x5e83,
0x5ea4, 0x5ec5, 0x5ee6, 0x5f07, 0x5f28, 0x5f49, 0x5f6a, 0x5f8b,
0x5fac, 0x5fcd, 0x5fee, 0x600f, 0x6030, 0x6051, 0x6072, 0x6093,
0x60b4, 0x60d5, 0x60f4, 0x6113, 0x6132, 0x6151, 0x6170, 0x618f,
0x61ae, 0x61cd, 0x61ec, 0x620b, 0x622a, 0x6249, 0x6268, 0x6287,
0x62a6, 0x62c5, 0x62e4, 0x6303, 0x6322, 0x6341, 0x6360, 0x637f,
// Entry 8780 - 87BF
0x639e, 0x63bd, 0x63dc, 0x63fb, 0x6421, 0x6447, 0x646d, 0x6493,
0x64b9, 0x64df, 0x6505, 0x652b, 0x6551, 0x6577, 0x659d, 0x65c3,
0x65e9, 0x660f, 0x6635, 0x665b, 0x6681, 0x66a7, 0x66cd, 0x66f3,
0x6719, 0x673f, 0x6765, 0x678b, 0x67b1, 0x67d7, 0x67fb, 0x681f,
0x6843, 0x6867, 0x688b, 0x68af, 0x68d3, 0x68f7, 0x691b, 0x693f,
0x6963, 0x6987, 0x69ab, 0x69cf, 0x69f3, 0x6a17, 0x6a3b, 0x6a5f,
0x6a83, 0x6aa7, 0x6acb, 0x6aef, 0x6b13, 0x6b37, 0x6b5b, 0x6b7f,
0x6ba7, 0x6bcf, 0x6bf7, 0x6c1f, 0x6c47, 0x6c6f, 0x6c97, 0x6cbf,
// Entry 87C0 - 87FF
0x6ce7, 0x6d0f, 0x6d37, 0x6d5f, 0x6d87, 0x6daf, 0x6dd7, 0x6dff,
0x6e27, 0x6e4f, 0x6e77, 0x6e9f, 0x6ec7, 0x6eef, 0x6f17, 0x6f3f,
0x6f67, 0x6f8f, 0x6fb5, 0x6fdb, 0x7001, 0x7027, 0x704d, 0x7073,
0x7099, 0x70bf, 0x70e5, 0x710b, 0x7131, 0x7157, 0x717d, 0x71a3,
0x71c9, 0x71ef, 0x7215, 0x723b, 0x7261, 0x7287, 0x72ad, 0x72d3,
0x72f9, 0x731f, 0x7345, 0x736b, 0x7398, 0x73c5, 0x73f2, 0x741f,
0x744c, 0x7479, 0x74a6, 0x74d3, 0x7500, 0x752d, 0x755a, 0x7587,
0x75b4, 0x75e1, 0x760e, 0x763b, 0x7668, 0x7695, 0x76c2, 0x76ef,
// Entry 8800 - 883F
0x771c, 0x7749, 0x7776, 0x77a3, 0x77d0, 0x77fd, 0x7828, 0x7853,
0x787e, 0x78a9, 0x78d4, 0x78ff, 0x792a, 0x7955, 0x7980, 0x79ab,
0x79d6, 0x7a01, 0x7a2c, 0x7a57, 0x7a82, 0x7aad, 0x7ad8, 0x7b03,
0x7b2e, 0x7b59, 0x7b84, 0x7baf, 0x7bda, 0x7c05, 0x7c30, 0x7c5b,
0x7c7b, 0x7c9b, 0x7cbb, 0x7cdb, 0x7cfb, 0x7d1b, 0x7d3b, 0x7d5b,
0x7d7b, 0x7d9b, 0x7dbb, 0x7ddb, 0x7dfb, 0x7e1b, 0x7e3b, 0x7e5b,
0x7e7b, 0x7e9b, 0x7ebb, 0x7edb, 0x7efb, 0x7f1b, 0x7f3b, 0x7f5b,
0x7f7b, 0x7f9b, 0x7fb9, 0x7fd7, 0x7ff5, 0x8013, 0x8031, 0x804f,
// Entry 8840 - 887F
0x806d, 0x808b, 0x80a9, 0x80c7, 0x80e5, 0x8103, 0x8121, 0x813f,
0x815d, 0x817b, 0x8199, 0x81b7, 0x81d5, 0x81f3, 0x8211, 0x822f,
0x824d, 0x826b, 0x8289, 0x82a7, 0x82ca, 0x82ed, 0x830c, 0x832a,
0x8349, 0x8368, 0x8389, 0x83a7, 0x83c4, 0x83e3, 0x8401, 0x8420,
0x843f, 0x845b, 0x8477, 0x8493, 0x84b4, 0x84d0, 0x84ed, 0x8513,
0x8532, 0x854f, 0x8570, 0x858d, 0x85aa, 0x85c7, 0x85e6, 0x85fd,
0x861a, 0x8636, 0x8653, 0x8670, 0x868f, 0x86ab, 0x86c6, 0x86e3,
0x86ff, 0x871c, 0x8739, 0x8753, 0x876d, 0x8787, 0x87a6, 0x87c0,
// Entry 8880 - 88BF
0x87db, 0x87fe, 0x881b, 0x8836, 0x8855, 0x8870, 0x888b, 0x88a6,
0x88c3, 0x88e9, 0x8909, 0x8927, 0x8945, 0x8961, 0x897d, 0x8998,
0x89b9, 0x89d9, 0x89fa, 0x8a1b, 0x8a3e, 0x8a5e, 0x8a7d, 0x8a9e,
0x8abe, 0x8adf, 0x8b00, 0x8b1e, 0x8b3c, 0x8b5a, 0x8b7d, 0x8b9b,
0x8bba, 0x8be2, 0x8c03, 0x8c22, 0x8c45, 0x8c64, 0x8c83, 0x8ca2,
0x8cc3, 0x8cdc, 0x8cfb, 0x8d19, 0x8d38, 0x8d57, 0x8d78, 0x8d96,
0x8db3, 0x8dd2, 0x8df0, 0x8e0f, 0x8e2e, 0x8e4a, 0x8e66, 0x8e82,
0x8ea3, 0x8ebf, 0x8edc, 0x8f01, 0x8f20, 0x8f3d, 0x8f5e, 0x8f7b,
// Entry 88C0 - 88FF
0x8f98, 0x8fb5, 0x8fd4, 0x8ffc, 0x901e, 0x903e, 0x905e, 0x907c,
0x909a, 0x90b7, 0x90dd, 0x9102, 0x9128, 0x914e, 0x9176, 0x919b,
0x91bf, 0x91e5, 0x920a, 0x9230, 0x9256, 0x9279, 0x929c, 0x92bf,
0x92e7, 0x930a, 0x932e, 0x935b, 0x9381, 0x93a5, 0x93cd, 0x93f1,
0x9415, 0x9439, 0x945f, 0x947d, 0x94a1, 0x94c4, 0x94e8, 0x950c,
0x9532, 0x9555, 0x9577, 0x959b, 0x95be, 0x95e2, 0x9606, 0x9627,
0x9648, 0x9669, 0x968f, 0x96b0, 0x96d2, 0x96fc, 0x9720, 0x9742,
0x9768, 0x978a, 0x97ac, 0x97ce, 0x97f2, 0x981f, 0x9846, 0x986b,
// Entry 8900 - 893F
0x9890, 0x98b3, 0x98d6, 0x98f8, 0x9922, 0x994b, 0x9975, 0x999f,
0x99cb, 0x99f4, 0x9a1c, 0x9a46, 0x9a6f, 0x9a99, 0x9ac3, 0x9aea,
0x9b11, 0x9b38, 0x9b64, 0x9b8b, 0x9bb3, 0x9be4, 0x9c0e, 0x9c36,
0x9c62, 0x9c8a, 0x9cb2, 0x9cda, 0x9d04, 0x9d26, 0x9d4e, 0x9d75,
0x9d9d, 0x9dc5, 0x9def, 0x9e16, 0x9e3c, 0x9e64, 0x9e8b, 0x9eb3,
0x9edb, 0x9f00, 0x9f25, 0x9f4a, 0x9f74, 0x9f99, 0x9fbf, 0x9fed,
0xa015, 0xa03b, 0xa065, 0xa08b, 0xa0b1, 0xa0d7, 0xa0ff, 0xa130,
0xa15b, 0xa184, 0xa1ad, 0xa1d4, 0xa1fb, 0xa221, 0xa252, 0xa282,
// Entry 8940 - 897F
0xa2b3, 0xa2e4, 0xa317, 0xa347, 0xa376, 0xa3a7, 0xa3d7, 0xa408,
0xa439, 0xa467, 0xa495, 0xa4c3, 0xa4f6, 0xa524, 0xa553, 0xa58b,
0xa5bc, 0xa5eb, 0xa61e, 0xa64d, 0xa67c, 0xa6ab, 0xa6dc, 0xa705,
0xa734, 0xa762, 0xa791, 0xa7c0, 0xa7f1, 0xa81f, 0xa84c, 0xa87b,
0xa8a9, 0xa8d8, 0xa907, 0xa933, 0xa95f, 0xa98b, 0xa9bc, 0xa9e8,
0xaa15, 0xaa4a, 0xaa79, 0xaaa6, 0xaad7, 0xab04, 0xab31, 0xab5e,
0xab8d, 0xabc5, 0xabf7, 0xac27, 0xac57, 0xac85, 0xacb3, 0xace0,
0xad01, 0xad20, 0xad3c, 0xad57, 0xad72, 0xad8f, 0xadab, 0xadc7,
// Entry 8980 - 89BF
0xade2, 0xadff, 0xae1c, 0xae38, 0xae5d, 0xae81, 0xaea5, 0xaecb,
0xaef0, 0xaf15, 0xaf39, 0xaf5f, 0xaf85, 0xafaa, 0xafcc, 0xafed,
0xb00e, 0xb031, 0xb053, 0xb075, 0xb096, 0xb0b9, 0xb0dc, 0xb0fe,
0xb125, 0xb14b, 0xb171, 0xb199, 0xb1c0, 0xb1e7, 0xb20d, 0xb235,
0xb25d, 0xb284, 0xb2a5, 0xb2c5, 0xb2e5, 0xb307, 0xb328, 0xb349,
0xb369, 0xb38b, 0xb3ad, 0xb3ce, 0xb3e9, 0xb406, 0xb420, 0xb43b,
0xb457, 0xb473, 0xb493, 0xb4b5, 0xb4e1, 0xb50b, 0xb52d, 0xb54f,
0xb575, 0xb598, 0xb5ba, 0xb5de, 0xb605, 0xb637, 0xb660, 0xb68c,
// Entry 89C0 - 89FF
0xb6b8, 0xb6e4, 0xb71b, 0xb753, 0xb786, 0xb7b9, 0xb7e3, 0xb80f,
0xb83b, 0xb867, 0xb88f, 0xb8b9, 0xb8ef, 0xb925, 0xb952, 0xb98d,
0xb9c4, 0xba00, 0xba37, 0xba71, 0xbaa0, 0xbad0, 0xbaff, 0xbb2e,
0xbb67, 0xbb9e, 0xbbdf, 0xbc1b, 0xbc4d, 0xbc7f, 0xbcbd, 0xbcf2,
0xbd2c, 0xbd6d, 0xbd9f, 0xbdd1, 0xbe04, 0xbe3b, 0xbe71, 0xbea6,
0xbed9, 0xbf12, 0xbf45, 0xbf74, 0xbfaa, 0xbfe5, 0xc017, 0xc04d,
0xc06f, 0xc096, 0xc0bf, 0xc0eb, 0xc11d, 0xc149, 0xc17a, 0xc1a7,
0xc1d0, 0xc1fe, 0xc231, 0xc269, 0xc297, 0xc2ca, 0xc301, 0xc329,
// Entry 8A00 - 8A3F
0xc356, 0xc385, 0xc3ae, 0xc3de, 0xc419, 0xc452, 0xc467, 0xc491,
0xc4ab, 0xc4cb, 0xc4f0, 0xc510, 0xc533, 0xc55f, 0xc581, 0xc5ae,
0xc5e0, 0xc602, 0xc617, 0xc637, 0xc655, 0xc678, 0xc696, 0xc6ab,
0xc6c4, 0xc6d8, 0xc6fc, 0xc71b, 0xc73d, 0xc75a, 0xc781, 0xc7a3,
0xc7c1, 0xc7da, 0xc7f1, 0xc806, 0xc826, 0xc844, 0xc867, 0xc882,
0xc8ab, 0xc8c1, 0xc8dd, 0xc903, 0xc924, 0xc948, 0xc967, 0xc997,
0xc9c7, 0xc9dd, 0xca04, 0xca2d, 0xca55, 0xca7d, 0xca9a, 0xcac6,
0xcaf7, 0xcb29, 0xcb4a, 0xcb7b, 0xcbaa, 0xcbda, 0xcbf9, 0xcc24,
// Entry 8A40 - 8A7F
0xcc45, 0xcc64, 0xcc84, 0xccaf, 0xccd0, 0xccfa, 0xcd1c, 0xcd3f,
0xcd67, 0xcd90, 0xcdc9, 0xcdfe, 0xce20, 0xce44, 0xce67, 0xce8a,
0xceb3, 0xcede, 0xcf08, 0xcf23, 0xcf4d, 0xcf7c, 0xcfad, 0xcfcc,
0xd004, 0xd03d, 0xd05a, 0xd083, 0xd0a4, 0xd0c7, 0xd0e8, 0xd10a,
0xd12b, 0xd156, 0xd187, 0xd1a7, 0xd1c7, 0xd1e7, 0xd20e, 0xd237,
0xd265, 0xd290, 0xd2ba, 0xd2e7, 0xd30d, 0xd335, 0xd361, 0xd389,
0xd3aa, 0xd3c7, 0xd3e6, 0xd407, 0xd432, 0xd45c, 0xd47e, 0xd4a7,
0xd4ca, 0xd4f2, 0xd51c, 0xd54b, 0xd572, 0xd59b, 0xd5c8, 0xd5f4,
// Entry 8A80 - 8ABF
0xd61d, 0xd64c, 0xd67e, 0xd6b5, 0xd6eb, 0xd720, 0xd752, 0xd775,
0xd79b, 0xd7c2, 0xd7f7, 0xd82d, 0xd85e, 0xd88f, 0xd8bf, 0xd8f1,
0xd929, 0xd95d, 0xd983, 0xd9ad, 0xd9e1, 0xda15, 0xda48, 0xda70,
0xda90, 0xdab5, 0xdadc, 0xdb04, 0xdb26, 0xdb4e, 0xdb74, 0xdb99,
0xdbbb, 0xdbd6, 0xdbf6, 0xdc1f, 0xdc49, 0xdc6e, 0xdc91, 0xdcc1,
0xdcf0, 0xdd1f, 0xdd4c, 0xdd78, 0xdda7, 0xddd5, 0xde0a, 0xde1f,
0xde39, 0xde51, 0xde6b, 0xde84, 0xde9c, 0xdeb6, 0xdecf, 0xdee8,
0xdf03, 0xdf1d, 0xdf35, 0xdf4f, 0xdf68, 0xdf7e, 0xdf96, 0xdfad,
// Entry 8AC0 - 8AFF
0xdfc8, 0xdfe3, 0xe003, 0xe023, 0xe045, 0xe067, 0xe085, 0xe0a3,
0xe0c1, 0xe0e1, 0xe101, 0xe11d, 0xe142, 0xe16a, 0xe192, 0xe1ba,
0xe1e4, 0xe218, 0xe24c, 0xe27c, 0xe2a9, 0xe2d7, 0xe30b, 0xe340,
0xe374, 0xe3aa, 0xe3da, 0xe408, 0xe438, 0xe469, 0xe4a5, 0xe4c9,
0xe500, 0xe530, 0xe561, 0xe59d, 0xe5c6, 0xe5f0, 0xe619, 0xe644,
0xe670, 0xe69b, 0xe6c9, 0xe6f3, 0xe71e, 0xe748, 0xe770, 0xe799,
0xe7c1, 0xe7ec, 0xe818, 0xe843, 0xe86d, 0xe898, 0xe8c2, 0xe8f8,
0xe92e, 0xe969, 0xe9a0, 0xe9d7, 0xea13, 0xea37, 0xea65, 0xea93,
// Entry 8B00 - 8B3F
0xeac1, 0xeae9, 0xeb12, 0xeb3a, 0xeb64, 0xeb8f, 0xebbb, 0xebe6,
0xec13, 0xec43, 0xec74, 0xeca4, 0xecd6, 0xed09, 0xed3d, 0xed70,
0xeda5, 0xedda, 0xee10, 0xee45, 0xee7c, 0xeead, 0xeedc, 0xef0d,
0xef3f, 0xef7c, 0xefa1, 0xefd9, 0xf00a, 0xf045, 0xf082, 0xf0a6,
0xf0d2, 0xf0ff, 0xf12b, 0xf150, 0xf179, 0xf1a3, 0xf1cc, 0xf1f8,
0xf225, 0xf251, 0xf27c, 0xf2a8, 0xf2d3, 0xf30b, 0xf343, 0xf380,
0xf3b7, 0xf3ee, 0xf42a, 0xf44f, 0xf481, 0xf4b4, 0xf4e6, 0xf51a,
0xf550, 0xf587, 0xf5bd, 0xf5f5, 0xf634, 0xf674, 0xf69d, 0xf6c7,
// Entry 8B40 - 8B7F
0xf6f0, 0xf719, 0xf743, 0xf76c, 0xf79c, 0xf7d2, 0xf809, 0xf83f,
0xf875, 0xf8ac, 0xf8e2, 0xf914, 0xf945, 0xf977, 0xf99c, 0xf9c1,
0xf9e9, 0xfa0f, 0xfa46, 0xfa7c, 0xfab2, 0xfae8, 0xfb20, 0xfb58,
0xfb95, 0xfbc7, 0xfbf8, 0xfc29, 0xfc5a, 0xfc8d, 0xfcc0, 0xfcf8,
0xfd2f, 0xfd67, 0xfd9e, 0xfdd9, 0xfe14, 0xfe55, 0xfe96, 0xfed7,
0xff18, 0xff59, 0xff9a, 0xffdb, 0x001c, 0x0056, 0x0090, 0x00c6,
0x00fc, 0x0137, 0x0170, 0x01a9, 0x01e8, 0x0227, 0x026d, 0x02b3,
0x02f2, 0x0331, 0x0370, 0x03af, 0x03e7, 0x041f, 0x0453, 0x0487,
// Entry 8B80 - 8BBF
0x04c0, 0x04eb, 0x0517, 0x0542, 0x056f, 0x059d, 0x05c7, 0x05f1,
0x061b, 0x0645, 0x066f, 0x0695, 0x06bb, 0x06e6, 0x0716, 0x074c,
0x0783, 0x07b9, 0x07f0, 0x0834, 0x0879, 0x08bd, 0x0901, 0x0946,
0x098a, 0x09c2, 0x09fa, 0x0a3a, 0x0a7a, 0x0aae, 0x0ae2, 0x0b24,
0x0b66, 0x0b89, 0x0bac, 0x0bc4, 0x0bdc, 0x0bf5, 0x0c10, 0x0c30,
0x0c5c, 0x0c80, 0x0c9b, 0x0cab, 0x0cbf, 0x0ceb, 0x0d13, 0x0d40,
0x0d69, 0x0d93, 0x0db3, 0x0deb, 0x0e1e, 0x0e59, 0x0e79, 0x0e9e,
0x0ec0, 0x0ee8, 0x0f10, 0x0f36, 0x0f5c, 0x0f78, 0x0f94, 0x0fb1,
// Entry 8BC0 - 8BFF
0x0fc6, 0x0fdf, 0x0ff6, 0x1012, 0x1030, 0x104a, 0x1064, 0x1080,
0x10a2, 0x10b6, 0x10ce, 0x10e8, 0x1108, 0x112e, 0x115b, 0x118d,
0x11b4, 0x11e2, 0x1215, 0x1239, 0x125e, 0x1284, 0x129d, 0x12b7,
0x12d0, 0x12ed, 0x130c, 0x1328, 0x1338, 0x1350, 0x1368, 0x1381,
0x1399, 0x13b4, 0x13ce, 0x13f2, 0x1416, 0x142f, 0x1448, 0x1468,
0x1488, 0x14a8, 0x14bf, 0x14df, 0x14fb, 0x1512, 0x1532, 0x154e,
0x156b, 0x1589, 0x15a8, 0x15c3, 0x15e7, 0x1607, 0x1627, 0x1650,
0x1675, 0x168b, 0x16a9, 0x16c8, 0x16df, 0x16fe, 0x171c, 0x173d,
// Entry 8C00 - 8C3F
0x175d, 0x177d, 0x1796, 0x17b7, 0x17d8, 0x17fb, 0x181a, 0x183d,
0x1869, 0x1890, 0x18b6, 0x18dc, 0x1902, 0x1913, 0x192d, 0x1948,
0x196c, 0x1985, 0x19a7, 0x19c2, 0x19e4, 0x1a07, 0x1a17, 0x1a27,
0x1a3d, 0x1a5b, 0x1a7d, 0x1aa4, 0x1acc, 0x1af3, 0x1b1f, 0x1b46,
0x1b6b, 0x1b99, 0x1bb5, 0x1bce, 0x1be7, 0x1c00, 0x1c19, 0x1c32,
0x1c4b, 0x1c64, 0x1c76, 0x1c9a, 0x1cbf, 0x1cda, 0x1cf4, 0x1d0e,
0x1d2c, 0x1d46, 0x1d67, 0x1d78, 0x1d8d, 0x1da2, 0x1db3, 0x1dca,
0x1de5, 0x1e00, 0x1e1b, 0x1e36, 0x1e51, 0x1e70, 0x1e8f, 0x1eae,
// Entry 8C40 - 8C7F
0x1ecd, 0x1eec, 0x1f0b, 0x1f2a, 0x1f49, 0x1f69, 0x1f89, 0x1fa9,
0x1fc9, 0x1fe9, 0x2009, 0x2029, 0x2053, 0x2077, 0x209a, 0x20b7,
0x20dd, 0x2108, 0x212d, 0x214c, 0x2188, 0x21b9, 0x21e9, 0x220f,
0x223e, 0x2263, 0x228f, 0x22b1, 0x22d4, 0x22f6, 0x2327, 0x2356,
0x237e, 0x23ab, 0x23de, 0x240f, 0x2437, 0x246a, 0x249d, 0x24c5,
0x24f8, 0x2520, 0x253e, 0x256c, 0x259a, 0x25c8, 0x25f6, 0x2624,
0x2652, 0x2671, 0x2691, 0x26b1, 0x26d4, 0x26f5, 0x2716, 0x2739,
0x275b, 0x277b, 0x27a3, 0x27c0, 0x27e2, 0x2802, 0x2825, 0x2848,
// Entry 8C80 - 8CBF
0x2869, 0x2888, 0x28aa, 0x28cb, 0x28ec, 0x290e, 0x292d, 0x294e,
0x296e, 0x298e, 0x29ad, 0x29cf, 0x29ee, 0x2a0e, 0x2a2e, 0x2a4e,
0x2a6c, 0x2a91, 0x2aaf, 0x2adc, 0x2aff, 0x2b2a, 0x2b4a, 0x2b6a,
0x2b8b, 0x2bac, 0x2bce, 0x2bef, 0x2c10, 0x2c32, 0x2c53, 0x2c73,
0x2c94, 0x2cb5, 0x2cd6, 0x2cf6, 0x2d17, 0x2d38, 0x2d59, 0x2d7a,
0x2d9a, 0x2dbb, 0x2ddc, 0x2dfe, 0x2e20, 0x2e42, 0x2e65, 0x2e85,
0x2ea6, 0x2ec9, 0x2eed, 0x2f24, 0x2f45, 0x2f6c, 0x2f95, 0x2fbc,
0x2fdd, 0x2fff, 0x3021, 0x3044, 0x3066, 0x3088, 0x30ab, 0x30cd,
// Entry 8CC0 - 8CFF
0x30ee, 0x3110, 0x3132, 0x3153, 0x3175, 0x3197, 0x31b8, 0x31da,
0x31fc, 0x321f, 0x3242, 0x3265, 0x328e, 0x32b2, 0x32e1, 0x3319,
0x333c, 0x3360, 0x3390, 0x33c1, 0x33f6, 0x342e, 0x344e, 0x346f,
0x3490, 0x34b0, 0x34d0, 0x34f0, 0x3510, 0x3531, 0x3551, 0x3571,
0x3591, 0x35b1, 0x35d2, 0x35f4, 0x3614, 0x3634, 0x3655, 0x3676,
0x3696, 0x36b8, 0x36d9, 0x36f9, 0x3719, 0x3739, 0x3759, 0x377a,
0x379a, 0x37bb, 0x37dc, 0x37fd, 0x381f, 0x3840, 0x3861, 0x3882,
0x38a2, 0x38c3, 0x38e2, 0x3902, 0x3921, 0x3940, 0x395f, 0x397f,
// Entry 8D00 - 8D3F
0x399e, 0x39be, 0x39dd, 0x39fa, 0x3a17, 0x3a34, 0x3a51, 0x3a6e,
0x3a8b, 0x3aa8, 0x3ace, 0x3af3, 0x3b1b, 0x3b41, 0x3b6d, 0x3b8e,
0x3bb8, 0x3bd9, 0x3bf9, 0x3c19, 0x3c3b, 0x3c5c, 0x3c7d, 0x3c9d,
0x3cbf, 0x3ce1, 0x3d02, 0x3d26, 0x3d47, 0x3d55, 0x3d63, 0x3d71,
0x3d7f, 0x3d8d, 0x3d9b, 0x3da9, 0x3db7, 0x3dc6, 0x3dd4, 0x3de3,
0x3df1, 0x3dff, 0x3e0d, 0x3e1b, 0x3e29, 0x3e37, 0x3e44, 0x3e59,
0x3e67, 0x3e7d, 0x3e8a, 0x3e97, 0x3eac, 0x3eba, 0x3ed0, 0x3edd,
0x3eeb, 0x3f01, 0x3f0e, 0x3f23, 0x3f33, 0x3f42, 0x3f52, 0x3f62,
// Entry 8D40 - 8D7F
0x3f72, 0x3f82, 0x3f92, 0x3fa3, 0x3fb3, 0x3fc3, 0x3fd3, 0x3fe3,
0x3ff4, 0x4004, 0x4014, 0x4025, 0x4035, 0x4045, 0x4055, 0x4065,
0x4075, 0x4084, 0x4094, 0x40a4, 0x40b4, 0x40c5, 0x40d5, 0x40e4,
0x40f3, 0x4104, 0x4113, 0x4125, 0x4136, 0x4147, 0x4158, 0x416a,
0x417b, 0x418c, 0x419c, 0x41ac, 0x41bd, 0x41ce, 0x41df, 0x41f0,
0x41ff, 0x4210, 0x421f, 0x4230, 0x4241, 0x4251, 0x4261, 0x4273,
0x4284, 0x4295, 0x42a5, 0x42b7, 0x42c9, 0x42da, 0x42ea, 0x42fe,
0x4313, 0x4328, 0x433d, 0x4353, 0x4367, 0x437c, 0x4391, 0x43a7,
// Entry 8D80 - 8DBF
0x43bc, 0x43d0, 0x43e5, 0x43fb, 0x4410, 0x4425, 0x4439, 0x444e,
0x4463, 0x4478, 0x448d, 0x44a1, 0x44b7, 0x44cc, 0x44e1, 0x44f6,
0x450c, 0x4522, 0x4537, 0x454d, 0x4563, 0x4578, 0x458e, 0x45a4,
0x45b9, 0x45ce, 0x45e5, 0x45fb, 0x4611, 0x4626, 0x463d, 0x4654,
0x466a, 0x467a, 0x468b, 0x469d, 0x46af, 0x46c0, 0x46d1, 0x46e1,
0x46f2, 0x4703, 0x4714, 0x4725, 0x4736, 0x4746, 0x4757, 0x4768,
0x477a, 0x478b, 0x479c, 0x47ac, 0x47bd, 0x47cf, 0x47e0, 0x47f2,
0x4803, 0x4813, 0x4824, 0x4835, 0x4846, 0x4858, 0x4869, 0x4878,
// Entry 8DC0 - 8DFF
0x4889, 0x489d, 0x48af, 0x48c0, 0x48d1, 0x48e4, 0x48f6, 0x4908,
0x4919, 0x492c, 0x493f, 0x4951, 0x496a, 0x497e, 0x4993, 0x49a8,
0x49be, 0x49ce, 0x49df, 0x49ef, 0x4a03, 0x4a18, 0x4a2d, 0x4a43,
0x4a53, 0x4a67, 0x4a7c, 0x4a8d, 0x4a9d, 0x4aad, 0x4ac1, 0x4ad6,
0x4ae7, 0x4afb, 0x4b10, 0x4b20, 0x4b30, 0x4b40, 0x4b50, 0x4b64,
0x4b79, 0x4b89, 0x4b9e, 0x4bb4, 0x4bc4, 0x4bd3, 0x4be3, 0x4bf1,
0x4c00, 0x4c10, 0x4c1e, 0x4c2d, 0x4c3c, 0x4c4c, 0x4c5d, 0x4c6d,
0x4c7d, 0x4c8e, 0x4c9c, 0x4cab, 0x4cbb, 0x4ccb, 0x4cdb, 0x4ceb,
// Entry 8E00 - 8E3F
0x4cfb, 0x4d09, 0x4d1d, 0x4d2b, 0x4d41, 0x4d57, 0x4d6d, 0x4d84,
0x4d9b, 0x4db1, 0x4dc7, 0x4de4, 0x4dfa, 0x4e11, 0x4e27, 0x4e43,
0x4e60, 0x4e7c, 0x4e99, 0x4eb5, 0x4ed1, 0x4eee, 0x4f0a, 0x4f27,
0x4f43, 0x4f5f, 0x4f7c, 0x4f98, 0x4fb4, 0x4fd1, 0x4fed, 0x500a,
0x5028, 0x5046, 0x5064, 0x5083, 0x50a1, 0x50c0, 0x50de, 0x50fd,
0x511b, 0x5139, 0x5157, 0x5176, 0x5194, 0x51b3, 0x51d1, 0x51f0,
0x520f, 0x522e, 0x524d, 0x526c, 0x528b, 0x52aa, 0x52c9, 0x52e8,
0x5307, 0x5327, 0x5347, 0x5365, 0x5383, 0x53a1, 0x53c0, 0x53de,
// Entry 8E40 - 8E7F
0x53fd, 0x541b, 0x5438, 0x5455, 0x5472, 0x5490, 0x54ad, 0x54cb,
0x54e8, 0x5506, 0x5524, 0x5542, 0x5560, 0x557e, 0x559c, 0x55ba,
0x55d8, 0x55f7, 0x5615, 0x5634, 0x5652, 0x5671, 0x568f, 0x56ad,
0x56cb, 0x56ea, 0x5708, 0x5727, 0x5745, 0x5768, 0x5786, 0x57a4,
0x57c2, 0x57e1, 0x5800, 0x581e, 0x583c, 0x585a, 0x5878, 0x5897,
0x58b5, 0x58d4, 0x58f2, 0x5910, 0x592e, 0x594c, 0x596b, 0x5989,
0x59a8, 0x59c6, 0x59e9, 0x5a07, 0x5a25, 0x5a43, 0x5a62, 0x5a80,
0x5a9f, 0x5abd, 0x5adb, 0x5af9, 0x5b17, 0x5b36, 0x5b54, 0x5b73,
// Entry 8E80 - 8EBF
0x5b91, 0x5bb0, 0x5bcf, 0x5bee, 0x5c0d, 0x5c2c, 0x5c4b, 0x5c6a,
0x5c88, 0x5ca6, 0x5cc4, 0x5ce3, 0x5d01, 0x5d20, 0x5d3e, 0x5d5e,
0x5d7e, 0x5d9d, 0x5dbc, 0x5ddb, 0x5dfa, 0x5e19, 0x5e39, 0x5e59,
0x5e79, 0x5e99, 0x5eba, 0x5eda, 0x5efb, 0x5f1b, 0x5f3c, 0x5f5d,
0x5f82, 0x5fa8, 0x5fcd, 0x5feb, 0x6009, 0x6027, 0x6046, 0x6066,
0x6086, 0x60a6, 0x60c6, 0x60e7, 0x6105, 0x6123, 0x6141, 0x6160,
0x617e, 0x619d, 0x61bb, 0x61da, 0x61f9, 0x6218, 0x6238, 0x6258,
0x6277, 0x6297, 0x62b6, 0x62d6, 0x62fa, 0x631f, 0x6343, 0x6362,
// Entry 8EC0 - 8EFF
0x6381, 0x63a0, 0x63c0, 0x63df, 0x63ff, 0x641e, 0x643d, 0x645c,
0x647b, 0x649b, 0x64ba, 0x64da, 0x64f9, 0x6517, 0x6536, 0x6555,
0x6574, 0x6594, 0x65b3, 0x65d3, 0x65f2, 0x6611, 0x6630, 0x6650,
0x6670, 0x668e, 0x66ac, 0x66ca, 0x66e9, 0x6707, 0x6726, 0x6744,
0x6764, 0x6784, 0x67a4, 0x67c4, 0x67e4, 0x67fb, 0x6812, 0x682b,
0x6843, 0x685b, 0x6872, 0x688b, 0x68a4, 0x68bc, 0x68e0, 0x6903,
0x692a, 0x6952, 0x697e, 0x69ae, 0x69d5, 0x69ee, 0x6a08, 0x6a21,
0x6a3a, 0x6a51, 0x6a70, 0x6a87, 0x6a9f, 0x6ab6, 0x6acc, 0x6ae3,
// Entry 8F00 - 8F3F
0x6af9, 0x6b0f, 0x6b27, 0x6b3f, 0x6b57, 0x6b6f, 0x6b87, 0x6b9e,
0x6bb4, 0x6bcd, 0x6be5, 0x6bfc, 0x6c15, 0x6c2c, 0x6c44, 0x6c5b,
0x6c73, 0x6c8a, 0x6ca2, 0x6cba, 0x6cd2, 0x6cea, 0x6d02, 0x6d19,
0x6d31, 0x6d48, 0x6d5f, 0x6d74, 0x6d91, 0x6da6, 0x6dbc, 0x6dd1,
0x6de5, 0x6dfa, 0x6e0e, 0x6e22, 0x6e38, 0x6e4e, 0x6e64, 0x6e7a,
0x6e90, 0x6ea5, 0x6eb9, 0x6ed0, 0x6ee6, 0x6efb, 0x6f12, 0x6f27,
0x6f3d, 0x6f52, 0x6f68, 0x6f7d, 0x6f93, 0x6fa9, 0x6fbf, 0x6fd5,
0x6feb, 0x7000, 0x7016, 0x702b, 0x7036, 0x704e, 0x706f, 0x707a,
// Entry 8F40 - 8F7F
0x7091, 0x70a1, 0x70b0, 0x70bf, 0x70d0, 0x70e0, 0x70f0, 0x70ff,
0x7110, 0x7121, 0x7131, 0x714f, 0x716a, 0x7180, 0x7196, 0x71ae,
0x71c5, 0x71dc, 0x71f2, 0x720a, 0x7222, 0x7239, 0x724f, 0x7268,
0x7281, 0x7299, 0x72b1, 0x72c9, 0x72e3, 0x72fc, 0x7315, 0x7333,
0x7351, 0x7371, 0x7390, 0x73af, 0x73cd, 0x73ed, 0x740d, 0x742c,
0x744b, 0x746a, 0x748b, 0x74ab, 0x74cb, 0x74ea, 0x750b, 0x752c,
0x754c, 0x756b, 0x758d, 0x75af, 0x75d0, 0x75f1, 0x7612, 0x7635,
0x7657, 0x7679, 0x7690, 0x76a9, 0x76be, 0x76d6, 0x76f0, 0x770f,
// Entry 8F80 - 8FBF
0x772e, 0x774f, 0x776f, 0x778f, 0x77ae, 0x77cf, 0x77f0, 0x7810,
0x7827, 0x7847, 0x7864, 0x7887, 0x789d, 0x78bd, 0x78dd, 0x7906,
0x7925, 0x793d, 0x7955, 0x796f, 0x7988, 0x79a1, 0x79b9, 0x79d3,
0x79ed, 0x7a06, 0x7a1e, 0x7a39, 0x7a54, 0x7a6e, 0x7a88, 0x7aa2,
0x7abe, 0x7ad9, 0x7af4, 0x7b14, 0x7b34, 0x7b56, 0x7b77, 0x7b98,
0x7bb8, 0x7bda, 0x7bfc, 0x7c1d, 0x7c3e, 0x7c5f, 0x7c82, 0x7ca4,
0x7cc6, 0x7ce7, 0x7d0a, 0x7d2d, 0x7d4f, 0x7d70, 0x7d94, 0x7db8,
0x7ddb, 0x7dfe, 0x7e21, 0x7e46, 0x7e6a, 0x7e8e, 0x7ea4, 0x7ec6,
// Entry 8FC0 - 8FFF
0x7eea, 0x7f0d, 0x7f30, 0x7f52, 0x7f76, 0x7f9a, 0x7fbd, 0x7fdf,
0x800a, 0x8034, 0x805f, 0x808a, 0x80a9, 0x80c9, 0x80e1, 0x80f8,
0x8110, 0x8127, 0x813e, 0x8156, 0x816d, 0x8184, 0x819b, 0x81b2,
0x81c9, 0x81e1, 0x81f9, 0x8211, 0x8228, 0x823f, 0x8256, 0x826d,
0x8284, 0x829d, 0x82b4, 0x82cc, 0x82e4, 0x82fc, 0x8313, 0x832a,
0x8343, 0x8362, 0x8382, 0x83a1, 0x83c0, 0x83df, 0x83ff, 0x841e,
0x843d, 0x845c, 0x847b, 0x849a, 0x84ba, 0x84da, 0x84fa, 0x8519,
0x8538, 0x8557, 0x8576, 0x8597, 0x85b6, 0x85d6, 0x85f6, 0x8615,
// Entry 9000 - 903F
0x8636, 0x8655, 0x8673, 0x8691, 0x86af, 0x86ce, 0x86ed, 0x870b,
0x8729, 0x8747, 0x8767, 0x8786, 0x87a4, 0x87c4, 0x87eb, 0x8811,
0x8832, 0x8854, 0x8875, 0x8896, 0x88b7, 0x88d8, 0x88f9, 0x891b,
0x893d, 0x895f, 0x8980, 0x89a1, 0x89c2, 0x89e3, 0x8a06, 0x8a27,
0x8a49, 0x8a6b, 0x8a8c, 0x8aad, 0x8ad0, 0x8af9, 0x8b22, 0x8b41,
0x8b5f, 0x8b7e, 0x8b9c, 0x8bba, 0x8bd8, 0x8bf7, 0x8c15, 0x8c33,
0x8c51, 0x8c6f, 0x8c8e, 0x8cad, 0x8ccc, 0x8cea, 0x8d08, 0x8d26,
0x8d44, 0x8d62, 0x8d82, 0x8da0, 0x8dbf, 0x8dde, 0x8dfd, 0x8e1b,
// Entry 9040 - 907F
0x8e39, 0x8e59, 0x8e7e, 0x8ea4, 0x8ec9, 0x8eee, 0x8f14, 0x8f39,
0x8f5e, 0x8f83, 0x8fa8, 0x8fce, 0x8ff4, 0x901a, 0x903f, 0x9064,
0x9089, 0x90ae, 0x90d3, 0x90fa, 0x911f, 0x9145, 0x916b, 0x9191,
0x91b6, 0x91db, 0x9202, 0x9239, 0x9262, 0x9278, 0x928f, 0x92a5,
0x92bc, 0x92d3, 0x92ec, 0x9305, 0x9323, 0x9341, 0x9361, 0x9380,
0x939f, 0x93bd, 0x93dd, 0x93fd, 0x941c, 0x9437, 0x9452, 0x946f,
0x948b, 0x94a7, 0x94c2, 0x94df, 0x94fc, 0x9518, 0x9533, 0x954e,
0x956b, 0x9587, 0x95a3, 0x95be, 0x95db, 0x95f8, 0x9614, 0x9625,
// Entry 9080 - 90BF
0x9638, 0x964b, 0x9665, 0x9678, 0x968b, 0x969e, 0x96b1, 0x96c3,
0x96d4, 0x96ef, 0x970b, 0x9727, 0x9743, 0x975f, 0x977b, 0x9797,
0x97b3, 0x97cf, 0x97eb, 0x9807, 0x9823, 0x983f, 0x985b, 0x9877,
0x9893, 0x98af, 0x98cb, 0x98e7, 0x9903, 0x991f, 0x993b, 0x9957,
0x9973, 0x998f, 0x99ab, 0x99c7, 0x99e3, 0x99ff, 0x9a1b, 0x9a37,
0x9a53, 0x9a6f, 0x9a8b, 0x9aa7, 0x9ac3, 0x9adf, 0x9afb, 0x9b17,
0x9b33, 0x9b4f, 0x9b6b, 0x9b87, 0x9ba3, 0x9bbf, 0x9bdb, 0x9bf7,
0x9c13, 0x9c2f, 0x9c4b, 0x9c64, 0x9c7e, 0x9c98, 0x9cb2, 0x9ccc,
// Entry 90C0 - 90FF
0x9ce6, 0x9d00, 0x9d1a, 0x9d34, 0x9d4e, 0x9d68, 0x9d82, 0x9d9c,
0x9db6, 0x9dd0, 0x9dea, 0x9e04, 0x9e1e, 0x9e38, 0x9e52, 0x9e6c,
0x9e86, 0x9ea0, 0x9eba, 0x9ed4, 0x9eee, 0x9f08, 0x9f22, 0x9f3c,
0x9f56, 0x9f70, 0x9f8a, 0x9fa4, 0x9fbe, 0x9fd8, 0x9ff2, 0xa00c,
0xa026, 0xa040, 0xa05a, 0xa074, 0xa08e, 0xa0a8, 0xa0c2, 0xa0dc,
0xa0f6, 0xa110, 0xa12a, 0xa144, 0xa15e, 0xa16f, 0xa189, 0xa1a3,
0xa1bf, 0xa1da, 0xa1f5, 0xa20f, 0xa22b, 0xa247, 0xa262, 0xa27c,
0xa297, 0xa2b4, 0xa2d0, 0xa2eb, 0xa305, 0xa31f, 0xa33b, 0xa356,
// Entry 9100 - 913F
0xa371, 0xa38b, 0xa3a7, 0xa3c3, 0xa3de, 0xa3f8, 0xa413, 0xa430,
0xa44c, 0xa467, 0xa47d, 0xa499, 0xa4b5, 0xa4d3, 0xa4f0, 0xa50d,
0xa529, 0xa547, 0xa565, 0xa582, 0xa59e, 0xa5bb, 0xa5da, 0xa5f8,
0xa615, 0xa62d, 0xa646, 0xa65f, 0xa67a, 0xa694, 0xa6ae, 0xa6c7,
0xa6e2, 0xa6fd, 0xa717, 0xa730, 0xa74a, 0xa766, 0xa781, 0xa79b,
0xa7b3, 0xa7c4, 0xa7d8, 0xa7ec, 0xa800, 0xa814, 0xa828, 0xa83c,
0xa850, 0xa864, 0xa878, 0xa88d, 0xa8a2, 0xa8b7, 0xa8cc, 0xa8e1,
0xa8f6, 0xa90b, 0xa920, 0xa935, 0xa94a, 0xa95f, 0xa974, 0xa988,
// Entry 9140 - 917F
0xa998, 0xa9a7, 0xa9b6, 0xa9c7, 0xa9d7, 0xa9e7, 0xa9f6, 0xaa07,
0xaa18, 0xaa28, 0xaa4d, 0xaa7b, 0xaa92, 0xaaad, 0xaad8, 0xaafc,
0xab20, 0xab44, 0xab68, 0xab8c, 0xabb0, 0xabd4, 0xabf8, 0xac1c,
0xac40, 0xac64, 0xac88, 0xacac, 0xacd0, 0xacf4, 0xad18, 0xad3c,
0xad60, 0xad84, 0xada8, 0xadcc, 0xadf0, 0xae14, 0xae38, 0xae5c,
0xae80, 0xaeaf, 0xaed4, 0xaef9, 0xaf03, 0xaf0d, 0xaf1c, 0xaf3a,
0xaf58, 0xaf76, 0xaf94, 0xafb2, 0xafd0, 0xafee, 0xb00c, 0xb02a,
0xb048, 0xb066, 0xb084, 0xb0a2, 0xb0c0, 0xb0de, 0xb0fc, 0xb11a,
// Entry 9180 - 91BF
0xb138, 0xb156, 0xb174, 0xb192, 0xb1b0, 0xb1ce, 0xb1ec, 0xb20a,
0xb228, 0xb232, 0xb23c, 0xb246, 0xb250, 0xb25b, 0xb265, 0xb28c,
0xb2b3, 0xb2da, 0xb301, 0xb328, 0xb34f, 0xb376, 0xb39d, 0xb3c4,
0xb3eb, 0xb412, 0xb439, 0xb460, 0xb487, 0xb4ae, 0xb4d5, 0xb4fc,
0xb523, 0xb54a, 0xb571, 0xb598, 0xb5bf, 0xb5e6, 0xb60d, 0xb634,
0xb65b, 0xb669, 0xb677, 0xb685, 0xb68f, 0xb6b0, 0xb6c4, 0xb6eb,
0xb712, 0xb739, 0xb760, 0xb787, 0xb7ae, 0xb7d5, 0xb7fc, 0xb823,
0xb84a, 0xb871, 0xb898, 0xb8bf, 0xb8e6, 0xb90d, 0xb934, 0xb95b,
// Entry 91C0 - 91FF
0xb982, 0xb9a9, 0xb9d0, 0xb9f7, 0xba1e, 0xba45, 0xba6c, 0xba93,
0xbaba, 0xbae9, 0xbafc, 0xbb0f, 0xbb22, 0xbb35, 0xbb48, 0xbb51,
0xbb5b, 0xbb67, 0xbb73, 0xbb7d, 0xbb88, 0xbb92, 0xbb9c, 0xbba7,
0xbbc7, 0xbbd1, 0xbbe0, 0xbbf5, 0xbc02, 0xbc10, 0xbc1f, 0xbc35,
0xbc4c, 0xbc68, 0xbc77, 0xbc93, 0xbcaf, 0xbcb9, 0xbcc4, 0xbcd2,
0xbce2, 0xbced, 0xbcf8, 0xbd03, 0xbd13, 0xbd35, 0xbd57, 0xbd79,
0xbd9b, 0xbdbd, 0xbddf, 0xbe01, 0xbe23, 0xbe45, 0xbe67, 0xbe89,
0xbeab, 0xbecd, 0xbeef, 0xbf11, 0xbf33, 0xbf55, 0xbf77, 0xbf99,
// Entry 9200 - 923F
0xbfbb, 0xbfdd, 0xbfff, 0xc021, 0xc043, 0xc065, 0xc087, 0xc09b,
0xc0b0, 0xc0c3, 0xc0e5, 0xc107, 0xc129, 0xc13c, 0xc15e, 0xc180,
0xc1a2, 0xc1c4, 0xc1e6, 0xc208, 0xc22a, 0xc24c, 0xc26e, 0xc290,
0xc2b2, 0xc2d4, 0xc2f6, 0xc318, 0xc33a, 0xc35c, 0xc37e, 0xc3a0,
0xc3c2, 0xc3e4, 0xc406, 0xc428, 0xc44a, 0xc46c, 0xc48e, 0xc4b0,
0xc4d2, 0xc4f4, 0xc516, 0xc538, 0xc55a, 0xc57c, 0xc59e, 0xc5c0,
0xc5e2, 0xc604, 0xc626, 0xc648, 0xc66a, 0xc68c, 0xc6bf, 0xc6f2,
0xc725, 0xc758, 0xc78b, 0xc7be, 0xc7f1, 0xc824, 0xc857, 0xc872,
// Entry 9240 - 927F
0xc88a, 0xc89f, 0xc8b4, 0xc8cb, 0xc8e0, 0xc8fb, 0xc911, 0xc918,
0xc91d, 0xc92c, 0xc93c, 0xc952, 0xc959, 0xc96a, 0xc97f, 0xc986,
0xc995, 0xc99f, 0xc9a6, 0xc9af, 0xc9c8, 0xc9dc, 0xc9f6, 0xca0a,
0xca19, 0xca34, 0xca4d, 0xca67, 0xca77, 0xca91, 0xcaa9, 0xcac4,
0xcad1, 0xcae3, 0xcaff, 0xcb1a, 0xcb2d, 0xcb3a, 0xcb46, 0xcb53,
0xcb5e, 0xcb6b, 0xcb74, 0xcb8e, 0xcba4, 0xcbc4, 0xcbd3, 0xcbe2,
0xcbf6, 0xcc08, 0xcc0b, 0xcc1c, 0xcc23, 0xcc27, 0xcc2e, 0xcc36,
0xcc3e, 0xcc4c, 0xcc5a, 0xcc63, 0xcc69, 0xcc73, 0xcc78, 0xcc86,
// Entry 9280 - 92BF
0xcc8a, 0xcc92, 0xcc9b, 0xcca2, 0xccae, 0xccb9, 0xccbd, 0xcccd,
0xccd7, 0xcce2, 0xccf9, 0xcd01, 0xcd07, 0xcd10, 0xcd16, 0xcd1b,
0xcd25, 0xcd2e, 0xcd33, 0xcd39, 0xcd42, 0xcd4b, 0xcd56, 0xcd5a,
0xcd5f, 0xcd67, 0xcd71, 0xcd7a, 0xcd88, 0xcd94, 0xcd9f, 0xcdab,
0xcdb4, 0xcdbf, 0xcdcd, 0xcdda, 0xcde3, 0xcde8, 0xcdf4, 0xce08,
0xce0d, 0xce11, 0xce16, 0xce22, 0xce3d, 0xce4b, 0xce55, 0xce5e,
0xce66, 0xce6c, 0xce79, 0xce7e, 0xce86, 0xce8d, 0xce96, 0xce9f,
0xcea8, 0xceb3, 0xceba, 0xcec8, 0xcedd, 0xcef0, 0xcefa, 0xcf08,
// Entry 92C0 - 92FF
0xcf16, 0xcf1e, 0xcf30, 0xcf3b, 0xcf54, 0xcf6c, 0xcf73, 0xcf79,
0xcf88, 0xcf95, 0xcfa3, 0xcfb1, 0xcfc1, 0xcfca, 0xcfdb, 0xcfe2,
0xcfee, 0xcffb, 0xd008, 0xd015, 0xd024, 0xd032, 0xd03f, 0xd049,
0xd05e, 0xd06c, 0xd07a, 0xd094, 0xd0a6, 0xd0b4, 0xd0c3, 0xd0de,
0xd0ef, 0xd0fb, 0xd108, 0xd126, 0xd145, 0xd150, 0xd161, 0xd16f,
0xd17b, 0xd189, 0xd19e, 0xd1a8, 0xd1b4, 0xd1ba, 0xd1c3, 0xd1d1,
0xd1d8, 0xd1e3, 0xd1e9, 0xd1f6, 0xd205, 0xd20f, 0xd219, 0xd225,
0xd22e, 0xd236, 0xd23d, 0xd251, 0xd25d, 0xd273, 0xd27c, 0xd282,
// Entry 9300 - 933F
0xd292, 0xd299, 0xd29f, 0xd2ac, 0xd2c3, 0xd2da, 0xd2ea, 0xd2fd,
0xd30b, 0xd316, 0xd31c, 0xd322, 0xd32e, 0xd334, 0xd340, 0xd351,
0xd35f, 0xd366, 0xd373, 0xd379, 0xd38a, 0xd394, 0xd3a8, 0xd3b2,
0xd3cd, 0xd3e6, 0xd402, 0xd416, 0xd41d, 0xd430, 0xd445, 0xd454,
0xd45d, 0xd474, 0xd486, 0xd48c, 0xd499, 0xd4a6, 0xd4ad, 0xd4bb,
0xd4cc, 0xd4db, 0xd4ef, 0xd503, 0xd50b, 0xd50f, 0xd527, 0xd52c,
0xd536, 0xd547, 0xd54d, 0xd55d, 0xd564, 0xd573, 0xd582, 0xd591,
0xd59e, 0xd5ab, 0xd5bc, 0xd5cd, 0xd5d4, 0xd5e1, 0xd5e6, 0xd607,
// Entry 9340 - 937F
0xd614, 0xd61b, 0xd63e, 0xd65f, 0xd680, 0xd6a1, 0xd6c2, 0xd6c5,
0xd6ca, 0xd6cc, 0xd6d9, 0xd6dc, 0xd6e1, 0xd6e8, 0xd6ee, 0xd6f1,
0xd6f7, 0xd700, 0xd705, 0xd70a, 0xd70f, 0xd714, 0xd717, 0xd71b,
0xd720, 0xd726, 0xd72d, 0xd734, 0xd737, 0xd73a, 0xd73e, 0xd746,
0xd74d, 0xd759, 0xd75c, 0xd75f, 0xd767, 0xd772, 0xd776, 0xd783,
0xd78b, 0xd791, 0xd79f, 0xd7a9, 0xd7c0, 0xd7c4, 0xd7cb, 0xd7d0,
0xd7d6, 0xd7e5, 0xd7f3, 0xd7fa, 0xd804, 0xd80c, 0xd816, 0xd821,
0xd829, 0xd834, 0xd842, 0xd84c, 0xd857, 0xd85f, 0xd867, 0xd870,
// Entry 9380 - 93BF
0xd87c, 0xd885, 0xd88e, 0xd898, 0xd8a0, 0xd8aa, 0xd8b2, 0xd8b6,
0xd8b9, 0xd8bc, 0xd8c0, 0xd8c5, 0xd8cb, 0xd8eb, 0xd90d, 0xd92f,
0xd952, 0xd962, 0xd972, 0xd97e, 0xd98c, 0xd99c, 0xd9af, 0xd9be,
0xd9c3, 0xd9cd, 0xd9d7, 0xd9de, 0xd9e5, 0xd9ea, 0xd9ef, 0xd9f5,
0xd9fb, 0xda09, 0xda0e, 0xda15, 0xda1a, 0xda23, 0xda30, 0xda40,
0xda4d, 0xda59, 0xda63, 0xda75, 0xda88, 0xda8b, 0xda8f, 0xda92,
0xda97, 0xda9d, 0xdab8, 0xdacd, 0xdae4, 0xdaf2, 0xdb07, 0xdb16,
0xdb2c, 0xdb3f, 0xdb4e, 0xdb57, 0xdb62, 0xdb66, 0xdb79, 0xdb81,
// Entry 93C0 - 93FF
0xdb8e, 0xdb9d, 0xdba2, 0xdbac, 0xdbc2, 0xdbcf, 0xdbd2, 0xdbd7,
0xdbee, 0xdbf7, 0xdbfd, 0xdc05, 0xdc10, 0xdc1c, 0xdc23, 0xdc2e,
0xdc35, 0xdc39, 0xdc42, 0xdc4d, 0xdc51, 0xdc5a, 0xdc5e, 0xdc65,
0xdc76, 0xdc7d, 0xdc8a, 0xdc96, 0xdca0, 0xdcaf, 0xdcbc, 0xdccc,
0xdcd6, 0xdce1, 0xdced, 0xdcf9, 0xdd0a, 0xdd1a, 0xdd2a, 0xdd49,
0xdd5c, 0xdd68, 0xdd6c, 0xdd7b, 0xdd8b, 0xdda1, 0xdda8, 0xddb3,
0xddbe, 0xddcb, 0xddd7, 0xdde5, 0xddf4, 0xde00, 0xde15, 0xde1e,
0xde2f, 0xde40, 0xde4b, 0xde61, 0xde7a, 0xde91, 0xdea9, 0xdeb9,
// Entry 9400 - 943F
0xdede, 0xdee2, 0xdef3, 0xdefc, 0xdf04, 0xdf0f, 0xdf1b, 0xdf1e,
0xdf29, 0xdf39, 0xdf47, 0xdf55, 0xdf5d, 0xdf6e, 0xdf78, 0xdf90,
0xdfaa, 0xdfb3, 0xdfbc, 0xdfc3, 0xdfd0, 0xdfd9, 0xdfe7, 0xdff7,
0xe004, 0xe00a, 0xe012, 0xe030, 0xe03b, 0xe044, 0xe04e, 0xe057,
0xe062, 0xe067, 0xe071, 0xe077, 0xe07b, 0xe08d, 0xe092, 0xe09d,
0xe0ae, 0xe0c8, 0xe0da, 0xe0e5, 0xe0ef, 0xe0f6, 0xe103, 0xe114,
0xe137, 0xe157, 0xe176, 0xe193, 0xe1b1, 0xe1b8, 0xe1c3, 0xe1cc,
0xe1d8, 0xe202, 0xe210, 0xe220, 0xe230, 0xe241, 0xe247, 0xe258,
// Entry 9440 - 947F
0xe264, 0xe26e, 0xe273, 0xe280, 0xe28e, 0xe29d, 0xe2a9, 0xe2c2,
0xe2f7, 0xe345, 0xe377, 0xe3ad, 0xe3c2, 0xe3d8, 0xe3f8, 0xe3ff,
0xe41a, 0xe438, 0xe43f, 0xe44c, 0xe46a, 0xe489, 0xe49a, 0xe4ae,
0xe4b1, 0xe4b5, 0xe4be, 0xe4c2, 0xe4df, 0xe4e7, 0xe4f2, 0xe4fe,
0xe51d, 0xe53b, 0xe56f, 0xe58f, 0xe5ab, 0xe5c7, 0xe5d1, 0xe5f7,
0xe61b, 0xe633, 0xe64b, 0xe669, 0xe66d, 0xe67b, 0xe681, 0xe687,
0xe693, 0xe698, 0xe69e, 0xe6a8, 0xe6b1, 0xe6bd, 0xe6dd, 0xe6f9,
0xe707, 0xe71a, 0xe72d, 0xe73d, 0xe74e, 0xe762, 0xe774, 0xe788,
// Entry 9480 - 94BF
0xe79a, 0xe7b2, 0xe7cc, 0xe7ea, 0xe80a, 0xe82b, 0xe84c, 0xe860,
0xe883, 0xe88f, 0xe8b6, 0xe8de, 0xe8f6, 0xe907, 0xe918, 0xe924,
0xe92d, 0xe93a, 0xe93f, 0xe945, 0xe94e, 0xe968, 0xe977, 0xe98c,
0xe9a1, 0xe9b8, 0xe9ce, 0xe9e4, 0xe9f9, 0xea10, 0xea27, 0xea3d,
0xea52, 0xea6a, 0xea82, 0xea97, 0xeaac, 0xeac3, 0xead9, 0xeaef,
0xeb04, 0xeb1b, 0xeb32, 0xeb48, 0xeb5d, 0xeb75, 0xeb8d, 0xeb9a,
0xebbb, 0xebdf, 0xebe7, 0xec00, 0xec0c, 0xec10, 0xec16, 0xec27,
0xec41, 0xec4a, 0xec4e, 0xec6d, 0xec7a, 0xec89, 0xec8f, 0xec99,
// Entry 94C0 - 94FF
0xeca1, 0xecac, 0xecc8, 0xece4, 0xed01, 0xed1a, 0xed33, 0xed4c,
0xed62, 0xed72, 0xed82, 0xed99, 0xeda8, 0xedc1, 0xedd2, 0xeddf,
0xedf0, 0xee08, 0xee1f, 0xee34, 0xee45, 0xee56, 0xee69, 0xee89,
0xeeb2, 0xeec9, 0xeee2, 0xeef7, 0xef20, 0xef55, 0xef78, 0xef9a,
0xefbd, 0xefdf, 0xf002, 0xf024, 0xf047, 0xf067, 0xf089, 0xf0a9,
0xf0cb, 0xf0eb, 0xf10d, 0xf118, 0xf128, 0xf13a, 0xf153, 0xf15a,
0xf16b, 0xf187, 0xf1a3, 0xf1b9, 0xf1c7, 0xf1d5, 0xf1e5, 0xf1f5,
0xf207, 0xf210, 0xf225, 0xf22e, 0xf234, 0xf240, 0xf248, 0xf259,
// Entry 9500 - 953F
0xf26b, 0xf289, 0xf29e, 0xf2b0, 0xf2c0, 0xf2cf, 0xf2db, 0xf2e1,
0xf2ec, 0xf2ff, 0xf30c, 0xf318, 0xf322, 0xf331, 0xf33f, 0xf343,
0xf34c, 0xf354, 0xf362, 0xf36c, 0xf377, 0xf37f, 0xf383, 0xf388,
0xf393, 0xf3a2, 0xf3b5, 0xf3c3, 0xf3cb, 0xf3d3, 0xf3da, 0xf404,
0xf412, 0xf42b, 0xf444, 0xf44f, 0xf456, 0xf469, 0xf47f, 0xf48a,
0xf496, 0xf49a, 0xf4b5, 0xf4c5, 0xf4d5, 0xf4e4, 0xf4f4, 0xf506,
0xf519, 0xf52b, 0xf53f, 0xf552, 0xf566, 0xf577, 0xf589, 0xf594,
0xf5a9, 0xf5b7, 0xf5cd, 0xf5dc, 0xf5f4, 0xf608, 0xf625, 0xf635,
// Entry 9540 - 957F
0xf64f, 0xf658, 0xf662, 0xf66d, 0xf67e, 0xf691, 0xf696, 0xf6a3,
0xf6c2, 0xf6d8, 0xf6f4, 0xf721, 0xf74c, 0xf780, 0xf796, 0xf7ad,
0xf7b9, 0xf7d7, 0xf7f4, 0xf801, 0xf824, 0xf840, 0xf84d, 0xf859,
0xf86c, 0xf879, 0xf88d, 0xf899, 0xf8a6, 0xf8b5, 0xf8c1, 0xf8d5,
0xf8f3, 0xf910, 0xf92a, 0xf954, 0xf986, 0xf997, 0xf9a3, 0xf9ad,
0xf9b9, 0xf9c4, 0xf9d4, 0xf9ed, 0xfa0b, 0xfa28, 0xfa36, 0xfa42,
0xfa4c, 0xfa57, 0xfa61, 0xfa6f, 0xfa81, 0xfa95, 0xfaa0, 0xfac3,
0xfad9, 0xfae8, 0xfaf4, 0xfb01, 0xfb0b, 0xfb1d, 0xfb33, 0xfb56,
// Entry 9580 - 95BF
0xfb70, 0xfb90, 0xfbb7, 0xfbce, 0xfbef, 0xfbff, 0xfc0e, 0xfc1c,
0xfc32, 0xfc47, 0xfc57, 0xfc6d, 0xfc86, 0xfc9a, 0xfcae, 0xfcc0,
0xfcd3, 0xfce7, 0xfd04, 0xfd2c, 0xfd3b, 0xfd53, 0xfd6b, 0xfd83,
0xfd9b, 0xfdb3, 0xfdcb, 0xfdea, 0xfe09, 0xfe28, 0xfe47, 0xfe64,
0xfe81, 0xfe9e, 0xfebb, 0xfede, 0xff01, 0xff24, 0xff47, 0xff5e,
0xff75, 0xff8c, 0xffa3, 0xffc0, 0xffdd, 0xfffa, 0x0017, 0x0033,
0x005f, 0x007a, 0x00a5, 0x00b5, 0x00c3, 0x00d4, 0x00e4, 0x00ff,
0x0120, 0x0139, 0x0158, 0x0170, 0x0188, 0x01c4, 0x01f9, 0x0232,
// Entry 95C0 - 95FF
0x024c, 0x026b, 0x0290, 0x02a2, 0x02bc, 0x02c9, 0x02de, 0x02e4,
0x02ee, 0x02fe, 0x0309, 0x0319, 0x033a, 0x033f, 0x0344, 0x034e,
0x0355, 0x0359, 0x0361, 0x0364, 0x0370, 0x037a, 0x0382, 0x0389,
0x0392, 0x039d, 0x03a7, 0x03ba, 0x03be, 0x03cb, 0x03d5, 0x03e8,
0x03fc, 0x040a, 0x041b, 0x0422, 0x042a, 0x043a, 0x044c, 0x045d,
0x046b, 0x046f, 0x0476, 0x047f, 0x0497, 0x04ad, 0x04be, 0x04d9,
0x04f0, 0x04f4, 0x0501, 0x050f, 0x0520, 0x053e, 0x0552, 0x0566,
0x057e, 0x0585, 0x0590, 0x0599, 0x05ab, 0x05b5, 0x05c3, 0x05d4,
// Entry 9600 - 963F
0x05df, 0x05ec, 0x05f4, 0x05ff, 0x0605, 0x0611, 0x0617, 0x061b,
0x0622, 0x0632, 0x0639, 0x0646, 0x0652, 0x066f, 0x067e, 0x0698,
0x06a3, 0x06af, 0x06bd, 0x06d3, 0x06e0, 0x06ec, 0x06ef, 0x06ff,
0x070d, 0x071d, 0x0722, 0x0728, 0x0734, 0x0737, 0x073f, 0x0748,
0x0750, 0x0760, 0x0765, 0x076e, 0x077f, 0x0785, 0x078d, 0x0795,
0x07a2, 0x07ac, 0x07c9, 0x07dd, 0x07f7, 0x0805, 0x0820, 0x0832,
0x0843, 0x084c, 0x0860, 0x0871, 0x087f, 0x0886, 0x0893, 0x0898,
0x089c, 0x08a9, 0x08b3, 0x08c0, 0x08cc, 0x08d8, 0x08fa, 0x0913,
// Entry 9640 - 967F
0x092d, 0x0948, 0x0963, 0x0983, 0x09a3, 0x09c5, 0x09e5, 0x0a07,
0x0a24, 0x0a43, 0x0a62, 0x0a7e, 0x0aa7, 0x0ac9, 0x0af0, 0x0b19,
0x0b42, 0x0b60, 0x0b7a, 0x0b95, 0x0bb2, 0x0bd1, 0x0bf0, 0x0c11,
0x0c2b, 0x0c47, 0x0c65, 0x0c85, 0x0ca9, 0x0cce, 0x0cee, 0x0d13,
0x0d3c, 0x0d62, 0x0d8a, 0x0db2, 0x0de2, 0x0e13, 0x0e32, 0x0e4f,
0x0e6d, 0x0e8f, 0x0eba, 0x0ee0, 0x0f13, 0x0f3c, 0x0f65, 0x0f90,
0x0fad, 0x0fcc, 0x0feb, 0x100a, 0x1026, 0x1044, 0x1063, 0x1085,
0x10a2, 0x10bf, 0x10de, 0x10ff, 0x1120, 0x113c, 0x115a, 0x117a,
// Entry 9680 - 96BF
0x1195, 0x11b2, 0x11cf, 0x11e9, 0x1202, 0x121e, 0x123c, 0x1255,
0x126e, 0x128a, 0x12a4, 0x12bf, 0x12e2, 0x1307, 0x1325, 0x1342,
0x1367, 0x1386, 0x13a0, 0x13bb, 0x13db, 0x13f6, 0x1415, 0x1430,
0x1454, 0x1471, 0x149c, 0x14c9, 0x14ea, 0x150b, 0x1528, 0x1546,
0x1566, 0x1582, 0x15a4, 0x15c2, 0x15e2, 0x1602, 0x1622, 0x1642,
0x165f, 0x1681, 0x16a6, 0x16c2, 0x16dc, 0x16f7, 0x1716, 0x1731,
0x1750, 0x1770, 0x177e, 0x1789, 0x1796, 0x17a4, 0x17b4, 0x17c3,
0x17d6, 0x17dc, 0x17e4, 0x17ec, 0x17f2, 0x17f7, 0x1823, 0x184d,
// Entry 96C0 - 96FF
0x187a, 0x18a6, 0x18c1, 0x18d9, 0x18ea, 0x18fc, 0x1913, 0x192f,
0x1959, 0x1965, 0x1976, 0x1991, 0x19a3, 0x19b6, 0x19c7, 0x19d9,
0x19f0, 0x1a0c, 0x1a3b, 0x1a66, 0x1a73, 0x1a85, 0x1a9d, 0x1ab7,
0x1ae8, 0x1b15, 0x1b23, 0x1b35, 0x1b4d, 0x1b67, 0x1b93, 0x1ba3,
0x1bb4, 0x1bc6, 0x1bd6, 0x1beb, 0x1c01, 0x1c1c, 0x1c28, 0x1c35,
0x1c43, 0x1c4f, 0x1c5c, 0x1c6e, 0x1c85, 0x1c9f, 0x1cba, 0x1cd3,
0x1ced, 0x1d0c, 0x1d30, 0x1d49, 0x1d63, 0x1d7b, 0x1d94, 0x1db2,
0x1dd5, 0x1df0, 0x1e0c, 0x1e26, 0x1e41, 0x1e61, 0x1e7f, 0x1e9e,
// Entry 9700 - 973F
0x1eb6, 0x1ed8, 0x1ef5, 0x1f13, 0x1f2a, 0x1f4b, 0x1f73, 0x1f90,
0x1fad, 0x1fca, 0x1fe6, 0x1fff, 0x201e, 0x203c, 0x205f, 0x2080,
0x209f, 0x20be, 0x20e0, 0x20f0, 0x2109, 0x2117, 0x212e, 0x2145,
0x2158, 0x216b, 0x217d, 0x2190, 0x21a2, 0x21b2, 0x21c3, 0x21d6,
0x21e9, 0x21fb, 0x220e, 0x2220, 0x2231, 0x225e, 0x2289, 0x22b7,
0x22e4, 0x2312, 0x233e, 0x236d, 0x239b, 0x23c8, 0x23f3, 0x2421,
0x244e, 0x247e, 0x24ac, 0x24dd, 0x250d, 0x2537, 0x255f, 0x258a,
0x25b4, 0x25e4, 0x2612, 0x2643, 0x2673, 0x26a9, 0x26dd, 0x2714,
// Entry 9740 - 977F
0x274a, 0x277b, 0x27aa, 0x27dc, 0x280d, 0x283e, 0x286d, 0x289f,
0x28d0, 0x28ff, 0x292c, 0x295c, 0x298b, 0x29bb, 0x29e9, 0x2a1a,
0x2a4a, 0x2a7f, 0x2ab2, 0x2ae8, 0x2b1d, 0x2b38, 0x2b51, 0x2b6d,
0x2b88, 0x2b9f, 0x2bb4, 0x2bcc, 0x2be3, 0x2bfd, 0x2c15, 0x2c30,
0x2c4a, 0x2c6a, 0x2c88, 0x2ca9, 0x2cc9, 0x2cde, 0x2cf1, 0x2d07,
0x2d1c, 0x2d36, 0x2d4e, 0x2d69, 0x2d83, 0x2d9e, 0x2db9, 0x2dd4,
0x2def, 0x2e0a, 0x2e22, 0x2e48, 0x2e6c, 0x2e93, 0x2eb9, 0x2ee0,
0x2f07, 0x2f2e, 0x2f55, 0x2f75, 0x2f93, 0x2fb4, 0x2fd4, 0x2ff5,
// Entry 9780 - 97BF
0x3016, 0x3037, 0x3058, 0x307f, 0x30a4, 0x30cc, 0x30f3, 0x311b,
0x3143, 0x316b, 0x3193, 0x31b9, 0x31dd, 0x3204, 0x322a, 0x3251,
0x3278, 0x329f, 0x32c6, 0x32f1, 0x331a, 0x3346, 0x3371, 0x339d,
0x33c9, 0x33f5, 0x3421, 0x343d, 0x3457, 0x3474, 0x3490, 0x34bf,
0x34ec, 0x351c, 0x354b, 0x356c, 0x358b, 0x35ad, 0x35ce, 0x35e9,
0x360b, 0x362b, 0x364c, 0x366f, 0x3693, 0x36b3, 0x36d4, 0x36f5,
0x3718, 0x373a, 0x375c, 0x3786, 0x37b1, 0x37dc, 0x3808, 0x3823,
0x3845, 0x386b, 0x389c, 0x38bc, 0x38d8, 0x38f8, 0x3916, 0x3937,
// Entry 97C0 - 97FF
0x3957, 0x3970, 0x3989, 0x39a2, 0x39bb, 0x39df, 0x3a04, 0x3a33,
0x3a66, 0x3a9b, 0x3ad0, 0x3b05, 0x3b3a, 0x3b59, 0x3b80, 0x3ba9,
0x3bcc, 0x3bee, 0x3c02, 0x3c21, 0x3c41, 0x3c5f, 0x3c78, 0x3c88,
0x3c9c, 0x3cb8, 0x3cd5, 0x3cfa, 0x3d09, 0x3d14, 0x3d1f, 0x3d2c,
0x3d3d, 0x3d4d, 0x3d62, 0x3d6b, 0x3d78, 0x3d8e, 0x3d98, 0x3da4,
0x3db5, 0x3dc1, 0x3dd4, 0x3de4, 0x3df5, 0x3dfe, 0x3e28, 0x3e3c,
0x3e50, 0x3e5a, 0x3e68, 0x3e85, 0x3e92, 0x3e9c, 0x3ea5, 0x3eb2,
0x3ece, 0x3eea, 0x3f18, 0x3f3d, 0x3f65, 0x3f9b, 0x3fb8, 0x3fd8,
// Entry 9800 - 983F
0x3fe6, 0x3ff4, 0x4005, 0x400b, 0x4011, 0x401e, 0x402e, 0x4033,
0x4049, 0x4051, 0x4057, 0x4068, 0x4071, 0x407b, 0x4083, 0x408e,
0x409b, 0x40af, 0x40bf, 0x40cc, 0x40d1, 0x40d9, 0x40de, 0x40ef,
0x4101, 0x4112, 0x411e, 0x4132, 0x413f, 0x4156, 0x415e, 0x4169,
0x4172, 0x4179, 0x4181, 0x4186, 0x418c, 0x4192, 0x41a0, 0x41ab,
0x41be, 0x41cf, 0x41d2, 0x41df, 0x41e6, 0x41ef, 0x41f7, 0x41ff,
0x420d, 0x4218, 0x4222, 0x4231, 0x423f, 0x4246, 0x424e, 0x4251,
0x4258, 0x4263, 0x426b, 0x4276, 0x4281, 0x4286, 0x428f, 0x4294,
// Entry 9840 - 987F
0x42c3, 0x42cf, 0x42e5, 0x4307, 0x432b, 0x433a, 0x4347, 0x434c,
0x435a, 0x4371, 0x4388, 0x438c, 0x4394, 0x439b, 0x43a6, 0x43af,
0x43b3, 0x43bc, 0x43c4, 0x43ca, 0x43d6, 0x43db, 0x43df, 0x43e2,
0x43e7, 0x43ea, 0x43f2, 0x43fb, 0x43ff, 0x4406, 0x440c, 0x4416,
0x441c, 0x4421, 0x442d, 0x4437, 0x443f, 0x4447, 0x444c, 0x4453,
0x445b, 0x4460, 0x4467, 0x4473, 0x4479, 0x4480, 0x4487, 0x448f,
0x4496, 0x449c, 0x44a0, 0x44a7, 0x44ab, 0x44b0, 0x44b5, 0x44be,
0x44c3, 0x44cb, 0x44d1, 0x44d7, 0x44dc, 0x44e0, 0x44e9, 0x44f5,
// Entry 9880 - 98BF
0x450d, 0x4527, 0x453b, 0x4555, 0x4559, 0x455c, 0x4560, 0x4565,
0x456e, 0x457a, 0x4585, 0x4599, 0x45ad, 0x45be, 0x45cc, 0x45da,
0x45e6, 0x45ed, 0x45f8, 0x4604, 0x460a, 0x460f, 0x4616, 0x461c,
0x4622, 0x462c, 0x4634, 0x463e, 0x4643, 0x4652, 0x4661, 0x466c,
0x467d, 0x4682, 0x4687, 0x4692, 0x46a0, 0x46b5, 0x46ca, 0x46d9,
0x46f1, 0x46f5, 0x46fa, 0x4701, 0x470a, 0x470d, 0x4712, 0x4718,
0x471d, 0x4729, 0x4733, 0x4738, 0x473e, 0x4742, 0x4747, 0x4758,
0x4763, 0x4776, 0x477f, 0x4789, 0x4799, 0x47a0, 0x47a6, 0x47b7,
// Entry 98C0 - 98FF
0x47be, 0x47c3, 0x47c9, 0x47d0, 0x47dd, 0x47ec, 0x47f8, 0x4802,
0x480c, 0x4811, 0x4817, 0x4824, 0x482f, 0x4835, 0x483c, 0x4848,
0x485a, 0x486d, 0x487f, 0x4893, 0x48a7, 0x48b9, 0x48e6, 0x4913,
0x4942, 0x4969, 0x4991, 0x49b8, 0x49e1, 0x4a0a, 0x4a31, 0x4a58,
0x4a80, 0x4aa7, 0x4ad0, 0x4af9, 0x4b20, 0x4b49, 0x4b73, 0x4b9c,
0x4bc7, 0x4bf2, 0x4c1b, 0x4c55, 0x4c8f, 0x4ccb, 0x4ce2, 0x4cfa,
0x4d11, 0x4d2a, 0x4d43, 0x4d5a, 0x4d71, 0x4d89, 0x4da0, 0x4db9,
0x4dd2, 0x4de9, 0x4e02, 0x4e1c, 0x4e35, 0x4e50, 0x4e6b, 0x4e84,
// Entry 9900 - 993F
0x4ebe, 0x4ef8, 0x4f34, 0x4f68, 0x4f9d, 0x4fd1, 0x5007, 0x503d,
0x5071, 0x50a5, 0x50da, 0x510e, 0x5144, 0x517a, 0x51ae, 0x51e4,
0x521b, 0x5251, 0x5289, 0x52c1, 0x52f7, 0x532f, 0x5367, 0x53a1,
0x53b7, 0x53cd, 0x53e5, 0x5412, 0x543f, 0x546e, 0x5486, 0x549d,
0x54b6, 0x54ce, 0x54e5, 0x54fe, 0x550e, 0x551f, 0x552f, 0x5540,
0x5553, 0x5567, 0x557b, 0x558c, 0x559f, 0x55b1, 0x55c4, 0x55d9,
0x55ef, 0x5605, 0x5618, 0x562d, 0x5641, 0x5656, 0x5662, 0x5674,
0x567a, 0x5680, 0x568c, 0x569c, 0x56a6, 0x56b0, 0x56bd, 0x56cd,
// Entry 9940 - 997F
0x56d8, 0x56dd, 0x56e3, 0x56e8, 0x56ec, 0x56f5, 0x56fe, 0x5708,
0x570e, 0x571b, 0x5722, 0x5727, 0x572b, 0x5733, 0x5741, 0x5747,
0x5754, 0x5759, 0x575e, 0x5761, 0x576a, 0x576f, 0x577e, 0x5787,
0x5790, 0x5794, 0x57a1, 0x57ac, 0x57b2, 0x57b6, 0x57bc, 0x57c2,
0x57c9, 0x57d6, 0x57da, 0x57e0, 0x57ea, 0x57f4, 0x57fd, 0x5804,
0x5808, 0x5813, 0x5826, 0x5831, 0x5836, 0x5846, 0x584f, 0x5855,
0x5858, 0x585c, 0x5862, 0x586b, 0x5877, 0x587b, 0x5882, 0x5887,
0x588c, 0x5896, 0x58a4, 0x58ac, 0x58b5, 0x58b9, 0x58c6, 0x58cb,
// Entry 9980 - 99BF
0x58db, 0x58e0, 0x58ee, 0x58fa, 0x5909, 0x591a, 0x5925, 0x5933,
0x5937, 0x593c, 0x5942, 0x594d, 0x5958, 0x595d, 0x5966, 0x596c,
0x5972, 0x5978, 0x5986, 0x598b, 0x598e, 0x5999, 0x59a0, 0x59ae,
0x59b6, 0x59c2, 0x59cf, 0x59f6, 0x5a0b, 0x5a23, 0x5a33, 0x5a3d,
0x5a44, 0x5a50, 0x5a69, 0x5a77, 0x5a82, 0x5aaa, 0x5ab9, 0x5ac7,
0x5ad5, 0x5ae1, 0x5afd, 0x5b08, 0x5b1e, 0x5b35, 0x5b44, 0x5b53,
0x5b63, 0x5b72, 0x5b82, 0x5b92, 0x5ba3, 0x5bb2, 0x5bc2, 0x5bd2,
0x5be3, 0x5bf3, 0x5c04, 0x5c15, 0x5c27, 0x5c36, 0x5c46, 0x5c56,
// Entry 99C0 - 99FF
0x5c67, 0x5c77, 0x5c88, 0x5c9a, 0x5caa, 0x5cbb, 0x5ccc, 0x5cde,
0x5cef, 0x5d01, 0x5d13, 0x5d26, 0x5d35, 0x5d45, 0x5d55, 0x5d66,
0x5d76, 0x5d87, 0x5d98, 0x5daa, 0x5dba, 0x5dcb, 0x5ddd, 0x5dee,
0x5e00, 0x5e12, 0x5e25, 0x5e35, 0x5e46, 0x5e57, 0x5e69, 0x5e7a,
0x5e8c, 0x5e9e, 0x5eb1, 0x5ec2, 0x5ed4, 0x5ee6, 0x5ef9, 0x5f0b,
0x5f1e, 0x5f31, 0x5f6c, 0x5fa6, 0x5fe1, 0x601b, 0x604f, 0x608b,
0x60c6, 0x6102, 0x613d, 0x6172, 0x61b4, 0x61f1, 0x622c, 0x6269,
0x62a4, 0x62da, 0x6316, 0x6350, 0x638c, 0x63c6, 0x63fb, 0x643c,
// Entry 9A00 - 9A3F
0x6478, 0x64b3, 0x64ef, 0x652a, 0x655f, 0x659a, 0x65d4, 0x660f,
0x6649, 0x667d, 0x66be, 0x66fa, 0x6734, 0x6770, 0x67aa, 0x67df,
0x681c, 0x6857, 0x6894, 0x68cf, 0x6905, 0x6947, 0x6980, 0x69b8,
0x69f0, 0x6a28, 0x6a49, 0x6a6b, 0x6a8d, 0x6aaf, 0x6aca, 0x6ae5,
0x6b00, 0x6b1b, 0x6b36, 0x6b51, 0x6b6e, 0x6b8b, 0x6ba8, 0x6bc5,
0x6be2, 0x6bff, 0x6c1e, 0x6c3d, 0x6c5d, 0x6c7d, 0x6c9d, 0x6cbd,
0x6cd4, 0x6ced, 0x6d05, 0x6d1f, 0x6d38, 0x6d4f, 0x6d68, 0x6d80,
0x6d9a, 0x6db3, 0x6dc9, 0x6de0, 0x6df7, 0x6e0e, 0x6e22, 0x6e56,
// Entry 9A40 - 9A7F
0x6e8a, 0x6ebd, 0x6ecf, 0x6ee9, 0x6efe, 0x6f1c, 0x6f3a, 0x6f5f,
0x6f83, 0x6fa5, 0x6fc8, 0x6feb, 0x700d, 0x7044, 0x707c, 0x70b3,
0x70eb, 0x7132, 0x717a, 0x71c1, 0x7208, 0x7260, 0x72b8, 0x730f,
0x7366, 0x73bd, 0x7414, 0x7437, 0x7469, 0x7481, 0x7493, 0x74a8,
0x74be, 0x74e8, 0x751c, 0x7551, 0x757b, 0x75a3, 0x75b3, 0x75c4,
0x75d6, 0x75ec, 0x7603, 0x7631, 0x764a, 0x7672, 0x7697, 0x76be,
0x76e4, 0x7702, 0x770e, 0x772b, 0x7744, 0x775e, 0x7775, 0x778e,
0x779e, 0x77be, 0x77dd, 0x77f2, 0x7806, 0x783c, 0x7872, 0x78a8,
// Entry 9A80 - 9ABF
0x78de, 0x7914, 0x794b, 0x7982, 0x79b8, 0x79fe, 0x7a45, 0x7a8b,
0x7ad0, 0x7b15, 0x7b5a, 0x7b9f, 0x7be3, 0x7c08, 0x7c2e, 0x7c56,
0x7c7c, 0x7c9a, 0x7cb8, 0x7cd5, 0x7cf3, 0x7d18, 0x7d3e, 0x7d66,
0x7d8c, 0x7dbf, 0x7df5, 0x7e2b, 0x7e5e, 0x7e72, 0x7e85, 0x7e98,
0x7ead, 0x7ec1, 0x7ed5, 0x7ee8, 0x7efd, 0x7f12, 0x7f26, 0x7f37,
0x7f58, 0x7f79, 0x7f9a, 0x7fbb, 0x7fdc, 0x7ffd, 0x801e, 0x803f,
0x8060, 0x8081, 0x80a2, 0x80c3, 0x80e4, 0x8105, 0x8126, 0x8147,
0x8168, 0x8189, 0x81aa, 0x81cb, 0x81ec, 0x820d, 0x822e, 0x824f,
// Entry 9AC0 - 9AFF
0x8270, 0x8291, 0x82b2, 0x82d3, 0x82f4, 0x8315, 0x8336, 0x8357,
0x8378, 0x8399, 0x83ba, 0x83db, 0x83fc, 0x841d, 0x843e, 0x845f,
0x8480, 0x84a1, 0x84c2, 0x84e3, 0x8504, 0x8525, 0x8546, 0x8567,
0x8588, 0x85a9, 0x85ca, 0x85eb, 0x860c, 0x862d, 0x864e, 0x866f,
0x8690, 0x86b1, 0x86d2, 0x86f3, 0x8714, 0x8735, 0x8756, 0x8777,
0x8798, 0x87b9, 0x87da, 0x87fb, 0x881c, 0x883d, 0x885e, 0x887f,
0x88a0, 0x88c1, 0x88e2, 0x8903, 0x8924, 0x8945, 0x8966, 0x8987,
0x89a8, 0x89c9, 0x89ea, 0x8a0b, 0x8a2c, 0x8a4d, 0x8a6e, 0x8a8f,
// Entry 9B00 - 9B3F
0x8ab0, 0x8ad1, 0x8af2, 0x8b13, 0x8b34, 0x8b55, 0x8b76, 0x8b97,
0x8bb8, 0x8bd9, 0x8bfa, 0x8c1b, 0x8c3c, 0x8c5d, 0x8c7e, 0x8c9f,
0x8cc0, 0x8ce1, 0x8d02, 0x8d23, 0x8d44, 0x8d65, 0x8d86, 0x8da7,
0x8dc8, 0x8de9, 0x8e0a, 0x8e2b, 0x8e4c, 0x8e6d, 0x8e8e, 0x8eaf,
0x8ed0, 0x8ef1, 0x8f12, 0x8f33, 0x8f54, 0x8f75, 0x8f96, 0x8fb7,
0x8fd8, 0x8ff9, 0x901a, 0x903b, 0x905c, 0x907d, 0x909e, 0x90bf,
0x90e0, 0x9101, 0x9122, 0x9143, 0x9164, 0x9185, 0x91a6, 0x91c7,
0x91e8, 0x9209, 0x922a, 0x924b, 0x926c, 0x928d, 0x92ae, 0x92cf,
// Entry 9B40 - 9B7F
0x92f0, 0x9311, 0x9332, 0x9353, 0x9374, 0x9395, 0x93b6, 0x93d7,
0x93f8, 0x9419, 0x943a, 0x945b, 0x947c, 0x949d, 0x94be, 0x94df,
0x9500, 0x9521, 0x9542, 0x9563, 0x9584, 0x95a5, 0x95c6, 0x95e7,
0x9608, 0x9629, 0x964a, 0x966b, 0x968c, 0x96ad, 0x96ce, 0x96ef,
0x9710, 0x9731, 0x9752, 0x9773, 0x9794, 0x97b5, 0x97d6, 0x97f7,
0x9818, 0x9839, 0x985a, 0x987b, 0x989c, 0x98bd, 0x98de, 0x98ff,
0x9920, 0x9941, 0x9962, 0x9983, 0x99a4, 0x99c5, 0x99e6, 0x9a07,
0x9a28, 0x9a49, 0x9a6a, 0x9a8b, 0x9aac, 0x9acd, 0x9aee, 0x9b0f,
// Entry 9B80 - 9BBF
0x9b30, 0x9b51, 0x9b72, 0x9b93, 0x9bb4, 0x9bd5, 0x9bf6, 0x9c17,
0x9c38, 0x9c59, 0x9c7a, 0x9c9b, 0x9cbc, 0x9cdd, 0x9cfe, 0x9d1f,
0x9d40, 0x9d61, 0x9d82, 0x9da3, 0x9dc4, 0x9de5, 0x9e06, 0x9e27,
0x9e48, 0x9e69, 0x9e8a, 0x9eab, 0x9ecc, 0x9eed, 0x9f0e, 0x9f2f,
0x9f50, 0x9f71, 0x9f92, 0x9fb3, 0x9fd4, 0x9ff5, 0xa016, 0xa037,
0xa058, 0xa079, 0xa09a, 0xa0bb, 0xa0dc, 0xa0fd, 0xa11e, 0xa13f,
0xa160, 0xa181, 0xa1a2, 0xa1c3, 0xa1e4, 0xa205, 0xa226, 0xa247,
0xa268, 0xa289, 0xa2aa, 0xa2cb, 0xa2ec, 0xa30d, 0xa32e, 0xa34f,
// Entry 9BC0 - 9BFF
0xa370, 0xa391, 0xa3b2, 0xa3d3, 0xa3f4, 0xa415, 0xa436, 0xa457,
0xa478, 0xa499, 0xa4ba, 0xa4db, 0xa4fc, 0xa51d, 0xa53e, 0xa55f,
0xa580, 0xa5a1, 0xa5c2, 0xa5e3, 0xa604, 0xa625, 0xa646, 0xa667,
0xa688, 0xa6a9, 0xa6ca, 0xa6eb, 0xa70c, 0xa72d, 0xa74e, 0xa76f,
0xa790, 0xa7b1, 0xa7d2, 0xa7f3, 0xa814, 0xa835, 0xa856, 0xa877,
0xa898, 0xa8b9, 0xa8da, 0xa8fb, 0xa91c, 0xa93d, 0xa95e, 0xa97f,
0xa9a0, 0xa9c1, 0xa9e2, 0xaa03, 0xaa24, 0xaa45, 0xaa66, 0xaa87,
0xaaa8, 0xaac9, 0xaaea, 0xab0b, 0xab2c, 0xab4d, 0xab6e, 0xab8f,
// Entry 9C00 - 9C3F
0xabb0, 0xabd1, 0xabf2, 0xac13, 0xac34, 0xac55, 0xac76, 0xac97,
0xacb8, 0xacd9, 0xacfa, 0xad1b, 0xad3c, 0xad5d, 0xad7e, 0xad9f,
0xadc0, 0xade1, 0xae02, 0xae23, 0xae44, 0xae65, 0xae86, 0xaea7,
0xaec8, 0xaee9, 0xaf0a, 0xaf2b, 0xaf4c, 0xaf6d, 0xaf8e, 0xafaf,
0xafd0, 0xaff1, 0xb012, 0xb033, 0xb054, 0xb075, 0xb096, 0xb0b7,
0xb0d8, 0xb0f9, 0xb11a, 0xb13b, 0xb15c, 0xb17d, 0xb19e, 0xb1bf,
0xb1e0, 0xb201, 0xb222, 0xb243, 0xb264, 0xb285, 0xb2a6, 0xb2c7,
0xb2e8, 0xb309, 0xb32a, 0xb34b, 0xb36c, 0xb38d, 0xb3ae, 0xb3cf,
// Entry 9C40 - 9C7F
0xb3f0, 0xb411, 0xb432, 0xb453, 0xb474, 0xb495, 0xb4b6, 0xb4d7,
0xb4f8, 0xb519, 0xb53a, 0xb55b, 0xb57c, 0xb59d, 0xb5be, 0xb5df,
0xb600, 0xb621, 0xb642, 0xb663, 0xb684, 0xb6a5, 0xb6c6, 0xb6e7,
0xb708, 0xb729, 0xb74a, 0xb76b, 0xb78c, 0xb7ad, 0xb7ce, 0xb7ef,
0xb810, 0xb831, 0xb852, 0xb873, 0xb894, 0xb8b5, 0xb8d6, 0xb8f7,
0xb918, 0xb939, 0xb95a, 0xb97b, 0xb99c, 0xb9bd, 0xb9de, 0xb9ff,
0xba20, 0xba41, 0xba62, 0xba83, 0xbaa4, 0xbac5, 0xbae6, 0xbb07,
0xbb28, 0xbb49, 0xbb6a, 0xbb8b, 0xbbac, 0xbbcd, 0xbbee, 0xbc0f,
// Entry 9C80 - 9CBF
0xbc30, 0xbc51, 0xbc72, 0xbc93, 0xbcb4, 0xbcd5, 0xbcf6, 0xbd17,
0xbd38, 0xbd59, 0xbd7a, 0xbd9b, 0xbdbc, 0xbddd, 0xbdfe, 0xbe1f,
0xbe40, 0xbe61, 0xbe82, 0xbea3, 0xbec4, 0xbee5, 0xbf06, 0xbf27,
0xbf48, 0xbf69, 0xbf8a, 0xbfab, 0xbfcc, 0xbfed, 0xc00e, 0xc02f,
0xc050, 0xc071, 0xc092, 0xc0b3, 0xc0d4, 0xc0f5, 0xc116, 0xc137,
0xc158, 0xc179, 0xc19a, 0xc1bb, 0xc1dc, 0xc1fd, 0xc21e, 0xc23f,
0xc260, 0xc281, 0xc2a2, 0xc2c3, 0xc2e4, 0xc305, 0xc326, 0xc347,
0xc368, 0xc389, 0xc3aa, 0xc3cb, 0xc3ec, 0xc40d, 0xc42e, 0xc44f,
// Entry 9CC0 - 9CFF
0xc470, 0xc491, 0xc4b2, 0xc4d3, 0xc4f4, 0xc515, 0xc521, 0xc52a,
0xc53e, 0xc550, 0xc55f, 0xc56e, 0xc57e, 0xc58b, 0xc599, 0xc5ad,
0xc5c2, 0xc5ce, 0xc5db, 0xc5e4, 0xc5f4, 0xc601, 0xc60c, 0xc61a,
0xc627, 0xc634, 0xc643, 0xc651, 0xc65f, 0xc66c, 0xc67b, 0xc68a,
0xc698, 0xc6a1, 0xc6ae, 0xc6c0, 0xc6cf, 0xc6e4, 0xc6f5, 0xc706,
0xc720, 0xc73a, 0xc754, 0xc76e, 0xc788, 0xc7a2, 0xc7bc, 0xc7d6,
0xc7f0, 0xc80a, 0xc824, 0xc83e, 0xc858, 0xc872, 0xc88c, 0xc8a6,
0xc8c0, 0xc8da, 0xc8f4, 0xc90e, 0xc928, 0xc942, 0xc95c, 0xc976,
// Entry 9D00 - 9D3F
0xc990, 0xc9aa, 0xc9c1, 0xc9d4, 0xc9ec, 0xca01, 0xca0d, 0xca1d,
0xca35, 0xca4d, 0xca65, 0xca7d, 0xca95, 0xcaad, 0xcac5, 0xcadd,
0xcaf5, 0xcb0d, 0xcb25, 0xcb3d, 0xcb55, 0xcb6d, 0xcb85, 0xcb9d,
0xcbb5, 0xcbcd, 0xcbe5, 0xcbfd, 0xcc15, 0xcc2d, 0xcc45, 0xcc5d,
0xcc75, 0xcc8d, 0xcca3, 0xccb4, 0xcccb, 0xccd4, 0xccde, 0xccf3,
0xcd08, 0xcd1d, 0xcd32, 0xcd47, 0xcd5c, 0xcd71, 0xcd86, 0xcd9b,
0xcdb0, 0xcdc5, 0xcdda, 0xcdef, 0xce04, 0xce19, 0xce2e, 0xce43,
0xce58, 0xce6d, 0xce82, 0xce97, 0xceac, 0xcec1, 0xced6, 0xceeb,
// Entry 9D40 - 9D7F
0xcf00, 0xcf15, 0xcf2a, 0xcf3f, 0xcf54, 0xcf69, 0xcf7e, 0xcf93,
0xcfa8, 0xcfbd, 0xcfd2, 0xcfe7, 0xcffc, 0xd011, 0xd026, 0xd03b,
0xd050, 0xd065, 0xd07a, 0xd08f, 0xd0a4, 0xd0b9, 0xd0ce, 0xd0e3,
0xd0f8, 0xd10d, 0xd122, 0xd137, 0xd14c, 0xd161, 0xd176, 0xd18b,
0xd1a0, 0xd1b5, 0xd1ca, 0xd1df, 0xd1f4, 0xd209, 0xd21e, 0xd233,
0xd248, 0xd25d, 0xd272, 0xd287, 0xd29c, 0xd2b1, 0xd2c6, 0xd2db,
0xd2f0, 0xd305, 0xd31a, 0xd32f, 0xd344, 0xd359, 0xd36e, 0xd383,
0xd398, 0xd3ad, 0xd3c3, 0xd3d9, 0xd3ef, 0xd405, 0xd41b, 0xd431,
// Entry 9D80 - 9DBF
0xd447, 0xd45d, 0xd473, 0xd489, 0xd49f, 0xd4b5, 0xd4cb, 0xd4e1,
0xd4f7, 0xd50d, 0xd523, 0xd539, 0xd54f, 0xd565, 0xd57b, 0xd591,
0xd5a7, 0xd5bd, 0xd5d3, 0xd5e9, 0xd5ff, 0xd615, 0xd62b, 0xd641,
0xd657, 0xd66d, 0xd683, 0xd699, 0xd6af, 0xd6c5, 0xd6db, 0xd6f1,
0xd707, 0xd71d, 0xd733, 0xd749, 0xd75f, 0xd775, 0xd78b, 0xd7a1,
0xd7b7, 0xd7cd, 0xd7e3, 0xd7f9, 0xd80f, 0xd825, 0xd83b, 0xd851,
0xd867, 0xd87d, 0xd893, 0xd8a9, 0xd8bf, 0xd8d5, 0xd8eb, 0xd901,
0xd917, 0xd92d, 0xd943, 0xd959, 0xd96f, 0xd985, 0xd99b, 0xd9b1,
// Entry 9DC0 - 9DFF
0xd9c7, 0xd9dd, 0xd9f3, 0xda09, 0xda1f, 0xda35, 0xda4b, 0xda61,
0xda77, 0xda8d, 0xdaa3, 0xdab9, 0xdacf, 0xdae5, 0xdafb, 0xdb11,
0xdb27, 0xdb3d, 0xdb53, 0xdb69, 0xdb7f, 0xdb95, 0xdbab, 0xdbc1,
0xdbd7, 0xdbed, 0xdc03, 0xdc19, 0xdc2f, 0xdc45, 0xdc5b, 0xdc71,
0xdc87, 0xdc9d, 0xdcb3, 0xdcc9, 0xdcdf, 0xdcf5, 0xdd0b, 0xdd21,
0xdd37, 0xdd4d, 0xdd63, 0xdd79, 0xdd8f, 0xdda5, 0xddbb, 0xddd1,
0xdde7, 0xddfd, 0xde13, 0xde29, 0xde3f, 0xde55, 0xde6b, 0xde81,
0xde97, 0xdead, 0xdec3, 0xded9, 0xdeef, 0xdf05, 0xdf1b, 0xdf31,
// Entry 9E00 - 9E3F
0xdf47, 0xdf5d, 0xdf73, 0xdf89, 0xdf9f, 0xdfb5, 0xdfcb, 0xdfe1,
0xdff7, 0xe00d, 0xe023, 0xe039, 0xe04f, 0xe065, 0xe07b, 0xe091,
0xe0a7, 0xe0bd, 0xe0d3, 0xe0e9, 0xe0ff, 0xe115, 0xe12b,
} // Size: 80966 bytes
const directData string = "" + // Size: 490 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 Extension I><CJK Ideograph Extension J><CJK Ideograph><Ha" +
"ngul Syllable><Low Surrogate><Non Private Use High Surrogate><Plane 15 P" +
"rivate Use><Plane 16 Private Use><Private Use High Surrogate><Private Us" +
"e><Tangut Ideograph Supplement><Tangut Ideograph><control>"
const singleData string = ("" + // Size: 1040683 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 LETTER NOON WITH R" +
"ING ABOVEARABIC POUND MARK ABOVEARABIC PIASTRE MARK ABOVEARABIC PEPETARA" +
"BIC SMALL HIGH WORD AL-JUZARABIC SMALL LOW WORD ISHMAAMARABIC SMALL LOW " +
"WORD IMAALAARABIC SMALL LOW WORD TASHEELARABIC MADDA WAAJIBARABIC SUPERS" +
"CRIPT ALEF MOKHASSASARABIC DOUBLED MADDAARABIC HALF MADDA OVER MADDAARAB" +
"IC LETTER BEH WITH SMALL V BELOWARABIC LETTER BEH WITH HAMZA ABOVEARABIC" +
" LETTER JEEM WITH TWO DOTS ABOVEARABIC LETTER TAH WITH TWO DOTS ABOVEARA" +
"BIC LETTER FEH WITH DOT BELOW AND THREE DOTS ABOVEARABIC LETTER QAF WITH" +
" DOT BELOWARABIC LETTER LAM WITH DOUBLE BARARABIC LETTER MEEM WITH THREE" +
" DOTS ABOVEARABIC LETTER YEH WITH TWO DOTS BELOW AND HAMZA ABOVEARABIC L" +
"ETTER YEH WITH TWO DOTS BELOW AND DOT ABOVEARABIC LETTER REH WITH LOOPAR" +
"ABIC LETTER WAW WITH DOT WITHINARABIC LETTER ROHINGYA YEHARABIC LETTER L" +
"OW ALEFARABIC LETTER DAL WITH THREE DOTS BELOWARABIC LETTER SAD WITH THR" +
"EE DOTS BELOWARABIC LETTER GAF WITH INVERTED STROKEARABIC LETTER STRAIGH" +
"T WAWARABIC LETTER ZAIN WITH INVERTED V ABOVEARABIC LETTER AIN WITH THRE" +
"E DOTS BELOWARABIC LETTER KAF WITH DOT BELOWARABIC LETTER QAF WITH DOT B" +
"ELOW AND NO DOTS ABOVEARABIC LETTER BEH WITH SMALL MEEM ABOVEARABIC LETT" +
"ER PEH WITH SMALL MEEM ABOVEARABIC LETTER TEH WITH SMALL TEH ABOVEARABIC" +
" LETTER REH WITH SMALL NOON ABOVEARABIC LETTER YEH WITH TWO DOTS BELOW A" +
"ND SMALL NOON ABOVEARABIC LETTER AFRICAN FEHARABIC LETTER AFRICAN QAFARA" +
"BIC LETTER AFRICAN NOONARABIC LETTER PEH WITH SMALL VARABIC LETTER TEH W" +
"ITH SMALL VARABIC LETTER TTEH WITH SMALL VARABIC LETTER TCHEH WITH SMALL" +
" VARABIC LETTER KEHEH WITH SMALL VARABIC LETTER GHAIN WITH THREE DOTS AB" +
"OVEARABIC LETTER AFRICAN QAF WITH THREE DOTS ABOVEARABIC LETTER JEEM WIT" +
"H THREE DOTS ABOVEARABIC LETTER JEEM WITH THREE DOTS BELOWARABIC LETTER " +
"LAM WITH SMALL ARABIC LETTER TAH ABOVEARABIC LETTER GRAFARABIC SMALL FAR") + ("" +
"SI YEHARABIC SMALL HIGH FARSI YEHARABIC SMALL HIGH YEH BARREE WITH TWO D" +
"OTS BELOWARABIC SMALL HIGH WORD SAHARABIC SMALL HIGH ZAHARABIC LARGE ROU" +
"ND DOT ABOVEARABIC LARGE ROUND DOT BELOWARABIC SUKUN BELOWARABIC LARGE C" +
"IRCLE BELOWARABIC LARGE ROUND DOT INSIDE CIRCLE BELOWARABIC SMALL LOW WA" +
"WARABIC SMALL HIGH WORD AR-RUBARABIC SMALL HIGH SADARABIC SMALL HIGH AIN" +
"ARABIC SMALL HIGH QAFARABIC SMALL HIGH NOON WITH KASRAARABIC SMALL LOW N" +
"OON WITH KASRAARABIC SMALL HIGH WORD ATH-THALATHAARABIC SMALL HIGH WORD " +
"AS-SAJDAARABIC SMALL HIGH WORD AN-NISFARABIC SMALL HIGH WORD SAKTAARABIC" +
" SMALL HIGH WORD QIFARABIC SMALL HIGH WORD WAQFAARABIC SMALL HIGH FOOTNO" +
"TE MARKERARABIC SMALL HIGH SIGN SAFHAARABIC DISPUTED END OF AYAHARABIC T" +
"URNED DAMMA BELOWARABIC CURLY FATHAARABIC CURLY DAMMAARABIC CURLY KASRAA" +
"RABIC CURLY FATHATANARABIC CURLY DAMMATANARABIC CURLY KASRATANARABIC TON" +
"E ONE DOT ABOVEARABIC TONE TWO DOTS ABOVEARABIC TONE LOOP ABOVEARABIC TO" +
"NE ONE DOT BELOWARABIC TONE TWO DOTS BELOWARABIC TONE LOOP BELOWARABIC O" +
"PEN FATHATANARABIC OPEN DAMMATANARABIC OPEN KASRATANARABIC SMALL HIGH WA" +
"WARABIC FATHA WITH RINGARABIC FATHA WITH DOT ABOVEARABIC KASRA WITH DOT " +
"BELOWARABIC LEFT ARROWHEAD ABOVEARABIC RIGHT ARROWHEAD ABOVEARABIC LEFT " +
"ARROWHEAD BELOWARABIC RIGHT ARROWHEAD BELOWARABIC DOUBLE RIGHT ARROWHEAD" +
" ABOVEARABIC DOUBLE RIGHT ARROWHEAD ABOVE WITH DOTARABIC RIGHT ARROWHEAD" +
" ABOVE WITH DOTARABIC DAMMA WITH DOTARABIC MARK SIDEWAYS NOON GHUNNADEVA" +
"NAGARI SIGN INVERTED CANDRABINDUDEVANAGARI SIGN CANDRABINDUDEVANAGARI SI" +
"GN ANUSVARADEVANAGARI SIGN VISARGADEVANAGARI LETTER SHORT ADEVANAGARI LE" +
"TTER ADEVANAGARI LETTER AADEVANAGARI LETTER IDEVANAGARI LETTER IIDEVANAG" +
"ARI LETTER UDEVANAGARI LETTER UUDEVANAGARI LETTER VOCALIC RDEVANAGARI LE" +
"TTER VOCALIC LDEVANAGARI LETTER CANDRA EDEVANAGARI LETTER SHORT EDEVANAG" +
"ARI LETTER EDEVANAGARI LETTER AIDEVANAGARI LETTER CANDRA ODEVANAGARI LET" +
"TER SHORT ODEVANAGARI LETTER ODEVANAGARI LETTER AUDEVANAGARI LETTER KADE" +
"VANAGARI LETTER KHADEVANAGARI LETTER GADEVANAGARI LETTER GHADEVANAGARI L" +
"ETTER NGADEVANAGARI LETTER CADEVANAGARI LETTER CHADEVANAGARI LETTER JADE" +
"VANAGARI LETTER JHADEVANAGARI LETTER NYADEVANAGARI LETTER TTADEVANAGARI " +
"LETTER TTHADEVANAGARI LETTER DDADEVANAGARI LETTER DDHADEVANAGARI LETTER " +
"NNADEVANAGARI LETTER TADEVANAGARI LETTER THADEVANAGARI LETTER DADEVANAGA" +
"RI LETTER DHADEVANAGARI LETTER NADEVANAGARI LETTER NNNADEVANAGARI LETTER" +
" PADEVANAGARI LETTER PHADEVANAGARI LETTER BADEVANAGARI LETTER BHADEVANAG" +
"ARI LETTER MADEVANAGARI LETTER YADEVANAGARI LETTER RADEVANAGARI LETTER R" +
"RADEVANAGARI LETTER LADEVANAGARI LETTER LLADEVANAGARI LETTER LLLADEVANAG" +
"ARI LETTER VADEVANAGARI LETTER SHADEVANAGARI LETTER SSADEVANAGARI LETTER" +
" SADEVANAGARI LETTER HADEVANAGARI VOWEL SIGN OEDEVANAGARI VOWEL SIGN OOE" +
"DEVANAGARI SIGN NUKTADEVANAGARI SIGN AVAGRAHADEVANAGARI VOWEL SIGN AADEV" +
"ANAGARI VOWEL SIGN IDEVANAGARI VOWEL SIGN IIDEVANAGARI VOWEL SIGN UDEVAN" +
"AGARI VOWEL SIGN UUDEVANAGARI VOWEL SIGN VOCALIC RDEVANAGARI VOWEL SIGN " +
"VOCALIC RRDEVANAGARI VOWEL SIGN CANDRA EDEVANAGARI VOWEL SIGN SHORT EDEV" +
"ANAGARI VOWEL SIGN EDEVANAGARI VOWEL SIGN AIDEVANAGARI VOWEL SIGN CANDRA" +
" ODEVANAGARI VOWEL SIGN SHORT ODEVANAGARI VOWEL SIGN ODEVANAGARI VOWEL S" +
"IGN AUDEVANAGARI SIGN VIRAMADEVANAGARI VOWEL SIGN PRISHTHAMATRA EDEVANAG" +
"ARI VOWEL SIGN AWDEVANAGARI OMDEVANAGARI STRESS SIGN UDATTADEVANAGARI ST" +
"RESS SIGN ANUDATTADEVANAGARI GRAVE ACCENTDEVANAGARI ACUTE ACCENTDEVANAGA" +
"RI VOWEL SIGN CANDRA LONG EDEVANAGARI VOWEL SIGN UEDEVANAGARI VOWEL SIGN" +
" UUEDEVANAGARI LETTER QADEVANAGARI LETTER KHHADEVANAGARI LETTER GHHADEVA" +
"NAGARI LETTER ZADEVANAGARI LETTER DDDHADEVANAGARI LETTER RHADEVANAGARI L" +
"ETTER FADEVANAGARI LETTER YYADEVANAGARI LETTER VOCALIC RRDEVANAGARI LETT" +
"ER VOCALIC LLDEVANAGARI VOWEL SIGN VOCALIC LDEVANAGARI VOWEL SIGN VOCALI" +
"C LLDEVANAGARI DANDADEVANAGARI DOUBLE DANDADEVANAGARI DIGIT ZERODEVANAGA" +
"RI DIGIT ONEDEVANAGARI DIGIT TWODEVANAGARI DIGIT THREEDEVANAGARI DIGIT F" +
"OURDEVANAGARI DIGIT FIVEDEVANAGARI DIGIT SIXDEVANAGARI DIGIT SEVENDEVANA" +
"GARI DIGIT EIGHTDEVANAGARI DIGIT NINEDEVANAGARI ABBREVIATION SIGNDEVANAG" +
"ARI SIGN HIGH SPACING DOTDEVANAGARI LETTER CANDRA ADEVANAGARI LETTER OED" +
"EVANAGARI LETTER OOEDEVANAGARI LETTER AWDEVANAGARI LETTER UEDEVANAGARI L" +
"ETTER UUEDEVANAGARI LETTER MARWARI DDADEVANAGARI LETTER ZHADEVANAGARI LE" +
"TTER HEAVY YADEVANAGARI LETTER GGADEVANAGARI LETTER JJADEVANAGARI LETTER" +
" GLOTTAL STOPDEVANAGARI LETTER DDDADEVANAGARI LETTER BBABENGALI ANJIBENG" +
"ALI SIGN CANDRABINDUBENGALI SIGN ANUSVARABENGALI SIGN VISARGABENGALI LET" +
"TER ABENGALI LETTER AABENGALI LETTER IBENGALI LETTER IIBENGALI LETTER UB" +
"ENGALI LETTER UUBENGALI LETTER VOCALIC RBENGALI LETTER VOCALIC LBENGALI ") + ("" +
"LETTER EBENGALI LETTER AIBENGALI LETTER OBENGALI LETTER AUBENGALI LETTER" +
" KABENGALI LETTER KHABENGALI LETTER GABENGALI LETTER GHABENGALI LETTER N" +
"GABENGALI LETTER CABENGALI LETTER CHABENGALI LETTER JABENGALI LETTER JHA" +
"BENGALI LETTER NYABENGALI LETTER TTABENGALI LETTER TTHABENGALI LETTER DD" +
"ABENGALI LETTER DDHABENGALI LETTER NNABENGALI LETTER TABENGALI LETTER TH" +
"ABENGALI LETTER DABENGALI LETTER DHABENGALI LETTER NABENGALI LETTER PABE" +
"NGALI LETTER PHABENGALI LETTER BABENGALI LETTER BHABENGALI LETTER MABENG" +
"ALI LETTER YABENGALI LETTER RABENGALI LETTER LABENGALI LETTER SHABENGALI" +
" LETTER SSABENGALI LETTER SABENGALI LETTER HABENGALI SIGN NUKTABENGALI S" +
"IGN AVAGRAHABENGALI VOWEL SIGN AABENGALI VOWEL SIGN IBENGALI VOWEL SIGN " +
"IIBENGALI VOWEL SIGN UBENGALI VOWEL SIGN UUBENGALI VOWEL SIGN VOCALIC RB" +
"ENGALI VOWEL SIGN VOCALIC RRBENGALI VOWEL SIGN EBENGALI VOWEL SIGN AIBEN" +
"GALI VOWEL SIGN OBENGALI VOWEL SIGN AUBENGALI SIGN VIRAMABENGALI LETTER " +
"KHANDA TABENGALI AU LENGTH MARKBENGALI LETTER RRABENGALI LETTER RHABENGA" +
"LI LETTER YYABENGALI LETTER VOCALIC RRBENGALI LETTER VOCALIC LLBENGALI V" +
"OWEL SIGN VOCALIC LBENGALI VOWEL SIGN VOCALIC LLBENGALI DIGIT ZEROBENGAL" +
"I DIGIT ONEBENGALI DIGIT TWOBENGALI DIGIT THREEBENGALI DIGIT FOURBENGALI" +
" DIGIT FIVEBENGALI DIGIT SIXBENGALI DIGIT SEVENBENGALI DIGIT EIGHTBENGAL" +
"I DIGIT NINEBENGALI LETTER RA WITH MIDDLE DIAGONALBENGALI LETTER RA WITH" +
" LOWER DIAGONALBENGALI RUPEE MARKBENGALI RUPEE SIGNBENGALI CURRENCY NUME" +
"RATOR ONEBENGALI CURRENCY NUMERATOR TWOBENGALI CURRENCY NUMERATOR THREEB" +
"ENGALI CURRENCY NUMERATOR FOURBENGALI CURRENCY NUMERATOR ONE LESS THAN T" +
"HE DENOMINATORBENGALI CURRENCY DENOMINATOR SIXTEENBENGALI ISSHARBENGALI " +
"GANDA MARKBENGALI LETTER VEDIC ANUSVARABENGALI ABBREVIATION SIGNBENGALI " +
"SANDHI MARKGURMUKHI SIGN ADAK BINDIGURMUKHI SIGN BINDIGURMUKHI SIGN VISA" +
"RGAGURMUKHI LETTER AGURMUKHI LETTER AAGURMUKHI LETTER IGURMUKHI LETTER I" +
"IGURMUKHI LETTER UGURMUKHI LETTER UUGURMUKHI LETTER EEGURMUKHI LETTER AI" +
"GURMUKHI LETTER OOGURMUKHI LETTER AUGURMUKHI LETTER KAGURMUKHI LETTER KH" +
"AGURMUKHI LETTER GAGURMUKHI LETTER GHAGURMUKHI LETTER NGAGURMUKHI LETTER" +
" CAGURMUKHI LETTER CHAGURMUKHI LETTER JAGURMUKHI LETTER JHAGURMUKHI LETT" +
"ER NYAGURMUKHI LETTER TTAGURMUKHI LETTER TTHAGURMUKHI LETTER DDAGURMUKHI" +
" LETTER DDHAGURMUKHI LETTER NNAGURMUKHI LETTER TAGURMUKHI LETTER THAGURM" +
"UKHI LETTER DAGURMUKHI LETTER DHAGURMUKHI LETTER NAGURMUKHI LETTER PAGUR" +
"MUKHI LETTER PHAGURMUKHI LETTER BAGURMUKHI LETTER BHAGURMUKHI LETTER MAG" +
"URMUKHI LETTER YAGURMUKHI LETTER RAGURMUKHI LETTER LAGURMUKHI LETTER LLA" +
"GURMUKHI LETTER VAGURMUKHI LETTER SHAGURMUKHI LETTER SAGURMUKHI LETTER H" +
"AGURMUKHI SIGN NUKTAGURMUKHI VOWEL SIGN AAGURMUKHI VOWEL SIGN IGURMUKHI " +
"VOWEL SIGN IIGURMUKHI VOWEL SIGN UGURMUKHI VOWEL SIGN UUGURMUKHI VOWEL S" +
"IGN EEGURMUKHI VOWEL SIGN AIGURMUKHI VOWEL SIGN OOGURMUKHI VOWEL SIGN AU" +
"GURMUKHI SIGN VIRAMAGURMUKHI SIGN UDAATGURMUKHI LETTER KHHAGURMUKHI LETT" +
"ER GHHAGURMUKHI LETTER ZAGURMUKHI LETTER RRAGURMUKHI LETTER FAGURMUKHI D" +
"IGIT ZEROGURMUKHI DIGIT ONEGURMUKHI DIGIT TWOGURMUKHI DIGIT THREEGURMUKH" +
"I DIGIT FOURGURMUKHI DIGIT FIVEGURMUKHI DIGIT SIXGURMUKHI DIGIT SEVENGUR" +
"MUKHI DIGIT EIGHTGURMUKHI DIGIT NINEGURMUKHI TIPPIGURMUKHI ADDAKGURMUKHI" +
" IRIGURMUKHI URAGURMUKHI EK ONKARGURMUKHI SIGN YAKASHGURMUKHI ABBREVIATI" +
"ON SIGNGUJARATI SIGN CANDRABINDUGUJARATI SIGN ANUSVARAGUJARATI SIGN VISA" +
"RGAGUJARATI LETTER AGUJARATI LETTER AAGUJARATI LETTER IGUJARATI LETTER I" +
"IGUJARATI LETTER UGUJARATI LETTER UUGUJARATI LETTER VOCALIC RGUJARATI LE" +
"TTER VOCALIC LGUJARATI VOWEL CANDRA EGUJARATI LETTER EGUJARATI LETTER AI" +
"GUJARATI VOWEL CANDRA OGUJARATI LETTER OGUJARATI LETTER AUGUJARATI LETTE" +
"R KAGUJARATI LETTER KHAGUJARATI LETTER GAGUJARATI LETTER GHAGUJARATI LET" +
"TER NGAGUJARATI LETTER CAGUJARATI LETTER CHAGUJARATI LETTER JAGUJARATI L" +
"ETTER JHAGUJARATI LETTER NYAGUJARATI LETTER TTAGUJARATI LETTER TTHAGUJAR" +
"ATI LETTER DDAGUJARATI LETTER DDHAGUJARATI LETTER NNAGUJARATI LETTER TAG" +
"UJARATI LETTER THAGUJARATI LETTER DAGUJARATI LETTER DHAGUJARATI LETTER N" +
"AGUJARATI LETTER PAGUJARATI LETTER PHAGUJARATI LETTER BAGUJARATI LETTER " +
"BHAGUJARATI LETTER MAGUJARATI LETTER YAGUJARATI LETTER RAGUJARATI LETTER" +
" LAGUJARATI LETTER LLAGUJARATI LETTER VAGUJARATI LETTER SHAGUJARATI LETT" +
"ER SSAGUJARATI LETTER SAGUJARATI LETTER HAGUJARATI SIGN NUKTAGUJARATI SI" +
"GN AVAGRAHAGUJARATI VOWEL SIGN AAGUJARATI VOWEL SIGN IGUJARATI VOWEL SIG" +
"N IIGUJARATI VOWEL SIGN UGUJARATI VOWEL SIGN UUGUJARATI VOWEL SIGN VOCAL" +
"IC RGUJARATI VOWEL SIGN VOCALIC RRGUJARATI VOWEL SIGN CANDRA EGUJARATI V" +
"OWEL SIGN EGUJARATI VOWEL SIGN AIGUJARATI VOWEL SIGN CANDRA OGUJARATI VO" +
"WEL SIGN OGUJARATI VOWEL SIGN AUGUJARATI SIGN VIRAMAGUJARATI OMGUJARATI ") + ("" +
"LETTER VOCALIC RRGUJARATI LETTER VOCALIC LLGUJARATI VOWEL SIGN VOCALIC L" +
"GUJARATI VOWEL SIGN VOCALIC LLGUJARATI DIGIT ZEROGUJARATI DIGIT ONEGUJAR" +
"ATI DIGIT TWOGUJARATI DIGIT THREEGUJARATI DIGIT FOURGUJARATI DIGIT FIVEG" +
"UJARATI DIGIT SIXGUJARATI DIGIT SEVENGUJARATI DIGIT EIGHTGUJARATI DIGIT " +
"NINEGUJARATI ABBREVIATION SIGNGUJARATI RUPEE SIGNGUJARATI LETTER ZHAGUJA" +
"RATI SIGN SUKUNGUJARATI SIGN SHADDAGUJARATI SIGN MADDAHGUJARATI SIGN THR" +
"EE-DOT NUKTA ABOVEGUJARATI SIGN CIRCLE NUKTA ABOVEGUJARATI SIGN TWO-CIRC" +
"LE NUKTA ABOVEORIYA SIGN CANDRABINDUORIYA SIGN ANUSVARAORIYA SIGN VISARG" +
"AORIYA LETTER AORIYA LETTER AAORIYA LETTER IORIYA LETTER IIORIYA LETTER " +
"UORIYA LETTER UUORIYA LETTER VOCALIC RORIYA LETTER VOCALIC LORIYA LETTER" +
" EORIYA LETTER AIORIYA LETTER OORIYA LETTER AUORIYA LETTER KAORIYA LETTE" +
"R KHAORIYA LETTER GAORIYA LETTER GHAORIYA LETTER NGAORIYA LETTER CAORIYA" +
" LETTER CHAORIYA LETTER JAORIYA LETTER JHAORIYA LETTER NYAORIYA LETTER T" +
"TAORIYA LETTER TTHAORIYA LETTER DDAORIYA LETTER DDHAORIYA LETTER NNAORIY" +
"A LETTER TAORIYA LETTER THAORIYA LETTER DAORIYA LETTER DHAORIYA LETTER N" +
"AORIYA LETTER PAORIYA LETTER PHAORIYA LETTER BAORIYA LETTER BHAORIYA LET" +
"TER MAORIYA LETTER YAORIYA LETTER RAORIYA LETTER LAORIYA LETTER LLAORIYA" +
" LETTER VAORIYA LETTER SHAORIYA LETTER SSAORIYA LETTER SAORIYA LETTER HA" +
"ORIYA SIGN NUKTAORIYA SIGN AVAGRAHAORIYA VOWEL SIGN AAORIYA VOWEL SIGN I" +
"ORIYA VOWEL SIGN IIORIYA VOWEL SIGN UORIYA VOWEL SIGN UUORIYA VOWEL SIGN" +
" VOCALIC RORIYA VOWEL SIGN VOCALIC RRORIYA VOWEL SIGN EORIYA VOWEL SIGN " +
"AIORIYA VOWEL SIGN OORIYA VOWEL SIGN AUORIYA SIGN VIRAMAORIYA SIGN OVERL" +
"INEORIYA AI LENGTH MARKORIYA AU LENGTH MARKORIYA LETTER RRAORIYA LETTER " +
"RHAORIYA LETTER YYAORIYA LETTER VOCALIC RRORIYA LETTER VOCALIC LLORIYA V" +
"OWEL SIGN VOCALIC LORIYA VOWEL SIGN VOCALIC LLORIYA DIGIT ZEROORIYA DIGI" +
"T ONEORIYA DIGIT TWOORIYA DIGIT THREEORIYA DIGIT FOURORIYA DIGIT FIVEORI" +
"YA DIGIT SIXORIYA DIGIT SEVENORIYA DIGIT EIGHTORIYA DIGIT NINEORIYA ISSH" +
"ARORIYA LETTER WAORIYA FRACTION ONE QUARTERORIYA FRACTION ONE HALFORIYA " +
"FRACTION THREE QUARTERSORIYA FRACTION ONE SIXTEENTHORIYA FRACTION ONE EI" +
"GHTHORIYA FRACTION THREE SIXTEENTHSTAMIL SIGN ANUSVARATAMIL SIGN VISARGA" +
"TAMIL LETTER ATAMIL LETTER AATAMIL LETTER ITAMIL LETTER IITAMIL LETTER U" +
"TAMIL LETTER UUTAMIL LETTER ETAMIL LETTER EETAMIL LETTER AITAMIL LETTER " +
"OTAMIL LETTER OOTAMIL LETTER AUTAMIL LETTER KATAMIL LETTER NGATAMIL LETT" +
"ER CATAMIL LETTER JATAMIL LETTER NYATAMIL LETTER TTATAMIL LETTER NNATAMI" +
"L LETTER TATAMIL LETTER NATAMIL LETTER NNNATAMIL LETTER PATAMIL LETTER M" +
"ATAMIL LETTER YATAMIL LETTER RATAMIL LETTER RRATAMIL LETTER LATAMIL LETT" +
"ER LLATAMIL LETTER LLLATAMIL LETTER VATAMIL LETTER SHATAMIL LETTER SSATA" +
"MIL LETTER SATAMIL LETTER HATAMIL VOWEL SIGN AATAMIL VOWEL SIGN ITAMIL V" +
"OWEL SIGN IITAMIL VOWEL SIGN UTAMIL VOWEL SIGN UUTAMIL VOWEL SIGN ETAMIL" +
" VOWEL SIGN EETAMIL VOWEL SIGN AITAMIL VOWEL SIGN OTAMIL VOWEL SIGN OOTA" +
"MIL VOWEL SIGN AUTAMIL SIGN VIRAMATAMIL OMTAMIL AU LENGTH MARKTAMIL DIGI" +
"T ZEROTAMIL DIGIT ONETAMIL DIGIT TWOTAMIL DIGIT THREETAMIL DIGIT FOURTAM" +
"IL DIGIT FIVETAMIL DIGIT SIXTAMIL DIGIT SEVENTAMIL DIGIT EIGHTTAMIL DIGI" +
"T NINETAMIL NUMBER TENTAMIL NUMBER ONE HUNDREDTAMIL NUMBER ONE THOUSANDT" +
"AMIL DAY SIGNTAMIL MONTH SIGNTAMIL YEAR SIGNTAMIL DEBIT SIGNTAMIL CREDIT" +
" SIGNTAMIL AS ABOVE SIGNTAMIL RUPEE SIGNTAMIL NUMBER SIGNTELUGU SIGN COM" +
"BINING CANDRABINDU ABOVETELUGU SIGN CANDRABINDUTELUGU SIGN ANUSVARATELUG" +
"U SIGN VISARGATELUGU SIGN COMBINING ANUSVARA ABOVETELUGU LETTER ATELUGU " +
"LETTER AATELUGU LETTER ITELUGU LETTER IITELUGU LETTER UTELUGU LETTER UUT" +
"ELUGU LETTER VOCALIC RTELUGU LETTER VOCALIC LTELUGU LETTER ETELUGU LETTE" +
"R EETELUGU LETTER AITELUGU LETTER OTELUGU LETTER OOTELUGU LETTER AUTELUG" +
"U LETTER KATELUGU LETTER KHATELUGU LETTER GATELUGU LETTER GHATELUGU LETT" +
"ER NGATELUGU LETTER CATELUGU LETTER CHATELUGU LETTER JATELUGU LETTER JHA" +
"TELUGU LETTER NYATELUGU LETTER TTATELUGU LETTER TTHATELUGU LETTER DDATEL" +
"UGU LETTER DDHATELUGU LETTER NNATELUGU LETTER TATELUGU LETTER THATELUGU " +
"LETTER DATELUGU LETTER DHATELUGU LETTER NATELUGU LETTER PATELUGU LETTER " +
"PHATELUGU LETTER BATELUGU LETTER BHATELUGU LETTER MATELUGU LETTER YATELU" +
"GU LETTER RATELUGU LETTER RRATELUGU LETTER LATELUGU LETTER LLATELUGU LET" +
"TER LLLATELUGU LETTER VATELUGU LETTER SHATELUGU LETTER SSATELUGU LETTER " +
"SATELUGU LETTER HATELUGU SIGN NUKTATELUGU SIGN AVAGRAHATELUGU VOWEL SIGN" +
" AATELUGU VOWEL SIGN ITELUGU VOWEL SIGN IITELUGU VOWEL SIGN UTELUGU VOWE" +
"L SIGN UUTELUGU VOWEL SIGN VOCALIC RTELUGU VOWEL SIGN VOCALIC RRTELUGU V" +
"OWEL SIGN ETELUGU VOWEL SIGN EETELUGU VOWEL SIGN AITELUGU VOWEL SIGN OTE" +
"LUGU VOWEL SIGN OOTELUGU VOWEL SIGN AUTELUGU SIGN VIRAMATELUGU LENGTH MA") + ("" +
"RKTELUGU AI LENGTH MARKTELUGU LETTER TSATELUGU LETTER DZATELUGU LETTER R" +
"RRATELUGU ARCHAIC SHRIITELUGU LETTER NAKAARA POLLUTELUGU LETTER VOCALIC " +
"RRTELUGU LETTER VOCALIC LLTELUGU VOWEL SIGN VOCALIC LTELUGU VOWEL SIGN V" +
"OCALIC LLTELUGU DIGIT ZEROTELUGU DIGIT ONETELUGU DIGIT TWOTELUGU DIGIT T" +
"HREETELUGU DIGIT FOURTELUGU DIGIT FIVETELUGU DIGIT SIXTELUGU DIGIT SEVEN" +
"TELUGU DIGIT EIGHTTELUGU DIGIT NINETELUGU SIGN SIDDHAMTELUGU FRACTION DI" +
"GIT ZERO FOR ODD POWERS OF FOURTELUGU FRACTION DIGIT ONE FOR ODD POWERS " +
"OF FOURTELUGU FRACTION DIGIT TWO FOR ODD POWERS OF FOURTELUGU FRACTION D" +
"IGIT THREE FOR ODD POWERS OF FOURTELUGU FRACTION DIGIT ONE FOR EVEN POWE" +
"RS OF FOURTELUGU FRACTION DIGIT TWO FOR EVEN POWERS OF FOURTELUGU FRACTI" +
"ON DIGIT THREE FOR EVEN POWERS OF FOURTELUGU SIGN TUUMUKANNADA SIGN SPAC" +
"ING CANDRABINDUKANNADA SIGN CANDRABINDUKANNADA SIGN ANUSVARAKANNADA SIGN" +
" VISARGAKANNADA SIGN SIDDHAMKANNADA LETTER AKANNADA LETTER AAKANNADA LET" +
"TER IKANNADA LETTER IIKANNADA LETTER UKANNADA LETTER UUKANNADA LETTER VO" +
"CALIC RKANNADA LETTER VOCALIC LKANNADA LETTER EKANNADA LETTER EEKANNADA " +
"LETTER AIKANNADA LETTER OKANNADA LETTER OOKANNADA LETTER AUKANNADA LETTE" +
"R KAKANNADA LETTER KHAKANNADA LETTER GAKANNADA LETTER GHAKANNADA LETTER " +
"NGAKANNADA LETTER CAKANNADA LETTER CHAKANNADA LETTER JAKANNADA LETTER JH" +
"AKANNADA LETTER NYAKANNADA LETTER TTAKANNADA LETTER TTHAKANNADA LETTER D" +
"DAKANNADA LETTER DDHAKANNADA LETTER NNAKANNADA LETTER TAKANNADA LETTER T" +
"HAKANNADA LETTER DAKANNADA LETTER DHAKANNADA LETTER NAKANNADA LETTER PAK" +
"ANNADA LETTER PHAKANNADA LETTER BAKANNADA LETTER BHAKANNADA LETTER MAKAN" +
"NADA LETTER YAKANNADA LETTER RAKANNADA LETTER RRAKANNADA LETTER LAKANNAD" +
"A LETTER LLAKANNADA LETTER VAKANNADA LETTER SHAKANNADA LETTER SSAKANNADA" +
" LETTER SAKANNADA LETTER HAKANNADA SIGN NUKTAKANNADA SIGN AVAGRAHAKANNAD" +
"A VOWEL SIGN AAKANNADA VOWEL SIGN IKANNADA VOWEL SIGN IIKANNADA VOWEL SI" +
"GN UKANNADA VOWEL SIGN UUKANNADA VOWEL SIGN VOCALIC RKANNADA VOWEL SIGN " +
"VOCALIC RRKANNADA VOWEL SIGN EKANNADA VOWEL SIGN EEKANNADA VOWEL SIGN AI" +
"KANNADA VOWEL SIGN OKANNADA VOWEL SIGN OOKANNADA VOWEL SIGN AUKANNADA SI" +
"GN VIRAMAKANNADA LENGTH MARKKANNADA AI LENGTH MARKKANNADA ARCHAIC SHRIIK" +
"ANNADA LETTER NAKAARA POLLUKANNADA LETTER FAKANNADA LETTER VOCALIC RRKAN" +
"NADA LETTER VOCALIC LLKANNADA VOWEL SIGN VOCALIC LKANNADA VOWEL SIGN VOC" +
"ALIC LLKANNADA DIGIT ZEROKANNADA DIGIT ONEKANNADA DIGIT TWOKANNADA DIGIT" +
" THREEKANNADA DIGIT FOURKANNADA DIGIT FIVEKANNADA DIGIT SIXKANNADA DIGIT" +
" SEVENKANNADA DIGIT EIGHTKANNADA DIGIT NINEKANNADA SIGN JIHVAMULIYAKANNA" +
"DA SIGN UPADHMANIYAKANNADA SIGN COMBINING ANUSVARA ABOVE RIGHTMALAYALAM " +
"SIGN COMBINING ANUSVARA ABOVEMALAYALAM SIGN CANDRABINDUMALAYALAM SIGN AN" +
"USVARAMALAYALAM SIGN VISARGAMALAYALAM LETTER VEDIC ANUSVARAMALAYALAM LET" +
"TER AMALAYALAM LETTER AAMALAYALAM LETTER IMALAYALAM LETTER IIMALAYALAM L" +
"ETTER UMALAYALAM LETTER UUMALAYALAM LETTER VOCALIC RMALAYALAM LETTER VOC" +
"ALIC LMALAYALAM LETTER EMALAYALAM LETTER EEMALAYALAM LETTER AIMALAYALAM " +
"LETTER OMALAYALAM LETTER OOMALAYALAM LETTER AUMALAYALAM LETTER KAMALAYAL" +
"AM LETTER KHAMALAYALAM LETTER GAMALAYALAM LETTER GHAMALAYALAM LETTER NGA" +
"MALAYALAM LETTER CAMALAYALAM LETTER CHAMALAYALAM LETTER JAMALAYALAM LETT" +
"ER JHAMALAYALAM LETTER NYAMALAYALAM LETTER TTAMALAYALAM LETTER TTHAMALAY" +
"ALAM LETTER DDAMALAYALAM LETTER DDHAMALAYALAM LETTER NNAMALAYALAM LETTER" +
" TAMALAYALAM LETTER THAMALAYALAM LETTER DAMALAYALAM LETTER DHAMALAYALAM " +
"LETTER NAMALAYALAM LETTER NNNAMALAYALAM LETTER PAMALAYALAM LETTER PHAMAL" +
"AYALAM LETTER BAMALAYALAM LETTER BHAMALAYALAM LETTER MAMALAYALAM LETTER " +
"YAMALAYALAM LETTER RAMALAYALAM LETTER RRAMALAYALAM LETTER LAMALAYALAM LE" +
"TTER LLAMALAYALAM LETTER LLLAMALAYALAM LETTER VAMALAYALAM LETTER SHAMALA" +
"YALAM LETTER SSAMALAYALAM LETTER SAMALAYALAM LETTER HAMALAYALAM LETTER T" +
"TTAMALAYALAM SIGN VERTICAL BAR VIRAMAMALAYALAM SIGN CIRCULAR VIRAMAMALAY" +
"ALAM SIGN AVAGRAHAMALAYALAM VOWEL SIGN AAMALAYALAM VOWEL SIGN IMALAYALAM" +
" VOWEL SIGN IIMALAYALAM VOWEL SIGN UMALAYALAM VOWEL SIGN UUMALAYALAM VOW" +
"EL SIGN VOCALIC RMALAYALAM VOWEL SIGN VOCALIC RRMALAYALAM VOWEL SIGN EMA" +
"LAYALAM VOWEL SIGN EEMALAYALAM VOWEL SIGN AIMALAYALAM VOWEL SIGN OMALAYA" +
"LAM VOWEL SIGN OOMALAYALAM VOWEL SIGN AUMALAYALAM SIGN VIRAMAMALAYALAM L" +
"ETTER DOT REPHMALAYALAM SIGN PARAMALAYALAM LETTER CHILLU MMALAYALAM LETT" +
"ER CHILLU YMALAYALAM LETTER CHILLU LLLMALAYALAM AU LENGTH MARKMALAYALAM " +
"FRACTION ONE ONE-HUNDRED-AND-SIXTIETHMALAYALAM FRACTION ONE FORTIETHMALA" +
"YALAM FRACTION THREE EIGHTIETHSMALAYALAM FRACTION ONE TWENTIETHMALAYALAM" +
" FRACTION ONE TENTHMALAYALAM FRACTION THREE TWENTIETHSMALAYALAM FRACTION" +
" ONE FIFTHMALAYALAM LETTER ARCHAIC IIMALAYALAM LETTER VOCALIC RRMALAYALA") + ("" +
"M LETTER VOCALIC LLMALAYALAM VOWEL SIGN VOCALIC LMALAYALAM VOWEL SIGN VO" +
"CALIC LLMALAYALAM DIGIT ZEROMALAYALAM DIGIT ONEMALAYALAM DIGIT TWOMALAYA" +
"LAM DIGIT THREEMALAYALAM DIGIT FOURMALAYALAM DIGIT FIVEMALAYALAM DIGIT S" +
"IXMALAYALAM DIGIT SEVENMALAYALAM DIGIT EIGHTMALAYALAM DIGIT NINEMALAYALA" +
"M NUMBER TENMALAYALAM NUMBER ONE HUNDREDMALAYALAM NUMBER ONE THOUSANDMAL" +
"AYALAM FRACTION ONE QUARTERMALAYALAM FRACTION ONE HALFMALAYALAM FRACTION" +
" THREE QUARTERSMALAYALAM FRACTION ONE SIXTEENTHMALAYALAM FRACTION ONE EI" +
"GHTHMALAYALAM FRACTION THREE SIXTEENTHSMALAYALAM DATE MARKMALAYALAM LETT" +
"ER CHILLU NNMALAYALAM LETTER CHILLU NMALAYALAM LETTER CHILLU RRMALAYALAM" +
" LETTER CHILLU LMALAYALAM LETTER CHILLU LLMALAYALAM LETTER CHILLU KSINHA" +
"LA SIGN CANDRABINDUSINHALA SIGN ANUSVARAYASINHALA SIGN VISARGAYASINHALA " +
"LETTER AYANNASINHALA LETTER AAYANNASINHALA LETTER AEYANNASINHALA LETTER " +
"AEEYANNASINHALA LETTER IYANNASINHALA LETTER IIYANNASINHALA LETTER UYANNA" +
"SINHALA LETTER UUYANNASINHALA LETTER IRUYANNASINHALA LETTER IRUUYANNASIN" +
"HALA LETTER ILUYANNASINHALA LETTER ILUUYANNASINHALA LETTER EYANNASINHALA" +
" LETTER EEYANNASINHALA LETTER AIYANNASINHALA LETTER OYANNASINHALA LETTER" +
" OOYANNASINHALA LETTER AUYANNASINHALA LETTER ALPAPRAANA KAYANNASINHALA L" +
"ETTER MAHAAPRAANA KAYANNASINHALA LETTER ALPAPRAANA GAYANNASINHALA LETTER" +
" MAHAAPRAANA GAYANNASINHALA LETTER KANTAJA NAASIKYAYASINHALA LETTER SANY" +
"AKA GAYANNASINHALA LETTER ALPAPRAANA CAYANNASINHALA LETTER MAHAAPRAANA C" +
"AYANNASINHALA LETTER ALPAPRAANA JAYANNASINHALA LETTER MAHAAPRAANA JAYANN" +
"ASINHALA LETTER TAALUJA NAASIKYAYASINHALA LETTER TAALUJA SANYOOGA NAAKSI" +
"KYAYASINHALA LETTER SANYAKA JAYANNASINHALA LETTER ALPAPRAANA TTAYANNASIN" +
"HALA LETTER MAHAAPRAANA TTAYANNASINHALA LETTER ALPAPRAANA DDAYANNASINHAL" +
"A LETTER MAHAAPRAANA DDAYANNASINHALA LETTER MUURDHAJA NAYANNASINHALA LET" +
"TER SANYAKA DDAYANNASINHALA LETTER ALPAPRAANA TAYANNASINHALA LETTER MAHA" +
"APRAANA TAYANNASINHALA LETTER ALPAPRAANA DAYANNASINHALA LETTER MAHAAPRAA" +
"NA DAYANNASINHALA LETTER DANTAJA NAYANNASINHALA LETTER SANYAKA DAYANNASI" +
"NHALA LETTER ALPAPRAANA PAYANNASINHALA LETTER MAHAAPRAANA PAYANNASINHALA" +
" LETTER ALPAPRAANA BAYANNASINHALA LETTER MAHAAPRAANA BAYANNASINHALA LETT" +
"ER MAYANNASINHALA LETTER AMBA BAYANNASINHALA LETTER YAYANNASINHALA LETTE" +
"R RAYANNASINHALA LETTER DANTAJA LAYANNASINHALA LETTER VAYANNASINHALA LET" +
"TER TAALUJA SAYANNASINHALA LETTER MUURDHAJA SAYANNASINHALA LETTER DANTAJ" +
"A SAYANNASINHALA LETTER HAYANNASINHALA LETTER MUURDHAJA LAYANNASINHALA L" +
"ETTER FAYANNASINHALA SIGN AL-LAKUNASINHALA VOWEL SIGN AELA-PILLASINHALA " +
"VOWEL SIGN KETTI AEDA-PILLASINHALA VOWEL SIGN DIGA AEDA-PILLASINHALA VOW" +
"EL SIGN KETTI IS-PILLASINHALA VOWEL SIGN DIGA IS-PILLASINHALA VOWEL SIGN" +
" KETTI PAA-PILLASINHALA VOWEL SIGN DIGA PAA-PILLASINHALA VOWEL SIGN GAET" +
"TA-PILLASINHALA VOWEL SIGN KOMBUVASINHALA VOWEL SIGN DIGA KOMBUVASINHALA" +
" VOWEL SIGN KOMBU DEKASINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLASINHALA V" +
"OWEL SIGN KOMBUVA HAA DIGA AELA-PILLASINHALA VOWEL SIGN KOMBUVA HAA GAYA" +
"NUKITTASINHALA VOWEL SIGN GAYANUKITTASINHALA LITH DIGIT ZEROSINHALA LITH" +
" DIGIT ONESINHALA LITH DIGIT TWOSINHALA LITH DIGIT THREESINHALA LITH DIG" +
"IT FOURSINHALA LITH DIGIT FIVESINHALA LITH DIGIT SIXSINHALA LITH DIGIT S" +
"EVENSINHALA LITH DIGIT EIGHTSINHALA LITH DIGIT NINESINHALA VOWEL SIGN DI" +
"GA GAETTA-PILLASINHALA VOWEL SIGN DIGA GAYANUKITTASINHALA PUNCTUATION KU" +
"NDDALIYATHAI CHARACTER KO KAITHAI CHARACTER KHO KHAITHAI CHARACTER KHO K" +
"HUATTHAI CHARACTER KHO KHWAITHAI CHARACTER KHO KHONTHAI CHARACTER KHO RA" +
"KHANGTHAI CHARACTER NGO NGUTHAI CHARACTER CHO CHANTHAI CHARACTER CHO CHI" +
"NGTHAI CHARACTER CHO CHANGTHAI CHARACTER SO SOTHAI CHARACTER CHO CHOETHA" +
"I CHARACTER YO YINGTHAI CHARACTER DO CHADATHAI CHARACTER TO PATAKTHAI CH" +
"ARACTER THO THANTHAI CHARACTER THO NANGMONTHOTHAI CHARACTER THO PHUTHAOT" +
"HAI CHARACTER NO NENTHAI CHARACTER DO DEKTHAI CHARACTER TO TAOTHAI CHARA" +
"CTER THO THUNGTHAI CHARACTER THO THAHANTHAI CHARACTER THO THONGTHAI CHAR" +
"ACTER NO NUTHAI CHARACTER BO BAIMAITHAI CHARACTER PO PLATHAI CHARACTER P" +
"HO PHUNGTHAI CHARACTER FO FATHAI CHARACTER PHO PHANTHAI CHARACTER FO FAN" +
"THAI CHARACTER PHO SAMPHAOTHAI CHARACTER MO MATHAI CHARACTER YO YAKTHAI " +
"CHARACTER RO RUATHAI CHARACTER RUTHAI CHARACTER LO LINGTHAI CHARACTER LU" +
"THAI CHARACTER WO WAENTHAI CHARACTER SO SALATHAI CHARACTER SO RUSITHAI C" +
"HARACTER SO SUATHAI CHARACTER HO HIPTHAI CHARACTER LO CHULATHAI CHARACTE" +
"R O ANGTHAI CHARACTER HO NOKHUKTHAI CHARACTER PAIYANNOITHAI CHARACTER SA" +
"RA ATHAI CHARACTER MAI HAN-AKATTHAI CHARACTER SARA AATHAI CHARACTER SARA" +
" AMTHAI CHARACTER SARA ITHAI CHARACTER SARA IITHAI CHARACTER SARA UETHAI" +
" CHARACTER SARA UEETHAI CHARACTER SARA UTHAI CHARACTER SARA UUTHAI CHARA") + ("" +
"CTER PHINTHUTHAI CURRENCY SYMBOL BAHTTHAI CHARACTER SARA ETHAI CHARACTER" +
" SARA AETHAI CHARACTER SARA OTHAI CHARACTER SARA AI MAIMUANTHAI CHARACTE" +
"R SARA AI MAIMALAITHAI CHARACTER LAKKHANGYAOTHAI CHARACTER MAIYAMOKTHAI " +
"CHARACTER MAITAIKHUTHAI CHARACTER MAI EKTHAI CHARACTER MAI THOTHAI CHARA" +
"CTER MAI TRITHAI CHARACTER MAI CHATTAWATHAI CHARACTER THANTHAKHATTHAI CH" +
"ARACTER NIKHAHITTHAI CHARACTER YAMAKKANTHAI CHARACTER FONGMANTHAI DIGIT " +
"ZEROTHAI DIGIT ONETHAI DIGIT TWOTHAI DIGIT THREETHAI DIGIT FOURTHAI DIGI" +
"T FIVETHAI DIGIT SIXTHAI DIGIT SEVENTHAI DIGIT EIGHTTHAI DIGIT NINETHAI " +
"CHARACTER ANGKHANKHUTHAI CHARACTER KHOMUTLAO LETTER KOLAO LETTER KHO SUN" +
"GLAO LETTER KHO TAMLAO LETTER PALI GHALAO LETTER NGOLAO LETTER COLAO LET" +
"TER PALI CHALAO LETTER SO TAMLAO LETTER PALI JHALAO LETTER NYOLAO LETTER" +
" PALI NYALAO LETTER PALI TTALAO LETTER PALI TTHALAO LETTER PALI DDALAO L" +
"ETTER PALI DDHALAO LETTER PALI NNALAO LETTER DOLAO LETTER TOLAO LETTER T" +
"HO SUNGLAO LETTER THO TAMLAO LETTER PALI DHALAO LETTER NOLAO LETTER BOLA" +
"O LETTER POLAO LETTER PHO SUNGLAO LETTER FO TAMLAO LETTER PHO TAMLAO LET" +
"TER FO SUNGLAO LETTER PALI BHALAO LETTER MOLAO LETTER YOLAO LETTER LO LI" +
"NGLAO LETTER LO LOOTLAO LETTER WOLAO LETTER SANSKRIT SHALAO LETTER SANSK" +
"RIT SSALAO LETTER SO SUNGLAO LETTER HO SUNGLAO LETTER PALI LLALAO LETTER" +
" OLAO LETTER HO TAMLAO ELLIPSISLAO VOWEL SIGN ALAO VOWEL SIGN MAI KANLAO" +
" VOWEL SIGN AALAO VOWEL SIGN AMLAO VOWEL SIGN ILAO VOWEL SIGN IILAO VOWE" +
"L SIGN YLAO VOWEL SIGN YYLAO VOWEL SIGN ULAO VOWEL SIGN UULAO SIGN PALI " +
"VIRAMALAO VOWEL SIGN MAI KONLAO SEMIVOWEL SIGN LOLAO SEMIVOWEL SIGN NYOL" +
"AO VOWEL SIGN ELAO VOWEL SIGN EILAO VOWEL SIGN OLAO VOWEL SIGN AYLAO VOW" +
"EL SIGN AILAO KO LALAO TONE MAI EKLAO TONE MAI THOLAO TONE MAI TILAO TON" +
"E MAI CATAWALAO CANCELLATION MARKLAO NIGGAHITALAO YAMAKKANLAO DIGIT ZERO" +
"LAO DIGIT ONELAO DIGIT TWOLAO DIGIT THREELAO DIGIT FOURLAO DIGIT FIVELAO" +
" DIGIT SIXLAO DIGIT SEVENLAO DIGIT EIGHTLAO DIGIT NINELAO HO NOLAO HO MO" +
"LAO LETTER KHMU GOLAO LETTER KHMU NYOTIBETAN SYLLABLE OMTIBETAN MARK GTE" +
"R YIG MGO TRUNCATED ATIBETAN MARK GTER YIG MGO -UM RNAM BCAD MATIBETAN M" +
"ARK GTER YIG MGO -UM GTER TSHEG MATIBETAN MARK INITIAL YIG MGO MDUN MATI" +
"BETAN MARK CLOSING YIG MGO SGAB MATIBETAN MARK CARET YIG MGO PHUR SHAD M" +
"ATIBETAN MARK YIG MGO TSHEG SHAD MATIBETAN MARK SBRUL SHADTIBETAN MARK B" +
"SKUR YIG MGOTIBETAN MARK BKA- SHOG YIG MGOTIBETAN MARK INTERSYLLABIC TSH" +
"EGTIBETAN MARK DELIMITER TSHEG BSTARTIBETAN MARK SHADTIBETAN MARK NYIS S" +
"HADTIBETAN MARK TSHEG SHADTIBETAN MARK NYIS TSHEG SHADTIBETAN MARK RIN C" +
"HEN SPUNGS SHADTIBETAN MARK RGYA GRAM SHADTIBETAN MARK CARET -DZUD RTAGS" +
" ME LONG CANTIBETAN MARK GTER TSHEGTIBETAN LOGOTYPE SIGN CHAD RTAGSTIBET" +
"AN LOGOTYPE SIGN LHAG RTAGSTIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTA" +
"GSTIBETAN ASTROLOGICAL SIGN -KHYUD PATIBETAN ASTROLOGICAL SIGN SDONG TSH" +
"UGSTIBETAN SIGN RDEL DKAR GCIGTIBETAN SIGN RDEL DKAR GNYISTIBETAN SIGN R" +
"DEL DKAR GSUMTIBETAN SIGN RDEL NAG GCIGTIBETAN SIGN RDEL NAG GNYISTIBETA" +
"N SIGN RDEL DKAR RDEL NAGTIBETAN DIGIT ZEROTIBETAN DIGIT ONETIBETAN DIGI" +
"T TWOTIBETAN DIGIT THREETIBETAN DIGIT FOURTIBETAN DIGIT FIVETIBETAN DIGI" +
"T SIXTIBETAN DIGIT SEVENTIBETAN DIGIT EIGHTTIBETAN DIGIT NINETIBETAN DIG" +
"IT HALF ONETIBETAN DIGIT HALF TWOTIBETAN DIGIT HALF THREETIBETAN DIGIT H" +
"ALF FOURTIBETAN DIGIT HALF FIVETIBETAN DIGIT HALF SIXTIBETAN DIGIT HALF " +
"SEVENTIBETAN DIGIT HALF EIGHTTIBETAN DIGIT HALF NINETIBETAN DIGIT HALF Z" +
"EROTIBETAN MARK BSDUS RTAGSTIBETAN MARK NGAS BZUNG NYI ZLATIBETAN MARK C" +
"ARET -DZUD RTAGS BZHI MIG CANTIBETAN MARK NGAS BZUNG SGOR RTAGSTIBETAN M" +
"ARK CHE MGOTIBETAN MARK TSA -PHRUTIBETAN MARK GUG RTAGS GYONTIBETAN MARK" +
" GUG RTAGS GYASTIBETAN MARK ANG KHANG GYONTIBETAN MARK ANG KHANG GYASTIB" +
"ETAN SIGN YAR TSHESTIBETAN SIGN MAR TSHESTIBETAN LETTER KATIBETAN LETTER" +
" KHATIBETAN LETTER GATIBETAN LETTER GHATIBETAN LETTER NGATIBETAN LETTER " +
"CATIBETAN LETTER CHATIBETAN LETTER JATIBETAN LETTER NYATIBETAN LETTER TT" +
"ATIBETAN LETTER TTHATIBETAN LETTER DDATIBETAN LETTER DDHATIBETAN LETTER " +
"NNATIBETAN LETTER TATIBETAN LETTER THATIBETAN LETTER DATIBETAN LETTER DH" +
"ATIBETAN LETTER NATIBETAN LETTER PATIBETAN LETTER PHATIBETAN LETTER BATI" +
"BETAN LETTER BHATIBETAN LETTER MATIBETAN LETTER TSATIBETAN LETTER TSHATI" +
"BETAN LETTER DZATIBETAN LETTER DZHATIBETAN LETTER WATIBETAN LETTER ZHATI" +
"BETAN LETTER ZATIBETAN LETTER -ATIBETAN LETTER YATIBETAN LETTER RATIBETA" +
"N LETTER LATIBETAN LETTER SHATIBETAN LETTER SSATIBETAN LETTER SATIBETAN " +
"LETTER HATIBETAN LETTER ATIBETAN LETTER KSSATIBETAN LETTER FIXED-FORM RA" +
"TIBETAN LETTER KKATIBETAN LETTER RRATIBETAN VOWEL SIGN AATIBETAN VOWEL S" +
"IGN ITIBETAN VOWEL SIGN IITIBETAN VOWEL SIGN UTIBETAN VOWEL SIGN UUTIBET") + ("" +
"AN VOWEL SIGN VOCALIC RTIBETAN VOWEL SIGN VOCALIC RRTIBETAN VOWEL SIGN V" +
"OCALIC LTIBETAN VOWEL SIGN VOCALIC LLTIBETAN VOWEL SIGN ETIBETAN VOWEL S" +
"IGN EETIBETAN VOWEL SIGN OTIBETAN VOWEL SIGN OOTIBETAN SIGN RJES SU NGA " +
"ROTIBETAN SIGN RNAM BCADTIBETAN VOWEL SIGN REVERSED ITIBETAN VOWEL SIGN " +
"REVERSED IITIBETAN SIGN NYI ZLA NAA DATIBETAN SIGN SNA LDANTIBETAN MARK " +
"HALANTATIBETAN MARK PALUTATIBETAN SIGN LCI RTAGSTIBETAN SIGN YANG RTAGST" +
"IBETAN SIGN LCE TSA CANTIBETAN SIGN MCHU CANTIBETAN SIGN GRU CAN RGYINGS" +
"TIBETAN SIGN GRU MED RGYINGSTIBETAN SIGN INVERTED MCHU CANTIBETAN SUBJOI" +
"NED SIGN LCE TSA CANTIBETAN SUBJOINED SIGN MCHU CANTIBETAN SUBJOINED SIG" +
"N INVERTED MCHU CANTIBETAN SUBJOINED LETTER KATIBETAN SUBJOINED LETTER K" +
"HATIBETAN SUBJOINED LETTER GATIBETAN SUBJOINED LETTER GHATIBETAN SUBJOIN" +
"ED LETTER NGATIBETAN SUBJOINED LETTER CATIBETAN SUBJOINED LETTER CHATIBE" +
"TAN SUBJOINED LETTER JATIBETAN SUBJOINED LETTER NYATIBETAN SUBJOINED LET" +
"TER TTATIBETAN SUBJOINED LETTER TTHATIBETAN SUBJOINED LETTER DDATIBETAN " +
"SUBJOINED LETTER DDHATIBETAN SUBJOINED LETTER NNATIBETAN SUBJOINED LETTE" +
"R TATIBETAN SUBJOINED LETTER THATIBETAN SUBJOINED LETTER DATIBETAN SUBJO" +
"INED LETTER DHATIBETAN SUBJOINED LETTER NATIBETAN SUBJOINED LETTER PATIB" +
"ETAN SUBJOINED LETTER PHATIBETAN SUBJOINED LETTER BATIBETAN SUBJOINED LE" +
"TTER BHATIBETAN SUBJOINED LETTER MATIBETAN SUBJOINED LETTER TSATIBETAN S" +
"UBJOINED LETTER TSHATIBETAN SUBJOINED LETTER DZATIBETAN SUBJOINED LETTER" +
" DZHATIBETAN SUBJOINED LETTER WATIBETAN SUBJOINED LETTER ZHATIBETAN SUBJ" +
"OINED LETTER ZATIBETAN SUBJOINED LETTER -ATIBETAN SUBJOINED LETTER YATIB" +
"ETAN SUBJOINED LETTER RATIBETAN SUBJOINED LETTER LATIBETAN SUBJOINED LET" +
"TER SHATIBETAN SUBJOINED LETTER SSATIBETAN SUBJOINED LETTER SATIBETAN SU" +
"BJOINED LETTER HATIBETAN SUBJOINED LETTER ATIBETAN SUBJOINED LETTER KSSA" +
"TIBETAN SUBJOINED LETTER FIXED-FORM WATIBETAN SUBJOINED LETTER FIXED-FOR" +
"M YATIBETAN SUBJOINED LETTER FIXED-FORM RATIBETAN KU RU KHATIBETAN KU RU" +
" KHA BZHI MIG CANTIBETAN CANTILLATION SIGN HEAVY BEATTIBETAN CANTILLATIO" +
"N SIGN LIGHT BEATTIBETAN CANTILLATION SIGN CANG TE-UTIBETAN CANTILLATION" +
" SIGN SBUB -CHALTIBETAN SYMBOL DRIL BUTIBETAN SYMBOL RDO RJETIBETAN SYMB" +
"OL PADMA GDANTIBETAN SYMBOL RDO RJE RGYA GRAMTIBETAN SYMBOL PHUR PATIBET" +
"AN SYMBOL NOR BUTIBETAN SYMBOL NOR BU NYIS -KHYILTIBETAN SYMBOL NOR BU G" +
"SUM -KHYILTIBETAN SYMBOL NOR BU BZHI -KHYILTIBETAN SIGN RDEL NAG RDEL DK" +
"ARTIBETAN SIGN RDEL NAG GSUMTIBETAN MARK BSKA- SHOG GI MGO RGYANTIBETAN " +
"MARK MNYAM YIG GI MGO RGYANTIBETAN MARK NYIS TSHEGTIBETAN MARK INITIAL B" +
"RDA RNYING YIG MGO MDUN MATIBETAN MARK CLOSING BRDA RNYING YIG MGO SGAB " +
"MARIGHT-FACING SVASTI SIGNLEFT-FACING SVASTI SIGNRIGHT-FACING SVASTI SIG" +
"N WITH DOTSLEFT-FACING SVASTI SIGN WITH DOTSTIBETAN MARK LEADING MCHAN R" +
"TAGSTIBETAN MARK TRAILING MCHAN RTAGSMYANMAR LETTER KAMYANMAR LETTER KHA" +
"MYANMAR LETTER GAMYANMAR LETTER GHAMYANMAR LETTER NGAMYANMAR LETTER CAMY" +
"ANMAR LETTER CHAMYANMAR LETTER JAMYANMAR LETTER JHAMYANMAR LETTER NYAMYA" +
"NMAR LETTER NNYAMYANMAR LETTER TTAMYANMAR LETTER TTHAMYANMAR LETTER DDAM" +
"YANMAR LETTER DDHAMYANMAR LETTER NNAMYANMAR LETTER TAMYANMAR LETTER THAM" +
"YANMAR LETTER DAMYANMAR LETTER DHAMYANMAR LETTER NAMYANMAR LETTER PAMYAN" +
"MAR LETTER PHAMYANMAR LETTER BAMYANMAR LETTER BHAMYANMAR LETTER MAMYANMA" +
"R LETTER YAMYANMAR LETTER RAMYANMAR LETTER LAMYANMAR LETTER WAMYANMAR LE" +
"TTER SAMYANMAR LETTER HAMYANMAR LETTER LLAMYANMAR LETTER AMYANMAR LETTER" +
" SHAN AMYANMAR LETTER IMYANMAR LETTER IIMYANMAR LETTER UMYANMAR LETTER U" +
"UMYANMAR LETTER EMYANMAR LETTER MON EMYANMAR LETTER OMYANMAR LETTER AUMY" +
"ANMAR VOWEL SIGN TALL AAMYANMAR VOWEL SIGN AAMYANMAR VOWEL SIGN IMYANMAR" +
" VOWEL SIGN IIMYANMAR VOWEL SIGN UMYANMAR VOWEL SIGN UUMYANMAR VOWEL SIG" +
"N EMYANMAR VOWEL SIGN AIMYANMAR VOWEL SIGN MON IIMYANMAR VOWEL SIGN MON " +
"OMYANMAR VOWEL SIGN E ABOVEMYANMAR SIGN ANUSVARAMYANMAR SIGN DOT BELOWMY" +
"ANMAR SIGN VISARGAMYANMAR SIGN VIRAMAMYANMAR SIGN ASATMYANMAR CONSONANT " +
"SIGN MEDIAL YAMYANMAR CONSONANT SIGN MEDIAL RAMYANMAR CONSONANT SIGN MED" +
"IAL WAMYANMAR CONSONANT SIGN MEDIAL HAMYANMAR LETTER GREAT SAMYANMAR DIG" +
"IT ZEROMYANMAR DIGIT ONEMYANMAR DIGIT TWOMYANMAR DIGIT THREEMYANMAR DIGI" +
"T FOURMYANMAR DIGIT FIVEMYANMAR DIGIT SIXMYANMAR DIGIT SEVENMYANMAR DIGI" +
"T EIGHTMYANMAR DIGIT NINEMYANMAR SIGN LITTLE SECTIONMYANMAR SIGN SECTION" +
"MYANMAR SYMBOL LOCATIVEMYANMAR SYMBOL COMPLETEDMYANMAR SYMBOL AFOREMENTI" +
"ONEDMYANMAR SYMBOL GENITIVEMYANMAR LETTER SHAMYANMAR LETTER SSAMYANMAR L" +
"ETTER VOCALIC RMYANMAR 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 LETTE") + ("" +
"R MON NGAMYANMAR LETTER MON JHAMYANMAR LETTER MON BBAMYANMAR LETTER MON " +
"BBEMYANMAR CONSONANT SIGN MON MEDIAL NAMYANMAR CONSONANT SIGN MON MEDIAL" +
" MAMYANMAR CONSONANT SIGN MON MEDIAL LAMYANMAR LETTER SGAW KAREN SHAMYAN" +
"MAR VOWEL SIGN SGAW KAREN EUMYANMAR TONE MARK SGAW KAREN HATHIMYANMAR TO" +
"NE MARK SGAW KAREN KE PHOMYANMAR LETTER WESTERN PWO KAREN THAMYANMAR LET" +
"TER WESTERN PWO KAREN PWAMYANMAR VOWEL SIGN WESTERN PWO KAREN EUMYANMAR " +
"VOWEL SIGN WESTERN PWO KAREN UEMYANMAR SIGN WESTERN PWO KAREN TONE-1MYAN" +
"MAR SIGN WESTERN PWO KAREN TONE-2MYANMAR SIGN WESTERN PWO KAREN TONE-3MY" +
"ANMAR SIGN WESTERN PWO KAREN TONE-4MYANMAR SIGN WESTERN PWO KAREN TONE-5" +
"MYANMAR LETTER EASTERN PWO KAREN NNAMYANMAR LETTER EASTERN PWO KAREN YWA" +
"MYANMAR LETTER EASTERN PWO KAREN GHWAMYANMAR VOWEL SIGN GEBA KAREN IMYAN" +
"MAR VOWEL SIGN KAYAH OEMYANMAR VOWEL SIGN KAYAH UMYANMAR VOWEL SIGN KAYA" +
"H EEMYANMAR LETTER SHAN KAMYANMAR LETTER SHAN KHAMYANMAR LETTER SHAN GAM" +
"YANMAR LETTER SHAN CAMYANMAR LETTER SHAN ZAMYANMAR LETTER SHAN NYAMYANMA" +
"R LETTER SHAN DAMYANMAR LETTER SHAN NAMYANMAR LETTER SHAN PHAMYANMAR LET" +
"TER SHAN FAMYANMAR LETTER SHAN BAMYANMAR LETTER SHAN THAMYANMAR LETTER S" +
"HAN HAMYANMAR CONSONANT SIGN SHAN MEDIAL WAMYANMAR VOWEL SIGN SHAN AAMYA" +
"NMAR VOWEL SIGN SHAN EMYANMAR VOWEL SIGN SHAN E ABOVEMYANMAR VOWEL SIGN " +
"SHAN FINAL YMYANMAR SIGN SHAN TONE-2MYANMAR SIGN SHAN TONE-3MYANMAR SIGN" +
" SHAN TONE-5MYANMAR SIGN SHAN TONE-6MYANMAR SIGN SHAN COUNCIL TONE-2MYAN" +
"MAR SIGN SHAN COUNCIL TONE-3MYANMAR SIGN SHAN COUNCIL EMPHATIC TONEMYANM" +
"AR LETTER RUMAI PALAUNG FAMYANMAR SIGN RUMAI PALAUNG TONE-5MYANMAR SHAN " +
"DIGIT ZEROMYANMAR SHAN DIGIT ONEMYANMAR SHAN DIGIT TWOMYANMAR SHAN DIGIT" +
" THREEMYANMAR SHAN DIGIT FOURMYANMAR SHAN DIGIT FIVEMYANMAR SHAN DIGIT S" +
"IXMYANMAR SHAN DIGIT SEVENMYANMAR SHAN DIGIT EIGHTMYANMAR SHAN DIGIT NIN" +
"EMYANMAR SIGN KHAMTI TONE-1MYANMAR SIGN KHAMTI TONE-3MYANMAR VOWEL SIGN " +
"AITON AMYANMAR VOWEL SIGN AITON AIMYANMAR SYMBOL SHAN ONEMYANMAR SYMBOL " +
"SHAN EXCLAMATIONGEORGIAN CAPITAL LETTER ANGEORGIAN CAPITAL LETTER BANGEO" +
"RGIAN CAPITAL LETTER GANGEORGIAN CAPITAL LETTER DONGEORGIAN CAPITAL LETT" +
"ER ENGEORGIAN CAPITAL LETTER VINGEORGIAN CAPITAL LETTER ZENGEORGIAN CAPI" +
"TAL LETTER TANGEORGIAN CAPITAL LETTER INGEORGIAN CAPITAL LETTER KANGEORG" +
"IAN CAPITAL LETTER LASGEORGIAN CAPITAL LETTER MANGEORGIAN CAPITAL LETTER" +
" NARGEORGIAN CAPITAL LETTER ONGEORGIAN CAPITAL LETTER PARGEORGIAN CAPITA" +
"L LETTER ZHARGEORGIAN CAPITAL LETTER RAEGEORGIAN CAPITAL LETTER SANGEORG" +
"IAN CAPITAL LETTER TARGEORGIAN CAPITAL LETTER UNGEORGIAN CAPITAL LETTER " +
"PHARGEORGIAN CAPITAL LETTER KHARGEORGIAN CAPITAL LETTER GHANGEORGIAN CAP" +
"ITAL LETTER QARGEORGIAN CAPITAL LETTER SHINGEORGIAN CAPITAL LETTER CHING" +
"EORGIAN CAPITAL LETTER CANGEORGIAN CAPITAL LETTER JILGEORGIAN CAPITAL LE" +
"TTER CILGEORGIAN CAPITAL LETTER CHARGEORGIAN CAPITAL LETTER XANGEORGIAN " +
"CAPITAL LETTER JHANGEORGIAN CAPITAL LETTER HAEGEORGIAN CAPITAL LETTER HE" +
"GEORGIAN CAPITAL LETTER HIEGEORGIAN CAPITAL LETTER WEGEORGIAN CAPITAL LE" +
"TTER HARGEORGIAN CAPITAL LETTER HOEGEORGIAN CAPITAL LETTER YNGEORGIAN CA" +
"PITAL LETTER AENGEORGIAN LETTER ANGEORGIAN LETTER BANGEORGIAN LETTER GAN" +
"GEORGIAN LETTER DONGEORGIAN LETTER ENGEORGIAN LETTER VINGEORGIAN LETTER " +
"ZENGEORGIAN LETTER TANGEORGIAN LETTER INGEORGIAN LETTER KANGEORGIAN LETT" +
"ER LASGEORGIAN LETTER MANGEORGIAN LETTER NARGEORGIAN LETTER ONGEORGIAN L" +
"ETTER PARGEORGIAN LETTER ZHARGEORGIAN LETTER RAEGEORGIAN LETTER SANGEORG" +
"IAN LETTER TARGEORGIAN LETTER UNGEORGIAN LETTER PHARGEORGIAN LETTER KHAR" +
"GEORGIAN LETTER GHANGEORGIAN LETTER QARGEORGIAN LETTER SHINGEORGIAN LETT" +
"ER CHINGEORGIAN LETTER CANGEORGIAN LETTER JILGEORGIAN LETTER CILGEORGIAN" +
" LETTER CHARGEORGIAN LETTER XANGEORGIAN LETTER JHANGEORGIAN LETTER HAEGE" +
"ORGIAN LETTER HEGEORGIAN LETTER HIEGEORGIAN LETTER WEGEORGIAN LETTER HAR" +
"GEORGIAN LETTER HOEGEORGIAN LETTER FIGEORGIAN LETTER YNGEORGIAN LETTER E" +
"LIFIGEORGIAN LETTER TURNED GANGEORGIAN LETTER AINGEORGIAN PARAGRAPH SEPA" +
"RATORMODIFIER LETTER GEORGIAN NARGEORGIAN LETTER AENGEORGIAN LETTER HARD" +
" SIGNGEORGIAN LETTER LABIAL SIGNHANGUL CHOSEONG KIYEOKHANGUL CHOSEONG SS" +
"ANGKIYEOKHANGUL CHOSEONG NIEUNHANGUL CHOSEONG TIKEUTHANGUL CHOSEONG SSAN" +
"GTIKEUTHANGUL CHOSEONG RIEULHANGUL CHOSEONG MIEUMHANGUL CHOSEONG PIEUPHA" +
"NGUL CHOSEONG SSANGPIEUPHANGUL CHOSEONG SIOSHANGUL CHOSEONG SSANGSIOSHAN" +
"GUL CHOSEONG IEUNGHANGUL CHOSEONG CIEUCHANGUL CHOSEONG SSANGCIEUCHANGUL " +
"CHOSEONG CHIEUCHHANGUL CHOSEONG KHIEUKHHANGUL CHOSEONG THIEUTHHANGUL CHO" +
"SEONG PHIEUPHHANGUL CHOSEONG HIEUHHANGUL CHOSEONG NIEUN-KIYEOKHANGUL CHO" +
"SEONG SSANGNIEUNHANGUL CHOSEONG NIEUN-TIKEUTHANGUL CHOSEONG NIEUN-PIEUPH" +
"ANGUL CHOSEONG TIKEUT-KIYEOKHANGUL CHOSEONG RIEUL-NIEUNHANGUL CHOSEONG S") + ("" +
"SANGRIEULHANGUL CHOSEONG RIEUL-HIEUHHANGUL CHOSEONG KAPYEOUNRIEULHANGUL " +
"CHOSEONG MIEUM-PIEUPHANGUL CHOSEONG KAPYEOUNMIEUMHANGUL CHOSEONG PIEUP-K" +
"IYEOKHANGUL CHOSEONG PIEUP-NIEUNHANGUL CHOSEONG PIEUP-TIKEUTHANGUL CHOSE" +
"ONG PIEUP-SIOSHANGUL CHOSEONG PIEUP-SIOS-KIYEOKHANGUL CHOSEONG PIEUP-SIO" +
"S-TIKEUTHANGUL CHOSEONG PIEUP-SIOS-PIEUPHANGUL CHOSEONG PIEUP-SSANGSIOSH" +
"ANGUL CHOSEONG PIEUP-SIOS-CIEUCHANGUL CHOSEONG PIEUP-CIEUCHANGUL CHOSEON" +
"G PIEUP-CHIEUCHHANGUL CHOSEONG PIEUP-THIEUTHHANGUL CHOSEONG PIEUP-PHIEUP" +
"HHANGUL CHOSEONG KAPYEOUNPIEUPHANGUL CHOSEONG KAPYEOUNSSANGPIEUPHANGUL C" +
"HOSEONG SIOS-KIYEOKHANGUL CHOSEONG SIOS-NIEUNHANGUL CHOSEONG SIOS-TIKEUT" +
"HANGUL CHOSEONG SIOS-RIEULHANGUL CHOSEONG SIOS-MIEUMHANGUL CHOSEONG SIOS" +
"-PIEUPHANGUL CHOSEONG SIOS-PIEUP-KIYEOKHANGUL CHOSEONG SIOS-SSANGSIOSHAN" +
"GUL CHOSEONG SIOS-IEUNGHANGUL CHOSEONG SIOS-CIEUCHANGUL CHOSEONG SIOS-CH" +
"IEUCHHANGUL CHOSEONG SIOS-KHIEUKHHANGUL CHOSEONG SIOS-THIEUTHHANGUL CHOS" +
"EONG SIOS-PHIEUPHHANGUL CHOSEONG SIOS-HIEUHHANGUL CHOSEONG CHITUEUMSIOSH" +
"ANGUL CHOSEONG CHITUEUMSSANGSIOSHANGUL CHOSEONG CEONGCHIEUMSIOSHANGUL CH" +
"OSEONG CEONGCHIEUMSSANGSIOSHANGUL CHOSEONG PANSIOSHANGUL CHOSEONG IEUNG-" +
"KIYEOKHANGUL CHOSEONG IEUNG-TIKEUTHANGUL CHOSEONG IEUNG-MIEUMHANGUL CHOS" +
"EONG IEUNG-PIEUPHANGUL CHOSEONG IEUNG-SIOSHANGUL CHOSEONG IEUNG-PANSIOSH" +
"ANGUL CHOSEONG SSANGIEUNGHANGUL CHOSEONG IEUNG-CIEUCHANGUL CHOSEONG IEUN" +
"G-CHIEUCHHANGUL CHOSEONG IEUNG-THIEUTHHANGUL CHOSEONG IEUNG-PHIEUPHHANGU" +
"L CHOSEONG YESIEUNGHANGUL CHOSEONG CIEUC-IEUNGHANGUL CHOSEONG CHITUEUMCI" +
"EUCHANGUL CHOSEONG CHITUEUMSSANGCIEUCHANGUL CHOSEONG CEONGCHIEUMCIEUCHAN" +
"GUL CHOSEONG CEONGCHIEUMSSANGCIEUCHANGUL CHOSEONG CHIEUCH-KHIEUKHHANGUL " +
"CHOSEONG CHIEUCH-HIEUHHANGUL CHOSEONG CHITUEUMCHIEUCHHANGUL CHOSEONG CEO" +
"NGCHIEUMCHIEUCHHANGUL CHOSEONG PHIEUPH-PIEUPHANGUL CHOSEONG KAPYEOUNPHIE" +
"UPHHANGUL CHOSEONG SSANGHIEUHHANGUL CHOSEONG YEORINHIEUHHANGUL CHOSEONG " +
"KIYEOK-TIKEUTHANGUL CHOSEONG NIEUN-SIOSHANGUL CHOSEONG NIEUN-CIEUCHANGUL" +
" CHOSEONG NIEUN-HIEUHHANGUL CHOSEONG TIKEUT-RIEULHANGUL CHOSEONG FILLERH" +
"ANGUL JUNGSEONG FILLERHANGUL JUNGSEONG AHANGUL JUNGSEONG AEHANGUL JUNGSE" +
"ONG YAHANGUL JUNGSEONG YAEHANGUL JUNGSEONG EOHANGUL JUNGSEONG EHANGUL JU" +
"NGSEONG YEOHANGUL JUNGSEONG YEHANGUL JUNGSEONG OHANGUL JUNGSEONG WAHANGU" +
"L JUNGSEONG WAEHANGUL JUNGSEONG OEHANGUL JUNGSEONG YOHANGUL JUNGSEONG UH" +
"ANGUL JUNGSEONG WEOHANGUL JUNGSEONG WEHANGUL JUNGSEONG WIHANGUL JUNGSEON" +
"G YUHANGUL JUNGSEONG EUHANGUL JUNGSEONG YIHANGUL JUNGSEONG IHANGUL JUNGS" +
"EONG A-OHANGUL JUNGSEONG A-UHANGUL JUNGSEONG YA-OHANGUL JUNGSEONG YA-YOH" +
"ANGUL JUNGSEONG EO-OHANGUL JUNGSEONG EO-UHANGUL JUNGSEONG EO-EUHANGUL JU" +
"NGSEONG YEO-OHANGUL JUNGSEONG YEO-UHANGUL JUNGSEONG O-EOHANGUL JUNGSEONG" +
" O-EHANGUL JUNGSEONG O-YEHANGUL JUNGSEONG O-OHANGUL JUNGSEONG O-UHANGUL " +
"JUNGSEONG YO-YAHANGUL JUNGSEONG YO-YAEHANGUL JUNGSEONG YO-YEOHANGUL JUNG" +
"SEONG YO-OHANGUL JUNGSEONG YO-IHANGUL JUNGSEONG U-AHANGUL JUNGSEONG U-AE" +
"HANGUL JUNGSEONG U-EO-EUHANGUL JUNGSEONG U-YEHANGUL JUNGSEONG U-UHANGUL " +
"JUNGSEONG YU-AHANGUL JUNGSEONG YU-EOHANGUL JUNGSEONG YU-EHANGUL JUNGSEON" +
"G YU-YEOHANGUL JUNGSEONG YU-YEHANGUL JUNGSEONG YU-UHANGUL JUNGSEONG YU-I" +
"HANGUL JUNGSEONG EU-UHANGUL JUNGSEONG EU-EUHANGUL JUNGSEONG YI-UHANGUL J" +
"UNGSEONG I-AHANGUL JUNGSEONG I-YAHANGUL JUNGSEONG I-OHANGUL JUNGSEONG I-" +
"UHANGUL JUNGSEONG I-EUHANGUL JUNGSEONG I-ARAEAHANGUL JUNGSEONG ARAEAHANG" +
"UL JUNGSEONG ARAEA-EOHANGUL JUNGSEONG ARAEA-UHANGUL JUNGSEONG ARAEA-IHAN" +
"GUL JUNGSEONG SSANGARAEAHANGUL JUNGSEONG A-EUHANGUL JUNGSEONG YA-UHANGUL" +
" JUNGSEONG YEO-YAHANGUL JUNGSEONG O-YAHANGUL JUNGSEONG O-YAEHANGUL JONGS" +
"EONG KIYEOKHANGUL JONGSEONG SSANGKIYEOKHANGUL JONGSEONG KIYEOK-SIOSHANGU" +
"L JONGSEONG NIEUNHANGUL JONGSEONG NIEUN-CIEUCHANGUL JONGSEONG NIEUN-HIEU" +
"HHANGUL JONGSEONG TIKEUTHANGUL JONGSEONG RIEULHANGUL JONGSEONG RIEUL-KIY" +
"EOKHANGUL JONGSEONG RIEUL-MIEUMHANGUL JONGSEONG RIEUL-PIEUPHANGUL JONGSE" +
"ONG RIEUL-SIOSHANGUL JONGSEONG RIEUL-THIEUTHHANGUL JONGSEONG RIEUL-PHIEU" +
"PHHANGUL JONGSEONG RIEUL-HIEUHHANGUL JONGSEONG MIEUMHANGUL JONGSEONG PIE" +
"UPHANGUL JONGSEONG PIEUP-SIOSHANGUL JONGSEONG SIOSHANGUL JONGSEONG SSANG" +
"SIOSHANGUL JONGSEONG IEUNGHANGUL JONGSEONG CIEUCHANGUL JONGSEONG CHIEUCH" +
"HANGUL JONGSEONG KHIEUKHHANGUL JONGSEONG THIEUTHHANGUL JONGSEONG PHIEUPH" +
"HANGUL JONGSEONG HIEUHHANGUL JONGSEONG KIYEOK-RIEULHANGUL JONGSEONG KIYE" +
"OK-SIOS-KIYEOKHANGUL JONGSEONG NIEUN-KIYEOKHANGUL JONGSEONG NIEUN-TIKEUT" +
"HANGUL JONGSEONG NIEUN-SIOSHANGUL JONGSEONG NIEUN-PANSIOSHANGUL JONGSEON" +
"G NIEUN-THIEUTHHANGUL JONGSEONG TIKEUT-KIYEOKHANGUL JONGSEONG TIKEUT-RIE" +
"ULHANGUL JONGSEONG RIEUL-KIYEOK-SIOSHANGUL JONGSEONG RIEUL-NIEUNHANGUL J" +
"ONGSEONG RIEUL-TIKEUTHANGUL JONGSEONG RIEUL-TIKEUT-HIEUHHANGUL JONGSEONG") + ("" +
" SSANGRIEULHANGUL JONGSEONG RIEUL-MIEUM-KIYEOKHANGUL JONGSEONG RIEUL-MIE" +
"UM-SIOSHANGUL JONGSEONG RIEUL-PIEUP-SIOSHANGUL JONGSEONG RIEUL-PIEUP-HIE" +
"UHHANGUL JONGSEONG RIEUL-KAPYEOUNPIEUPHANGUL JONGSEONG RIEUL-SSANGSIOSHA" +
"NGUL JONGSEONG RIEUL-PANSIOSHANGUL JONGSEONG RIEUL-KHIEUKHHANGUL JONGSEO" +
"NG RIEUL-YEORINHIEUHHANGUL JONGSEONG MIEUM-KIYEOKHANGUL JONGSEONG MIEUM-" +
"RIEULHANGUL JONGSEONG MIEUM-PIEUPHANGUL JONGSEONG MIEUM-SIOSHANGUL JONGS" +
"EONG MIEUM-SSANGSIOSHANGUL JONGSEONG MIEUM-PANSIOSHANGUL JONGSEONG MIEUM" +
"-CHIEUCHHANGUL JONGSEONG MIEUM-HIEUHHANGUL JONGSEONG KAPYEOUNMIEUMHANGUL" +
" JONGSEONG PIEUP-RIEULHANGUL JONGSEONG PIEUP-PHIEUPHHANGUL JONGSEONG PIE" +
"UP-HIEUHHANGUL JONGSEONG KAPYEOUNPIEUPHANGUL JONGSEONG SIOS-KIYEOKHANGUL" +
" JONGSEONG SIOS-TIKEUTHANGUL JONGSEONG SIOS-RIEULHANGUL JONGSEONG SIOS-P" +
"IEUPHANGUL JONGSEONG PANSIOSHANGUL JONGSEONG IEUNG-KIYEOKHANGUL JONGSEON" +
"G IEUNG-SSANGKIYEOKHANGUL JONGSEONG SSANGIEUNGHANGUL JONGSEONG IEUNG-KHI" +
"EUKHHANGUL JONGSEONG YESIEUNGHANGUL JONGSEONG YESIEUNG-SIOSHANGUL JONGSE" +
"ONG YESIEUNG-PANSIOSHANGUL JONGSEONG PHIEUPH-PIEUPHANGUL JONGSEONG KAPYE" +
"OUNPHIEUPHHANGUL JONGSEONG HIEUH-NIEUNHANGUL JONGSEONG HIEUH-RIEULHANGUL" +
" JONGSEONG HIEUH-MIEUMHANGUL JONGSEONG HIEUH-PIEUPHANGUL JONGSEONG YEORI" +
"NHIEUHHANGUL JONGSEONG KIYEOK-NIEUNHANGUL JONGSEONG KIYEOK-PIEUPHANGUL J" +
"ONGSEONG KIYEOK-CHIEUCHHANGUL JONGSEONG KIYEOK-KHIEUKHHANGUL JONGSEONG K" +
"IYEOK-HIEUHHANGUL JONGSEONG SSANGNIEUNETHIOPIC SYLLABLE HAETHIOPIC SYLLA" +
"BLE HUETHIOPIC SYLLABLE HIETHIOPIC SYLLABLE HAAETHIOPIC SYLLABLE HEEETHI" +
"OPIC SYLLABLE HEETHIOPIC SYLLABLE HOETHIOPIC SYLLABLE HOAETHIOPIC SYLLAB" +
"LE LAETHIOPIC SYLLABLE LUETHIOPIC SYLLABLE LIETHIOPIC SYLLABLE LAAETHIOP" +
"IC SYLLABLE LEEETHIOPIC SYLLABLE LEETHIOPIC SYLLABLE LOETHIOPIC SYLLABLE" +
" LWAETHIOPIC SYLLABLE HHAETHIOPIC SYLLABLE HHUETHIOPIC SYLLABLE HHIETHIO" +
"PIC SYLLABLE HHAAETHIOPIC SYLLABLE HHEEETHIOPIC SYLLABLE HHEETHIOPIC SYL" +
"LABLE HHOETHIOPIC SYLLABLE HHWAETHIOPIC SYLLABLE MAETHIOPIC SYLLABLE MUE" +
"THIOPIC SYLLABLE MIETHIOPIC SYLLABLE MAAETHIOPIC SYLLABLE MEEETHIOPIC SY" +
"LLABLE MEETHIOPIC SYLLABLE MOETHIOPIC SYLLABLE MWAETHIOPIC SYLLABLE SZAE" +
"THIOPIC SYLLABLE SZUETHIOPIC SYLLABLE SZIETHIOPIC SYLLABLE SZAAETHIOPIC " +
"SYLLABLE SZEEETHIOPIC SYLLABLE SZEETHIOPIC SYLLABLE SZOETHIOPIC SYLLABLE" +
" SZWAETHIOPIC SYLLABLE RAETHIOPIC SYLLABLE RUETHIOPIC SYLLABLE RIETHIOPI" +
"C SYLLABLE RAAETHIOPIC SYLLABLE REEETHIOPIC SYLLABLE REETHIOPIC SYLLABLE" +
" ROETHIOPIC SYLLABLE RWAETHIOPIC SYLLABLE SAETHIOPIC SYLLABLE SUETHIOPIC" +
" SYLLABLE SIETHIOPIC SYLLABLE SAAETHIOPIC SYLLABLE SEEETHIOPIC SYLLABLE " +
"SEETHIOPIC SYLLABLE SOETHIOPIC SYLLABLE SWAETHIOPIC SYLLABLE SHAETHIOPIC" +
" SYLLABLE SHUETHIOPIC SYLLABLE SHIETHIOPIC SYLLABLE SHAAETHIOPIC SYLLABL" +
"E SHEEETHIOPIC SYLLABLE SHEETHIOPIC SYLLABLE SHOETHIOPIC SYLLABLE SHWAET" +
"HIOPIC SYLLABLE QAETHIOPIC SYLLABLE QUETHIOPIC SYLLABLE QIETHIOPIC SYLLA" +
"BLE QAAETHIOPIC SYLLABLE QEEETHIOPIC SYLLABLE QEETHIOPIC SYLLABLE QOETHI" +
"OPIC SYLLABLE QOAETHIOPIC SYLLABLE QWAETHIOPIC SYLLABLE QWIETHIOPIC SYLL" +
"ABLE QWAAETHIOPIC SYLLABLE QWEEETHIOPIC SYLLABLE QWEETHIOPIC SYLLABLE QH" +
"AETHIOPIC SYLLABLE QHUETHIOPIC SYLLABLE QHIETHIOPIC SYLLABLE QHAAETHIOPI" +
"C SYLLABLE QHEEETHIOPIC SYLLABLE QHEETHIOPIC SYLLABLE QHOETHIOPIC SYLLAB" +
"LE QHWAETHIOPIC SYLLABLE QHWIETHIOPIC SYLLABLE QHWAAETHIOPIC SYLLABLE QH" +
"WEEETHIOPIC SYLLABLE QHWEETHIOPIC SYLLABLE BAETHIOPIC SYLLABLE BUETHIOPI" +
"C SYLLABLE BIETHIOPIC SYLLABLE BAAETHIOPIC SYLLABLE BEEETHIOPIC SYLLABLE" +
" BEETHIOPIC SYLLABLE BOETHIOPIC SYLLABLE BWAETHIOPIC SYLLABLE VAETHIOPIC" +
" SYLLABLE VUETHIOPIC SYLLABLE VIETHIOPIC SYLLABLE VAAETHIOPIC SYLLABLE V" +
"EEETHIOPIC SYLLABLE VEETHIOPIC SYLLABLE VOETHIOPIC SYLLABLE VWAETHIOPIC " +
"SYLLABLE TAETHIOPIC SYLLABLE TUETHIOPIC SYLLABLE TIETHIOPIC SYLLABLE TAA" +
"ETHIOPIC SYLLABLE TEEETHIOPIC SYLLABLE TEETHIOPIC SYLLABLE TOETHIOPIC SY" +
"LLABLE TWAETHIOPIC SYLLABLE CAETHIOPIC SYLLABLE CUETHIOPIC SYLLABLE CIET" +
"HIOPIC SYLLABLE CAAETHIOPIC SYLLABLE CEEETHIOPIC SYLLABLE CEETHIOPIC SYL" +
"LABLE COETHIOPIC SYLLABLE CWAETHIOPIC SYLLABLE XAETHIOPIC SYLLABLE XUETH" +
"IOPIC SYLLABLE XIETHIOPIC SYLLABLE XAAETHIOPIC SYLLABLE XEEETHIOPIC SYLL" +
"ABLE XEETHIOPIC SYLLABLE XOETHIOPIC SYLLABLE XOAETHIOPIC SYLLABLE XWAETH" +
"IOPIC SYLLABLE XWIETHIOPIC SYLLABLE XWAAETHIOPIC SYLLABLE XWEEETHIOPIC S" +
"YLLABLE XWEETHIOPIC SYLLABLE NAETHIOPIC SYLLABLE NUETHIOPIC SYLLABLE NIE" +
"THIOPIC SYLLABLE NAAETHIOPIC SYLLABLE NEEETHIOPIC SYLLABLE NEETHIOPIC SY" +
"LLABLE NOETHIOPIC SYLLABLE NWAETHIOPIC SYLLABLE NYAETHIOPIC SYLLABLE NYU" +
"ETHIOPIC SYLLABLE NYIETHIOPIC SYLLABLE NYAAETHIOPIC SYLLABLE NYEEETHIOPI" +
"C SYLLABLE NYEETHIOPIC SYLLABLE NYOETHIOPIC SYLLABLE NYWAETHIOPIC SYLLAB" +
"LE GLOTTAL AETHIOPIC SYLLABLE GLOTTAL UETHIOPIC SYLLABLE GLOTTAL IETHIOP") + ("" +
"IC SYLLABLE GLOTTAL AAETHIOPIC SYLLABLE GLOTTAL EEETHIOPIC SYLLABLE GLOT" +
"TAL EETHIOPIC SYLLABLE GLOTTAL OETHIOPIC SYLLABLE GLOTTAL WAETHIOPIC SYL" +
"LABLE KAETHIOPIC SYLLABLE KUETHIOPIC SYLLABLE KIETHIOPIC SYLLABLE KAAETH" +
"IOPIC SYLLABLE KEEETHIOPIC SYLLABLE KEETHIOPIC SYLLABLE KOETHIOPIC SYLLA" +
"BLE KOAETHIOPIC SYLLABLE KWAETHIOPIC SYLLABLE KWIETHIOPIC SYLLABLE KWAAE" +
"THIOPIC SYLLABLE KWEEETHIOPIC SYLLABLE KWEETHIOPIC SYLLABLE KXAETHIOPIC " +
"SYLLABLE KXUETHIOPIC SYLLABLE KXIETHIOPIC SYLLABLE KXAAETHIOPIC SYLLABLE" +
" KXEEETHIOPIC SYLLABLE KXEETHIOPIC SYLLABLE KXOETHIOPIC SYLLABLE KXWAETH" +
"IOPIC SYLLABLE KXWIETHIOPIC SYLLABLE KXWAAETHIOPIC SYLLABLE KXWEEETHIOPI" +
"C SYLLABLE KXWEETHIOPIC SYLLABLE WAETHIOPIC SYLLABLE WUETHIOPIC SYLLABLE" +
" WIETHIOPIC SYLLABLE WAAETHIOPIC SYLLABLE WEEETHIOPIC SYLLABLE WEETHIOPI" +
"C SYLLABLE WOETHIOPIC SYLLABLE WOAETHIOPIC SYLLABLE PHARYNGEAL AETHIOPIC" +
" SYLLABLE PHARYNGEAL UETHIOPIC SYLLABLE PHARYNGEAL IETHIOPIC SYLLABLE PH" +
"ARYNGEAL AAETHIOPIC SYLLABLE PHARYNGEAL EEETHIOPIC SYLLABLE PHARYNGEAL E" +
"ETHIOPIC SYLLABLE PHARYNGEAL OETHIOPIC SYLLABLE ZAETHIOPIC SYLLABLE ZUET" +
"HIOPIC SYLLABLE ZIETHIOPIC SYLLABLE ZAAETHIOPIC SYLLABLE ZEEETHIOPIC SYL" +
"LABLE ZEETHIOPIC SYLLABLE ZOETHIOPIC SYLLABLE ZWAETHIOPIC SYLLABLE ZHAET" +
"HIOPIC SYLLABLE ZHUETHIOPIC SYLLABLE ZHIETHIOPIC SYLLABLE ZHAAETHIOPIC S" +
"YLLABLE ZHEEETHIOPIC SYLLABLE ZHEETHIOPIC SYLLABLE ZHOETHIOPIC SYLLABLE " +
"ZHWAETHIOPIC SYLLABLE YAETHIOPIC SYLLABLE YUETHIOPIC SYLLABLE YIETHIOPIC" +
" SYLLABLE YAAETHIOPIC SYLLABLE YEEETHIOPIC SYLLABLE YEETHIOPIC SYLLABLE " +
"YOETHIOPIC SYLLABLE YOAETHIOPIC SYLLABLE DAETHIOPIC SYLLABLE DUETHIOPIC " +
"SYLLABLE DIETHIOPIC SYLLABLE DAAETHIOPIC SYLLABLE DEEETHIOPIC SYLLABLE D" +
"EETHIOPIC SYLLABLE DOETHIOPIC SYLLABLE DWAETHIOPIC SYLLABLE DDAETHIOPIC " +
"SYLLABLE DDUETHIOPIC SYLLABLE DDIETHIOPIC SYLLABLE DDAAETHIOPIC SYLLABLE" +
" DDEEETHIOPIC SYLLABLE DDEETHIOPIC SYLLABLE DDOETHIOPIC SYLLABLE DDWAETH" +
"IOPIC SYLLABLE JAETHIOPIC SYLLABLE JUETHIOPIC SYLLABLE JIETHIOPIC SYLLAB" +
"LE JAAETHIOPIC SYLLABLE JEEETHIOPIC SYLLABLE JEETHIOPIC SYLLABLE JOETHIO" +
"PIC SYLLABLE JWAETHIOPIC SYLLABLE GAETHIOPIC SYLLABLE GUETHIOPIC SYLLABL" +
"E GIETHIOPIC SYLLABLE GAAETHIOPIC SYLLABLE GEEETHIOPIC SYLLABLE GEETHIOP" +
"IC SYLLABLE GOETHIOPIC SYLLABLE GOAETHIOPIC SYLLABLE GWAETHIOPIC SYLLABL" +
"E GWIETHIOPIC SYLLABLE GWAAETHIOPIC SYLLABLE GWEEETHIOPIC SYLLABLE GWEET" +
"HIOPIC SYLLABLE GGAETHIOPIC SYLLABLE GGUETHIOPIC SYLLABLE GGIETHIOPIC SY" +
"LLABLE GGAAETHIOPIC SYLLABLE GGEEETHIOPIC SYLLABLE GGEETHIOPIC SYLLABLE " +
"GGOETHIOPIC SYLLABLE GGWAAETHIOPIC SYLLABLE THAETHIOPIC SYLLABLE THUETHI" +
"OPIC SYLLABLE THIETHIOPIC SYLLABLE THAAETHIOPIC SYLLABLE THEEETHIOPIC SY" +
"LLABLE THEETHIOPIC SYLLABLE THOETHIOPIC SYLLABLE THWAETHIOPIC SYLLABLE C" +
"HAETHIOPIC SYLLABLE CHUETHIOPIC SYLLABLE CHIETHIOPIC SYLLABLE CHAAETHIOP" +
"IC SYLLABLE CHEEETHIOPIC SYLLABLE CHEETHIOPIC SYLLABLE CHOETHIOPIC SYLLA" +
"BLE CHWAETHIOPIC SYLLABLE PHAETHIOPIC SYLLABLE PHUETHIOPIC SYLLABLE PHIE" +
"THIOPIC SYLLABLE PHAAETHIOPIC SYLLABLE PHEEETHIOPIC SYLLABLE PHEETHIOPIC" +
" SYLLABLE PHOETHIOPIC SYLLABLE PHWAETHIOPIC SYLLABLE TSAETHIOPIC SYLLABL" +
"E TSUETHIOPIC SYLLABLE TSIETHIOPIC SYLLABLE TSAAETHIOPIC SYLLABLE TSEEET" +
"HIOPIC SYLLABLE TSEETHIOPIC SYLLABLE TSOETHIOPIC SYLLABLE TSWAETHIOPIC S" +
"YLLABLE TZAETHIOPIC SYLLABLE TZUETHIOPIC SYLLABLE TZIETHIOPIC SYLLABLE T" +
"ZAAETHIOPIC SYLLABLE TZEEETHIOPIC SYLLABLE TZEETHIOPIC SYLLABLE TZOETHIO" +
"PIC SYLLABLE TZOAETHIOPIC SYLLABLE FAETHIOPIC SYLLABLE FUETHIOPIC SYLLAB" +
"LE FIETHIOPIC SYLLABLE FAAETHIOPIC SYLLABLE FEEETHIOPIC SYLLABLE FEETHIO" +
"PIC SYLLABLE FOETHIOPIC SYLLABLE FWAETHIOPIC SYLLABLE PAETHIOPIC SYLLABL" +
"E PUETHIOPIC SYLLABLE PIETHIOPIC SYLLABLE PAAETHIOPIC SYLLABLE PEEETHIOP" +
"IC SYLLABLE PEETHIOPIC SYLLABLE POETHIOPIC SYLLABLE PWAETHIOPIC SYLLABLE" +
" RYAETHIOPIC SYLLABLE MYAETHIOPIC SYLLABLE FYAETHIOPIC COMBINING GEMINAT" +
"ION AND VOWEL LENGTH MARKETHIOPIC COMBINING VOWEL LENGTH MARKETHIOPIC CO" +
"MBINING GEMINATION MARKETHIOPIC SECTION MARKETHIOPIC WORDSPACEETHIOPIC F" +
"ULL STOPETHIOPIC COMMAETHIOPIC SEMICOLONETHIOPIC COLONETHIOPIC PREFACE C" +
"OLONETHIOPIC QUESTION MARKETHIOPIC PARAGRAPH SEPARATORETHIOPIC DIGIT ONE" +
"ETHIOPIC DIGIT TWOETHIOPIC DIGIT THREEETHIOPIC DIGIT FOURETHIOPIC DIGIT " +
"FIVEETHIOPIC DIGIT SIXETHIOPIC DIGIT SEVENETHIOPIC DIGIT EIGHTETHIOPIC D" +
"IGIT NINEETHIOPIC NUMBER TENETHIOPIC NUMBER TWENTYETHIOPIC NUMBER THIRTY" +
"ETHIOPIC NUMBER FORTYETHIOPIC NUMBER FIFTYETHIOPIC NUMBER SIXTYETHIOPIC " +
"NUMBER SEVENTYETHIOPIC NUMBER EIGHTYETHIOPIC NUMBER NINETYETHIOPIC NUMBE" +
"R HUNDREDETHIOPIC NUMBER TEN THOUSANDETHIOPIC SYLLABLE SEBATBEIT MWAETHI" +
"OPIC SYLLABLE MWIETHIOPIC SYLLABLE MWEEETHIOPIC SYLLABLE MWEETHIOPIC SYL" +
"LABLE SEBATBEIT BWAETHIOPIC SYLLABLE BWIETHIOPIC SYLLABLE BWEEETHIOPIC S") + ("" +
"YLLABLE BWEETHIOPIC SYLLABLE SEBATBEIT FWAETHIOPIC SYLLABLE FWIETHIOPIC " +
"SYLLABLE FWEEETHIOPIC SYLLABLE FWEETHIOPIC SYLLABLE SEBATBEIT PWAETHIOPI" +
"C SYLLABLE PWIETHIOPIC SYLLABLE PWEEETHIOPIC SYLLABLE PWEETHIOPIC TONAL " +
"MARK YIZETETHIOPIC TONAL MARK DERETETHIOPIC TONAL MARK RIKRIKETHIOPIC TO" +
"NAL MARK SHORT RIKRIKETHIOPIC TONAL MARK DIFATETHIOPIC TONAL MARK KENATE" +
"THIOPIC TONAL MARK CHIRETETHIOPIC TONAL MARK HIDETETHIOPIC TONAL MARK DE" +
"RET-HIDETETHIOPIC TONAL MARK KURTCHEROKEE LETTER ACHEROKEE LETTER ECHERO" +
"KEE LETTER ICHEROKEE LETTER OCHEROKEE LETTER UCHEROKEE LETTER VCHEROKEE " +
"LETTER GACHEROKEE LETTER KACHEROKEE LETTER GECHEROKEE LETTER GICHEROKEE " +
"LETTER GOCHEROKEE LETTER GUCHEROKEE LETTER GVCHEROKEE LETTER HACHEROKEE " +
"LETTER HECHEROKEE LETTER HICHEROKEE LETTER HOCHEROKEE LETTER HUCHEROKEE " +
"LETTER HVCHEROKEE LETTER LACHEROKEE LETTER LECHEROKEE LETTER LICHEROKEE " +
"LETTER LOCHEROKEE LETTER LUCHEROKEE LETTER LVCHEROKEE LETTER MACHEROKEE " +
"LETTER MECHEROKEE LETTER MICHEROKEE LETTER MOCHEROKEE LETTER MUCHEROKEE " +
"LETTER NACHEROKEE LETTER HNACHEROKEE LETTER NAHCHEROKEE LETTER NECHEROKE" +
"E LETTER NICHEROKEE LETTER NOCHEROKEE LETTER NUCHEROKEE LETTER NVCHEROKE" +
"E LETTER QUACHEROKEE LETTER QUECHEROKEE LETTER QUICHEROKEE LETTER QUOCHE" +
"ROKEE LETTER QUUCHEROKEE LETTER QUVCHEROKEE LETTER SACHEROKEE LETTER SCH" +
"EROKEE LETTER SECHEROKEE LETTER SICHEROKEE LETTER SOCHEROKEE LETTER SUCH" +
"EROKEE LETTER SVCHEROKEE LETTER DACHEROKEE LETTER TACHEROKEE LETTER DECH" +
"EROKEE LETTER TECHEROKEE LETTER DICHEROKEE LETTER TICHEROKEE LETTER DOCH" +
"EROKEE LETTER DUCHEROKEE LETTER DVCHEROKEE LETTER DLACHEROKEE LETTER TLA" +
"CHEROKEE LETTER TLECHEROKEE LETTER TLICHEROKEE LETTER TLOCHEROKEE LETTER" +
" TLUCHEROKEE LETTER TLVCHEROKEE LETTER TSACHEROKEE LETTER TSECHEROKEE LE" +
"TTER TSICHEROKEE LETTER TSOCHEROKEE LETTER TSUCHEROKEE LETTER TSVCHEROKE" +
"E LETTER WACHEROKEE LETTER WECHEROKEE LETTER WICHEROKEE LETTER WOCHEROKE" +
"E LETTER WUCHEROKEE LETTER WVCHEROKEE LETTER YACHEROKEE LETTER YECHEROKE" +
"E LETTER YICHEROKEE LETTER YOCHEROKEE LETTER YUCHEROKEE LETTER YVCHEROKE" +
"E LETTER MVCHEROKEE SMALL LETTER YECHEROKEE SMALL LETTER YICHEROKEE SMAL" +
"L LETTER YOCHEROKEE SMALL LETTER YUCHEROKEE SMALL LETTER YVCHEROKEE SMAL" +
"L LETTER MVCANADIAN SYLLABICS HYPHENCANADIAN SYLLABICS ECANADIAN SYLLABI" +
"CS AAICANADIAN SYLLABICS ICANADIAN SYLLABICS IICANADIAN SYLLABICS OCANAD" +
"IAN SYLLABICS OOCANADIAN SYLLABICS Y-CREE OOCANADIAN SYLLABICS CARRIER E" +
"ECANADIAN SYLLABICS CARRIER ICANADIAN SYLLABICS ACANADIAN SYLLABICS AACA" +
"NADIAN SYLLABICS WECANADIAN SYLLABICS WEST-CREE WECANADIAN SYLLABICS WIC" +
"ANADIAN SYLLABICS WEST-CREE WICANADIAN SYLLABICS WIICANADIAN SYLLABICS W" +
"EST-CREE WIICANADIAN SYLLABICS WOCANADIAN SYLLABICS WEST-CREE WOCANADIAN" +
" SYLLABICS WOOCANADIAN SYLLABICS WEST-CREE WOOCANADIAN SYLLABICS NASKAPI" +
" WOOCANADIAN SYLLABICS WACANADIAN SYLLABICS WEST-CREE WACANADIAN SYLLABI" +
"CS WAACANADIAN SYLLABICS WEST-CREE WAACANADIAN SYLLABICS NASKAPI WAACANA" +
"DIAN SYLLABICS AICANADIAN SYLLABICS Y-CREE WCANADIAN SYLLABICS GLOTTAL S" +
"TOPCANADIAN SYLLABICS FINAL ACUTECANADIAN SYLLABICS FINAL GRAVECANADIAN " +
"SYLLABICS FINAL BOTTOM HALF RINGCANADIAN SYLLABICS FINAL TOP HALF RINGCA" +
"NADIAN SYLLABICS FINAL RIGHT HALF RINGCANADIAN SYLLABICS FINAL RINGCANAD" +
"IAN SYLLABICS FINAL DOUBLE ACUTECANADIAN SYLLABICS FINAL DOUBLE SHORT VE" +
"RTICAL STROKESCANADIAN SYLLABICS FINAL MIDDLE DOTCANADIAN SYLLABICS FINA" +
"L SHORT HORIZONTAL STROKECANADIAN SYLLABICS FINAL PLUSCANADIAN SYLLABICS" +
" FINAL DOWN TACKCANADIAN SYLLABICS ENCANADIAN SYLLABICS INCANADIAN SYLLA" +
"BICS ONCANADIAN SYLLABICS ANCANADIAN SYLLABICS PECANADIAN SYLLABICS PAAI" +
"CANADIAN SYLLABICS PICANADIAN SYLLABICS PIICANADIAN SYLLABICS POCANADIAN" +
" SYLLABICS POOCANADIAN SYLLABICS Y-CREE POOCANADIAN SYLLABICS CARRIER HE" +
"ECANADIAN SYLLABICS CARRIER HICANADIAN SYLLABICS PACANADIAN SYLLABICS PA" +
"ACANADIAN SYLLABICS PWECANADIAN SYLLABICS WEST-CREE PWECANADIAN SYLLABIC" +
"S PWICANADIAN SYLLABICS WEST-CREE PWICANADIAN SYLLABICS PWIICANADIAN SYL" +
"LABICS WEST-CREE PWIICANADIAN SYLLABICS PWOCANADIAN SYLLABICS WEST-CREE " +
"PWOCANADIAN SYLLABICS PWOOCANADIAN SYLLABICS WEST-CREE PWOOCANADIAN SYLL" +
"ABICS PWACANADIAN SYLLABICS WEST-CREE PWACANADIAN SYLLABICS PWAACANADIAN" +
" SYLLABICS WEST-CREE PWAACANADIAN SYLLABICS Y-CREE PWAACANADIAN SYLLABIC" +
"S PCANADIAN SYLLABICS WEST-CREE PCANADIAN SYLLABICS CARRIER HCANADIAN SY" +
"LLABICS TECANADIAN SYLLABICS TAAICANADIAN SYLLABICS TICANADIAN SYLLABICS" +
" TIICANADIAN SYLLABICS TOCANADIAN SYLLABICS TOOCANADIAN SYLLABICS Y-CREE" +
" TOOCANADIAN SYLLABICS CARRIER DEECANADIAN SYLLABICS CARRIER DICANADIAN " +
"SYLLABICS TACANADIAN SYLLABICS TAACANADIAN SYLLABICS TWECANADIAN SYLLABI" +
"CS WEST-CREE TWECANADIAN SYLLABICS TWICANADIAN SYLLABICS WEST-CREE TWICA") + ("" +
"NADIAN SYLLABICS TWIICANADIAN SYLLABICS WEST-CREE TWIICANADIAN SYLLABICS" +
" TWOCANADIAN SYLLABICS WEST-CREE TWOCANADIAN SYLLABICS TWOOCANADIAN SYLL" +
"ABICS WEST-CREE TWOOCANADIAN SYLLABICS TWACANADIAN SYLLABICS WEST-CREE T" +
"WACANADIAN SYLLABICS TWAACANADIAN SYLLABICS WEST-CREE TWAACANADIAN SYLLA" +
"BICS NASKAPI TWAACANADIAN SYLLABICS TCANADIAN SYLLABICS TTECANADIAN SYLL" +
"ABICS TTICANADIAN SYLLABICS TTOCANADIAN SYLLABICS TTACANADIAN SYLLABICS " +
"KECANADIAN SYLLABICS KAAICANADIAN SYLLABICS KICANADIAN SYLLABICS KIICANA" +
"DIAN SYLLABICS KOCANADIAN SYLLABICS KOOCANADIAN SYLLABICS Y-CREE KOOCANA" +
"DIAN SYLLABICS KACANADIAN SYLLABICS KAACANADIAN SYLLABICS KWECANADIAN SY" +
"LLABICS WEST-CREE KWECANADIAN SYLLABICS KWICANADIAN SYLLABICS WEST-CREE " +
"KWICANADIAN SYLLABICS KWIICANADIAN SYLLABICS WEST-CREE KWIICANADIAN SYLL" +
"ABICS KWOCANADIAN SYLLABICS WEST-CREE KWOCANADIAN SYLLABICS KWOOCANADIAN" +
" SYLLABICS WEST-CREE KWOOCANADIAN SYLLABICS KWACANADIAN SYLLABICS WEST-C" +
"REE KWACANADIAN SYLLABICS KWAACANADIAN SYLLABICS WEST-CREE KWAACANADIAN " +
"SYLLABICS NASKAPI KWAACANADIAN SYLLABICS KCANADIAN SYLLABICS KWCANADIAN " +
"SYLLABICS SOUTH-SLAVEY KEHCANADIAN SYLLABICS SOUTH-SLAVEY KIHCANADIAN SY" +
"LLABICS SOUTH-SLAVEY KOHCANADIAN SYLLABICS SOUTH-SLAVEY KAHCANADIAN SYLL" +
"ABICS CECANADIAN SYLLABICS CAAICANADIAN SYLLABICS CICANADIAN SYLLABICS C" +
"IICANADIAN SYLLABICS COCANADIAN SYLLABICS COOCANADIAN SYLLABICS Y-CREE C" +
"OOCANADIAN SYLLABICS CACANADIAN SYLLABICS CAACANADIAN SYLLABICS CWECANAD" +
"IAN SYLLABICS WEST-CREE CWECANADIAN SYLLABICS CWICANADIAN SYLLABICS WEST" +
"-CREE CWICANADIAN SYLLABICS CWIICANADIAN SYLLABICS WEST-CREE CWIICANADIA" +
"N SYLLABICS CWOCANADIAN SYLLABICS WEST-CREE CWOCANADIAN SYLLABICS CWOOCA" +
"NADIAN SYLLABICS WEST-CREE CWOOCANADIAN SYLLABICS CWACANADIAN SYLLABICS " +
"WEST-CREE CWACANADIAN SYLLABICS CWAACANADIAN SYLLABICS WEST-CREE CWAACAN" +
"ADIAN SYLLABICS NASKAPI CWAACANADIAN SYLLABICS CCANADIAN SYLLABICS SAYIS" +
"I THCANADIAN SYLLABICS MECANADIAN SYLLABICS MAAICANADIAN SYLLABICS MICAN" +
"ADIAN SYLLABICS MIICANADIAN SYLLABICS MOCANADIAN SYLLABICS MOOCANADIAN S" +
"YLLABICS Y-CREE MOOCANADIAN SYLLABICS MACANADIAN SYLLABICS MAACANADIAN S" +
"YLLABICS MWECANADIAN SYLLABICS WEST-CREE MWECANADIAN SYLLABICS MWICANADI" +
"AN SYLLABICS WEST-CREE MWICANADIAN SYLLABICS MWIICANADIAN SYLLABICS WEST" +
"-CREE MWIICANADIAN SYLLABICS MWOCANADIAN SYLLABICS WEST-CREE MWOCANADIAN" +
" SYLLABICS MWOOCANADIAN SYLLABICS WEST-CREE MWOOCANADIAN SYLLABICS MWACA" +
"NADIAN SYLLABICS WEST-CREE MWACANADIAN SYLLABICS MWAACANADIAN SYLLABICS " +
"WEST-CREE MWAACANADIAN SYLLABICS NASKAPI MWAACANADIAN SYLLABICS MCANADIA" +
"N SYLLABICS WEST-CREE MCANADIAN SYLLABICS MHCANADIAN SYLLABICS ATHAPASCA" +
"N MCANADIAN SYLLABICS SAYISI MCANADIAN SYLLABICS NECANADIAN SYLLABICS NA" +
"AICANADIAN SYLLABICS NICANADIAN SYLLABICS NIICANADIAN SYLLABICS NOCANADI" +
"AN SYLLABICS NOOCANADIAN SYLLABICS Y-CREE NOOCANADIAN SYLLABICS NACANADI" +
"AN SYLLABICS NAACANADIAN SYLLABICS NWECANADIAN SYLLABICS WEST-CREE NWECA" +
"NADIAN SYLLABICS NWACANADIAN SYLLABICS WEST-CREE NWACANADIAN SYLLABICS N" +
"WAACANADIAN SYLLABICS WEST-CREE NWAACANADIAN SYLLABICS NASKAPI NWAACANAD" +
"IAN SYLLABICS NCANADIAN SYLLABICS CARRIER NGCANADIAN SYLLABICS NHCANADIA" +
"N SYLLABICS LECANADIAN SYLLABICS LAAICANADIAN SYLLABICS LICANADIAN SYLLA" +
"BICS LIICANADIAN SYLLABICS LOCANADIAN SYLLABICS LOOCANADIAN SYLLABICS Y-" +
"CREE LOOCANADIAN SYLLABICS LACANADIAN SYLLABICS LAACANADIAN SYLLABICS LW" +
"ECANADIAN SYLLABICS WEST-CREE LWECANADIAN SYLLABICS LWICANADIAN SYLLABIC" +
"S WEST-CREE LWICANADIAN SYLLABICS LWIICANADIAN SYLLABICS WEST-CREE LWIIC" +
"ANADIAN SYLLABICS LWOCANADIAN SYLLABICS WEST-CREE LWOCANADIAN SYLLABICS " +
"LWOOCANADIAN SYLLABICS WEST-CREE LWOOCANADIAN SYLLABICS LWACANADIAN SYLL" +
"ABICS WEST-CREE LWACANADIAN SYLLABICS LWAACANADIAN SYLLABICS WEST-CREE L" +
"WAACANADIAN SYLLABICS LCANADIAN SYLLABICS WEST-CREE LCANADIAN SYLLABICS " +
"MEDIAL LCANADIAN SYLLABICS SECANADIAN SYLLABICS SAAICANADIAN SYLLABICS S" +
"ICANADIAN SYLLABICS SIICANADIAN SYLLABICS SOCANADIAN SYLLABICS SOOCANADI" +
"AN SYLLABICS Y-CREE SOOCANADIAN SYLLABICS SACANADIAN SYLLABICS SAACANADI" +
"AN SYLLABICS SWECANADIAN SYLLABICS WEST-CREE SWECANADIAN SYLLABICS SWICA" +
"NADIAN SYLLABICS WEST-CREE SWICANADIAN SYLLABICS SWIICANADIAN SYLLABICS " +
"WEST-CREE SWIICANADIAN SYLLABICS SWOCANADIAN SYLLABICS WEST-CREE SWOCANA" +
"DIAN SYLLABICS SWOOCANADIAN SYLLABICS WEST-CREE SWOOCANADIAN SYLLABICS S" +
"WACANADIAN SYLLABICS WEST-CREE SWACANADIAN SYLLABICS SWAACANADIAN SYLLAB" +
"ICS WEST-CREE SWAACANADIAN SYLLABICS NASKAPI SWAACANADIAN SYLLABICS SCAN" +
"ADIAN SYLLABICS ATHAPASCAN SCANADIAN SYLLABICS SWCANADIAN SYLLABICS BLAC" +
"KFOOT SCANADIAN SYLLABICS MOOSE-CREE SKCANADIAN SYLLABICS NASKAPI SKWCAN" +
"ADIAN SYLLABICS NASKAPI S-WCANADIAN SYLLABICS NASKAPI SPWACANADIAN SYLLA") + ("" +
"BICS NASKAPI STWACANADIAN SYLLABICS NASKAPI SKWACANADIAN SYLLABICS NASKA" +
"PI SCWACANADIAN SYLLABICS SHECANADIAN SYLLABICS SHICANADIAN SYLLABICS SH" +
"IICANADIAN SYLLABICS SHOCANADIAN SYLLABICS SHOOCANADIAN SYLLABICS SHACAN" +
"ADIAN SYLLABICS SHAACANADIAN SYLLABICS SHWECANADIAN SYLLABICS WEST-CREE " +
"SHWECANADIAN SYLLABICS SHWICANADIAN SYLLABICS WEST-CREE SHWICANADIAN SYL" +
"LABICS SHWIICANADIAN SYLLABICS WEST-CREE SHWIICANADIAN SYLLABICS SHWOCAN" +
"ADIAN SYLLABICS WEST-CREE SHWOCANADIAN SYLLABICS SHWOOCANADIAN SYLLABICS" +
" WEST-CREE SHWOOCANADIAN SYLLABICS SHWACANADIAN SYLLABICS WEST-CREE SHWA" +
"CANADIAN SYLLABICS SHWAACANADIAN SYLLABICS WEST-CREE SHWAACANADIAN SYLLA" +
"BICS SHCANADIAN SYLLABICS YECANADIAN SYLLABICS YAAICANADIAN SYLLABICS YI" +
"CANADIAN SYLLABICS YIICANADIAN SYLLABICS YOCANADIAN SYLLABICS YOOCANADIA" +
"N SYLLABICS Y-CREE YOOCANADIAN SYLLABICS YACANADIAN SYLLABICS YAACANADIA" +
"N SYLLABICS YWECANADIAN SYLLABICS WEST-CREE YWECANADIAN SYLLABICS YWICAN" +
"ADIAN SYLLABICS WEST-CREE YWICANADIAN SYLLABICS YWIICANADIAN SYLLABICS W" +
"EST-CREE YWIICANADIAN SYLLABICS YWOCANADIAN SYLLABICS WEST-CREE YWOCANAD" +
"IAN SYLLABICS YWOOCANADIAN SYLLABICS WEST-CREE YWOOCANADIAN SYLLABICS YW" +
"ACANADIAN SYLLABICS WEST-CREE YWACANADIAN SYLLABICS YWAACANADIAN SYLLABI" +
"CS WEST-CREE YWAACANADIAN SYLLABICS NASKAPI YWAACANADIAN SYLLABICS YCANA" +
"DIAN SYLLABICS BIBLE-CREE YCANADIAN SYLLABICS WEST-CREE YCANADIAN SYLLAB" +
"ICS SAYISI YICANADIAN SYLLABICS RECANADIAN SYLLABICS R-CREE RECANADIAN S" +
"YLLABICS WEST-CREE LECANADIAN SYLLABICS RAAICANADIAN SYLLABICS RICANADIA" +
"N SYLLABICS RIICANADIAN SYLLABICS ROCANADIAN SYLLABICS ROOCANADIAN SYLLA" +
"BICS WEST-CREE LOCANADIAN SYLLABICS RACANADIAN SYLLABICS RAACANADIAN SYL" +
"LABICS WEST-CREE LACANADIAN SYLLABICS RWAACANADIAN SYLLABICS WEST-CREE R" +
"WAACANADIAN SYLLABICS RCANADIAN SYLLABICS WEST-CREE RCANADIAN SYLLABICS " +
"MEDIAL RCANADIAN SYLLABICS FECANADIAN SYLLABICS FAAICANADIAN SYLLABICS F" +
"ICANADIAN SYLLABICS FIICANADIAN SYLLABICS FOCANADIAN SYLLABICS FOOCANADI" +
"AN SYLLABICS FACANADIAN SYLLABICS FAACANADIAN SYLLABICS FWAACANADIAN SYL" +
"LABICS WEST-CREE FWAACANADIAN SYLLABICS FCANADIAN SYLLABICS THECANADIAN " +
"SYLLABICS N-CREE THECANADIAN SYLLABICS THICANADIAN SYLLABICS N-CREE THIC" +
"ANADIAN SYLLABICS THIICANADIAN SYLLABICS N-CREE THIICANADIAN SYLLABICS T" +
"HOCANADIAN SYLLABICS THOOCANADIAN SYLLABICS THACANADIAN SYLLABICS THAACA" +
"NADIAN SYLLABICS THWAACANADIAN SYLLABICS WEST-CREE THWAACANADIAN SYLLABI" +
"CS THCANADIAN SYLLABICS TTHECANADIAN SYLLABICS TTHICANADIAN SYLLABICS TT" +
"HOCANADIAN SYLLABICS TTHACANADIAN SYLLABICS TTHCANADIAN SYLLABICS TYECAN" +
"ADIAN SYLLABICS TYICANADIAN SYLLABICS TYOCANADIAN SYLLABICS TYACANADIAN " +
"SYLLABICS NUNAVIK HECANADIAN SYLLABICS NUNAVIK HICANADIAN SYLLABICS NUNA" +
"VIK HIICANADIAN SYLLABICS NUNAVIK HOCANADIAN SYLLABICS NUNAVIK HOOCANADI" +
"AN SYLLABICS NUNAVIK HACANADIAN SYLLABICS NUNAVIK HAACANADIAN SYLLABICS " +
"NUNAVIK HCANADIAN SYLLABICS NUNAVUT HCANADIAN SYLLABICS HKCANADIAN SYLLA" +
"BICS QAAICANADIAN SYLLABICS QICANADIAN SYLLABICS QIICANADIAN SYLLABICS Q" +
"OCANADIAN SYLLABICS QOOCANADIAN SYLLABICS QACANADIAN SYLLABICS QAACANADI" +
"AN SYLLABICS QCANADIAN SYLLABICS TLHECANADIAN SYLLABICS TLHICANADIAN SYL" +
"LABICS TLHOCANADIAN SYLLABICS TLHACANADIAN SYLLABICS WEST-CREE RECANADIA" +
"N SYLLABICS WEST-CREE RICANADIAN SYLLABICS WEST-CREE ROCANADIAN SYLLABIC" +
"S WEST-CREE RACANADIAN SYLLABICS NGAAICANADIAN SYLLABICS NGICANADIAN SYL" +
"LABICS NGIICANADIAN SYLLABICS NGOCANADIAN SYLLABICS NGOOCANADIAN SYLLABI" +
"CS NGACANADIAN SYLLABICS NGAACANADIAN SYLLABICS NGCANADIAN SYLLABICS NNG" +
"CANADIAN SYLLABICS SAYISI SHECANADIAN SYLLABICS SAYISI SHICANADIAN SYLLA" +
"BICS SAYISI SHOCANADIAN SYLLABICS SAYISI SHACANADIAN SYLLABICS WOODS-CRE" +
"E THECANADIAN SYLLABICS WOODS-CREE THICANADIAN SYLLABICS WOODS-CREE THOC" +
"ANADIAN SYLLABICS WOODS-CREE THACANADIAN SYLLABICS WOODS-CREE THCANADIAN" +
" SYLLABICS LHICANADIAN SYLLABICS LHIICANADIAN SYLLABICS LHOCANADIAN SYLL" +
"ABICS LHOOCANADIAN SYLLABICS LHACANADIAN SYLLABICS LHAACANADIAN SYLLABIC" +
"S LHCANADIAN SYLLABICS TH-CREE THECANADIAN SYLLABICS TH-CREE THICANADIAN" +
" SYLLABICS TH-CREE THIICANADIAN SYLLABICS TH-CREE THOCANADIAN SYLLABICS " +
"TH-CREE THOOCANADIAN SYLLABICS TH-CREE THACANADIAN SYLLABICS TH-CREE THA" +
"ACANADIAN SYLLABICS TH-CREE THCANADIAN SYLLABICS AIVILIK BCANADIAN SYLLA" +
"BICS BLACKFOOT ECANADIAN SYLLABICS BLACKFOOT ICANADIAN SYLLABICS BLACKFO" +
"OT OCANADIAN SYLLABICS BLACKFOOT ACANADIAN SYLLABICS BLACKFOOT WECANADIA" +
"N SYLLABICS BLACKFOOT WICANADIAN SYLLABICS BLACKFOOT WOCANADIAN SYLLABIC" +
"S BLACKFOOT WACANADIAN SYLLABICS BLACKFOOT NECANADIAN SYLLABICS BLACKFOO" +
"T NICANADIAN SYLLABICS BLACKFOOT NOCANADIAN SYLLABICS BLACKFOOT NACANADI" +
"AN SYLLABICS BLACKFOOT KECANADIAN SYLLABICS BLACKFOOT KICANADIAN SYLLABI") + ("" +
"CS BLACKFOOT KOCANADIAN SYLLABICS BLACKFOOT KACANADIAN SYLLABICS SAYISI " +
"HECANADIAN SYLLABICS SAYISI HICANADIAN SYLLABICS SAYISI HOCANADIAN SYLLA" +
"BICS SAYISI HACANADIAN SYLLABICS CARRIER GHUCANADIAN SYLLABICS CARRIER G" +
"HOCANADIAN SYLLABICS CARRIER GHECANADIAN SYLLABICS CARRIER GHEECANADIAN " +
"SYLLABICS CARRIER GHICANADIAN SYLLABICS CARRIER GHACANADIAN SYLLABICS CA" +
"RRIER RUCANADIAN SYLLABICS CARRIER ROCANADIAN SYLLABICS CARRIER RECANADI" +
"AN SYLLABICS CARRIER REECANADIAN SYLLABICS CARRIER RICANADIAN SYLLABICS " +
"CARRIER RACANADIAN SYLLABICS CARRIER WUCANADIAN SYLLABICS CARRIER WOCANA" +
"DIAN SYLLABICS CARRIER WECANADIAN SYLLABICS CARRIER WEECANADIAN SYLLABIC" +
"S CARRIER WICANADIAN SYLLABICS CARRIER WACANADIAN SYLLABICS CARRIER HWUC" +
"ANADIAN SYLLABICS CARRIER HWOCANADIAN SYLLABICS CARRIER HWECANADIAN SYLL" +
"ABICS CARRIER HWEECANADIAN SYLLABICS CARRIER HWICANADIAN SYLLABICS CARRI" +
"ER HWACANADIAN SYLLABICS CARRIER THUCANADIAN SYLLABICS CARRIER THOCANADI" +
"AN SYLLABICS CARRIER THECANADIAN SYLLABICS CARRIER THEECANADIAN SYLLABIC" +
"S CARRIER THICANADIAN SYLLABICS CARRIER THACANADIAN SYLLABICS CARRIER TT" +
"UCANADIAN SYLLABICS CARRIER TTOCANADIAN SYLLABICS CARRIER TTECANADIAN SY" +
"LLABICS CARRIER TTEECANADIAN SYLLABICS CARRIER TTICANADIAN SYLLABICS CAR" +
"RIER TTACANADIAN SYLLABICS CARRIER PUCANADIAN SYLLABICS CARRIER POCANADI" +
"AN SYLLABICS CARRIER PECANADIAN SYLLABICS CARRIER PEECANADIAN SYLLABICS " +
"CARRIER PICANADIAN SYLLABICS CARRIER PACANADIAN SYLLABICS CARRIER PCANAD" +
"IAN SYLLABICS CARRIER GUCANADIAN SYLLABICS CARRIER GOCANADIAN SYLLABICS " +
"CARRIER GECANADIAN SYLLABICS CARRIER GEECANADIAN SYLLABICS CARRIER GICAN" +
"ADIAN SYLLABICS CARRIER GACANADIAN SYLLABICS CARRIER KHUCANADIAN SYLLABI" +
"CS CARRIER KHOCANADIAN SYLLABICS CARRIER KHECANADIAN SYLLABICS CARRIER K" +
"HEECANADIAN SYLLABICS CARRIER KHICANADIAN SYLLABICS CARRIER KHACANADIAN " +
"SYLLABICS CARRIER KKUCANADIAN SYLLABICS CARRIER KKOCANADIAN SYLLABICS CA" +
"RRIER KKECANADIAN SYLLABICS CARRIER KKEECANADIAN SYLLABICS CARRIER KKICA" +
"NADIAN SYLLABICS CARRIER KKACANADIAN SYLLABICS CARRIER KKCANADIAN SYLLAB" +
"ICS CARRIER NUCANADIAN SYLLABICS CARRIER NOCANADIAN SYLLABICS CARRIER NE" +
"CANADIAN SYLLABICS CARRIER NEECANADIAN SYLLABICS CARRIER NICANADIAN SYLL" +
"ABICS CARRIER NACANADIAN SYLLABICS CARRIER MUCANADIAN SYLLABICS CARRIER " +
"MOCANADIAN SYLLABICS CARRIER MECANADIAN SYLLABICS CARRIER MEECANADIAN SY" +
"LLABICS CARRIER MICANADIAN SYLLABICS CARRIER MACANADIAN SYLLABICS CARRIE" +
"R YUCANADIAN SYLLABICS CARRIER YOCANADIAN SYLLABICS CARRIER YECANADIAN S" +
"YLLABICS CARRIER YEECANADIAN SYLLABICS CARRIER YICANADIAN SYLLABICS CARR" +
"IER YACANADIAN SYLLABICS CARRIER JUCANADIAN SYLLABICS SAYISI JUCANADIAN " +
"SYLLABICS CARRIER JOCANADIAN SYLLABICS CARRIER JECANADIAN SYLLABICS CARR" +
"IER JEECANADIAN SYLLABICS CARRIER JICANADIAN SYLLABICS SAYISI JICANADIAN" +
" SYLLABICS CARRIER JACANADIAN SYLLABICS CARRIER JJUCANADIAN SYLLABICS CA" +
"RRIER JJOCANADIAN SYLLABICS CARRIER JJECANADIAN SYLLABICS CARRIER JJEECA" +
"NADIAN SYLLABICS CARRIER JJICANADIAN SYLLABICS CARRIER JJACANADIAN SYLLA" +
"BICS CARRIER LUCANADIAN SYLLABICS CARRIER LOCANADIAN SYLLABICS CARRIER L" +
"ECANADIAN SYLLABICS CARRIER LEECANADIAN SYLLABICS CARRIER LICANADIAN SYL" +
"LABICS CARRIER LACANADIAN SYLLABICS CARRIER DLUCANADIAN SYLLABICS CARRIE" +
"R DLOCANADIAN SYLLABICS CARRIER DLECANADIAN SYLLABICS CARRIER DLEECANADI" +
"AN SYLLABICS CARRIER DLICANADIAN SYLLABICS CARRIER DLACANADIAN SYLLABICS" +
" CARRIER LHUCANADIAN SYLLABICS CARRIER LHOCANADIAN SYLLABICS CARRIER LHE" +
"CANADIAN SYLLABICS CARRIER LHEECANADIAN SYLLABICS CARRIER LHICANADIAN SY" +
"LLABICS CARRIER LHACANADIAN SYLLABICS CARRIER TLHUCANADIAN SYLLABICS CAR" +
"RIER TLHOCANADIAN SYLLABICS CARRIER TLHECANADIAN SYLLABICS CARRIER TLHEE" +
"CANADIAN SYLLABICS CARRIER TLHICANADIAN SYLLABICS CARRIER TLHACANADIAN S" +
"YLLABICS CARRIER TLUCANADIAN SYLLABICS CARRIER TLOCANADIAN SYLLABICS CAR" +
"RIER TLECANADIAN SYLLABICS CARRIER TLEECANADIAN SYLLABICS CARRIER TLICAN" +
"ADIAN SYLLABICS CARRIER TLACANADIAN SYLLABICS CARRIER ZUCANADIAN SYLLABI" +
"CS CARRIER ZOCANADIAN SYLLABICS CARRIER ZECANADIAN SYLLABICS CARRIER ZEE" +
"CANADIAN SYLLABICS CARRIER ZICANADIAN SYLLABICS CARRIER ZACANADIAN SYLLA" +
"BICS CARRIER ZCANADIAN SYLLABICS CARRIER INITIAL ZCANADIAN SYLLABICS CAR" +
"RIER DZUCANADIAN SYLLABICS CARRIER DZOCANADIAN SYLLABICS CARRIER DZECANA" +
"DIAN SYLLABICS CARRIER DZEECANADIAN SYLLABICS CARRIER DZICANADIAN SYLLAB" +
"ICS CARRIER DZACANADIAN SYLLABICS CARRIER SUCANADIAN SYLLABICS CARRIER S" +
"OCANADIAN SYLLABICS CARRIER SECANADIAN SYLLABICS CARRIER SEECANADIAN SYL" +
"LABICS CARRIER SICANADIAN SYLLABICS CARRIER SACANADIAN SYLLABICS CARRIER" +
" SHUCANADIAN SYLLABICS CARRIER SHOCANADIAN SYLLABICS CARRIER SHECANADIAN" +
" SYLLABICS CARRIER SHEECANADIAN SYLLABICS CARRIER SHICANADIAN SYLLABICS ") + ("" +
"CARRIER SHACANADIAN SYLLABICS CARRIER SHCANADIAN SYLLABICS CARRIER TSUCA" +
"NADIAN SYLLABICS CARRIER TSOCANADIAN SYLLABICS CARRIER TSECANADIAN SYLLA" +
"BICS CARRIER TSEECANADIAN SYLLABICS CARRIER TSICANADIAN SYLLABICS CARRIE" +
"R TSACANADIAN SYLLABICS CARRIER CHUCANADIAN SYLLABICS CARRIER CHOCANADIA" +
"N SYLLABICS CARRIER CHECANADIAN SYLLABICS CARRIER CHEECANADIAN SYLLABICS" +
" CARRIER CHICANADIAN SYLLABICS CARRIER CHACANADIAN SYLLABICS CARRIER TTS" +
"UCANADIAN SYLLABICS CARRIER TTSOCANADIAN SYLLABICS CARRIER TTSECANADIAN " +
"SYLLABICS CARRIER TTSEECANADIAN SYLLABICS CARRIER TTSICANADIAN SYLLABICS" +
" CARRIER TTSACANADIAN SYLLABICS CHI SIGNCANADIAN SYLLABICS FULL STOPCANA" +
"DIAN SYLLABICS QAICANADIAN SYLLABICS NGAICANADIAN SYLLABICS NNGICANADIAN" +
" SYLLABICS NNGIICANADIAN SYLLABICS NNGOCANADIAN SYLLABICS NNGOOCANADIAN " +
"SYLLABICS NNGACANADIAN SYLLABICS NNGAACANADIAN SYLLABICS WOODS-CREE THWE" +
"ECANADIAN SYLLABICS WOODS-CREE THWICANADIAN SYLLABICS WOODS-CREE THWIICA" +
"NADIAN SYLLABICS WOODS-CREE THWOCANADIAN SYLLABICS WOODS-CREE THWOOCANAD" +
"IAN SYLLABICS WOODS-CREE THWACANADIAN SYLLABICS WOODS-CREE THWAACANADIAN" +
" SYLLABICS WOODS-CREE FINAL THCANADIAN SYLLABICS BLACKFOOT WOGHAM SPACE " +
"MARKOGHAM LETTER BEITHOGHAM LETTER LUISOGHAM LETTER FEARNOGHAM LETTER SA" +
"ILOGHAM LETTER NIONOGHAM LETTER UATHOGHAM LETTER DAIROGHAM LETTER TINNEO" +
"GHAM LETTER COLLOGHAM LETTER CEIRTOGHAM LETTER MUINOGHAM LETTER GORTOGHA" +
"M LETTER NGEADALOGHAM LETTER STRAIFOGHAM LETTER RUISOGHAM LETTER AILMOGH" +
"AM LETTER ONNOGHAM LETTER UROGHAM LETTER EADHADHOGHAM LETTER IODHADHOGHA" +
"M LETTER EABHADHOGHAM LETTER OROGHAM LETTER UILLEANNOGHAM LETTER IFINOGH" +
"AM LETTER EAMHANCHOLLOGHAM LETTER PEITHOGHAM FEATHER MARKOGHAM REVERSED " +
"FEATHER MARKRUNIC LETTER FEHU FEOH FE FRUNIC LETTER VRUNIC LETTER URUZ U" +
"R URUNIC LETTER YRRUNIC LETTER YRUNIC LETTER WRUNIC LETTER THURISAZ THUR" +
"S THORNRUNIC LETTER ETHRUNIC LETTER ANSUZ ARUNIC LETTER OS ORUNIC LETTER" +
" AC ARUNIC LETTER AESCRUNIC LETTER LONG-BRANCH-OSS ORUNIC LETTER SHORT-T" +
"WIG-OSS ORUNIC LETTER ORUNIC LETTER OERUNIC LETTER ONRUNIC LETTER RAIDO " +
"RAD REID RRUNIC LETTER KAUNARUNIC LETTER CENRUNIC LETTER KAUN KRUNIC LET" +
"TER GRUNIC LETTER ENGRUNIC LETTER GEBO GYFU GRUNIC LETTER GARRUNIC LETTE" +
"R WUNJO WYNN WRUNIC LETTER HAGLAZ HRUNIC LETTER HAEGL HRUNIC LETTER LONG" +
"-BRANCH-HAGALL HRUNIC LETTER SHORT-TWIG-HAGALL HRUNIC LETTER NAUDIZ NYD " +
"NAUD NRUNIC LETTER SHORT-TWIG-NAUD NRUNIC LETTER DOTTED-NRUNIC LETTER IS" +
"AZ IS ISS IRUNIC LETTER ERUNIC LETTER JERAN JRUNIC LETTER GERRUNIC LETTE" +
"R LONG-BRANCH-AR AERUNIC LETTER SHORT-TWIG-AR ARUNIC LETTER IWAZ EOHRUNI" +
"C LETTER PERTHO PEORTH PRUNIC LETTER ALGIZ EOLHXRUNIC LETTER SOWILO SRUN" +
"IC LETTER SIGEL LONG-BRANCH-SOL SRUNIC LETTER SHORT-TWIG-SOL SRUNIC LETT" +
"ER CRUNIC LETTER ZRUNIC LETTER TIWAZ TIR TYR TRUNIC LETTER SHORT-TWIG-TY" +
"R TRUNIC LETTER DRUNIC LETTER BERKANAN BEORC BJARKAN BRUNIC LETTER SHORT" +
"-TWIG-BJARKAN BRUNIC LETTER DOTTED-PRUNIC LETTER OPEN-PRUNIC LETTER EHWA" +
"Z EH ERUNIC LETTER MANNAZ MAN MRUNIC LETTER LONG-BRANCH-MADR MRUNIC LETT" +
"ER SHORT-TWIG-MADR MRUNIC LETTER LAUKAZ LAGU LOGR LRUNIC LETTER DOTTED-L" +
"RUNIC LETTER INGWAZRUNIC LETTER INGRUNIC LETTER DAGAZ DAEG DRUNIC LETTER" +
" OTHALAN ETHEL ORUNIC LETTER EARRUNIC LETTER IORRUNIC LETTER CWEORTHRUNI" +
"C LETTER CALCRUNIC LETTER CEALCRUNIC LETTER STANRUNIC LETTER LONG-BRANCH" +
"-YRRUNIC LETTER SHORT-TWIG-YRRUNIC LETTER ICELANDIC-YRRUNIC LETTER QRUNI" +
"C LETTER XRUNIC SINGLE PUNCTUATIONRUNIC MULTIPLE PUNCTUATIONRUNIC CROSS " +
"PUNCTUATIONRUNIC ARLAUG SYMBOLRUNIC TVIMADUR SYMBOLRUNIC BELGTHOR SYMBOL" +
"RUNIC LETTER KRUNIC LETTER SHRUNIC LETTER OORUNIC LETTER FRANKS CASKET O" +
"SRUNIC LETTER FRANKS CASKET ISRUNIC LETTER FRANKS CASKET EHRUNIC LETTER " +
"FRANKS CASKET ACRUNIC LETTER FRANKS CASKET AESCTAGALOG LETTER ATAGALOG L" +
"ETTER ITAGALOG LETTER UTAGALOG LETTER KATAGALOG LETTER GATAGALOG LETTER " +
"NGATAGALOG LETTER TATAGALOG LETTER DATAGALOG LETTER NATAGALOG LETTER PAT" +
"AGALOG LETTER BATAGALOG LETTER MATAGALOG LETTER YATAGALOG LETTER RATAGAL" +
"OG LETTER LATAGALOG LETTER WATAGALOG LETTER SATAGALOG LETTER HATAGALOG V" +
"OWEL SIGN ITAGALOG VOWEL SIGN UTAGALOG SIGN VIRAMATAGALOG SIGN PAMUDPODT" +
"AGALOG LETTER ARCHAIC RAHANUNOO LETTER AHANUNOO LETTER IHANUNOO LETTER U" +
"HANUNOO LETTER KAHANUNOO LETTER GAHANUNOO LETTER NGAHANUNOO LETTER TAHAN" +
"UNOO LETTER DAHANUNOO LETTER NAHANUNOO LETTER PAHANUNOO LETTER BAHANUNOO" +
" LETTER MAHANUNOO LETTER YAHANUNOO LETTER RAHANUNOO LETTER LAHANUNOO LET" +
"TER WAHANUNOO LETTER SAHANUNOO LETTER HAHANUNOO VOWEL SIGN IHANUNOO VOWE" +
"L SIGN UHANUNOO SIGN PAMUDPODPHILIPPINE SINGLE PUNCTUATIONPHILIPPINE DOU" +
"BLE PUNCTUATIONBUHID LETTER ABUHID LETTER IBUHID LETTER UBUHID LETTER KA" +
"BUHID LETTER GABUHID LETTER NGABUHID LETTER TABUHID LETTER DABUHID LETTE") + ("" +
"R NABUHID LETTER PABUHID LETTER BABUHID LETTER MABUHID LETTER YABUHID LE" +
"TTER RABUHID LETTER LABUHID LETTER WABUHID LETTER SABUHID LETTER HABUHID" +
" VOWEL SIGN IBUHID VOWEL SIGN UTAGBANWA LETTER ATAGBANWA LETTER ITAGBANW" +
"A LETTER UTAGBANWA LETTER KATAGBANWA LETTER GATAGBANWA LETTER NGATAGBANW" +
"A LETTER TATAGBANWA LETTER DATAGBANWA LETTER NATAGBANWA LETTER PATAGBANW" +
"A LETTER BATAGBANWA LETTER MATAGBANWA LETTER YATAGBANWA LETTER LATAGBANW" +
"A LETTER WATAGBANWA LETTER SATAGBANWA VOWEL SIGN ITAGBANWA VOWEL SIGN UK" +
"HMER LETTER KAKHMER LETTER KHAKHMER LETTER KOKHMER LETTER KHOKHMER LETTE" +
"R NGOKHMER LETTER CAKHMER LETTER CHAKHMER LETTER COKHMER LETTER CHOKHMER" +
" LETTER NYOKHMER LETTER DAKHMER LETTER TTHAKHMER LETTER DOKHMER LETTER T" +
"THOKHMER LETTER NNOKHMER LETTER TAKHMER LETTER THAKHMER LETTER TOKHMER L" +
"ETTER THOKHMER LETTER NOKHMER LETTER BAKHMER LETTER PHAKHMER LETTER POKH" +
"MER LETTER PHOKHMER LETTER MOKHMER LETTER YOKHMER LETTER ROKHMER LETTER " +
"LOKHMER LETTER VOKHMER LETTER SHAKHMER LETTER SSOKHMER LETTER SAKHMER LE" +
"TTER HAKHMER LETTER LAKHMER LETTER QAKHMER INDEPENDENT VOWEL QAQKHMER IN" +
"DEPENDENT VOWEL QAAKHMER INDEPENDENT VOWEL QIKHMER INDEPENDENT VOWEL QII" +
"KHMER INDEPENDENT VOWEL QUKHMER INDEPENDENT VOWEL QUKKHMER INDEPENDENT V" +
"OWEL QUUKHMER INDEPENDENT VOWEL QUUVKHMER INDEPENDENT VOWEL RYKHMER INDE" +
"PENDENT VOWEL RYYKHMER INDEPENDENT VOWEL LYKHMER INDEPENDENT VOWEL LYYKH" +
"MER INDEPENDENT VOWEL QEKHMER INDEPENDENT VOWEL QAIKHMER INDEPENDENT VOW" +
"EL QOO TYPE ONEKHMER INDEPENDENT VOWEL QOO TYPE TWOKHMER INDEPENDENT VOW" +
"EL QAUKHMER VOWEL INHERENT AQKHMER VOWEL INHERENT AAKHMER VOWEL SIGN AAK" +
"HMER VOWEL SIGN IKHMER VOWEL SIGN IIKHMER VOWEL SIGN YKHMER VOWEL SIGN Y" +
"YKHMER VOWEL SIGN UKHMER VOWEL SIGN UUKHMER VOWEL SIGN UAKHMER VOWEL SIG" +
"N OEKHMER VOWEL SIGN YAKHMER VOWEL SIGN IEKHMER VOWEL SIGN EKHMER VOWEL " +
"SIGN AEKHMER VOWEL SIGN AIKHMER VOWEL SIGN OOKHMER VOWEL SIGN AUKHMER SI" +
"GN NIKAHITKHMER SIGN REAHMUKKHMER SIGN YUUKALEAPINTUKHMER SIGN MUUSIKATO" +
"ANKHMER SIGN TRIISAPKHMER SIGN BANTOCKHMER SIGN ROBATKHMER SIGN TOANDAKH" +
"IATKHMER SIGN KAKABATKHMER SIGN AHSDAKHMER SIGN SAMYOK SANNYAKHMER SIGN " +
"VIRIAMKHMER SIGN COENGKHMER SIGN BATHAMASATKHMER SIGN KHANKHMER SIGN BAR" +
"IYOOSANKHMER SIGN CAMNUC PII KUUHKHMER SIGN LEK TOOKHMER SIGN BEYYALKHME" +
"R SIGN PHNAEK MUANKHMER SIGN KOOMUUTKHMER CURRENCY SYMBOL RIELKHMER SIGN" +
" AVAKRAHASANYAKHMER SIGN ATTHACANKHMER DIGIT ZEROKHMER DIGIT ONEKHMER DI" +
"GIT TWOKHMER DIGIT THREEKHMER DIGIT FOURKHMER DIGIT FIVEKHMER DIGIT SIXK" +
"HMER DIGIT SEVENKHMER 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 SY" +
"MBOL LEK ATTAK PRAM-MUOYKHMER SYMBOL LEK ATTAK PRAM-PIIKHMER SYMBOL LEK " +
"ATTAK PRAM-BEIKHMER SYMBOL LEK ATTAK PRAM-BUONMONGOLIAN BIRGAMONGOLIAN E" +
"LLIPSISMONGOLIAN COMMAMONGOLIAN FULL STOPMONGOLIAN COLONMONGOLIAN FOUR D" +
"OTSMONGOLIAN TODO SOFT HYPHENMONGOLIAN SIBE SYLLABLE BOUNDARY MARKERMONG" +
"OLIAN MANCHU COMMAMONGOLIAN MANCHU FULL STOPMONGOLIAN NIRUGUMONGOLIAN FR" +
"EE VARIATION SELECTOR ONEMONGOLIAN FREE VARIATION SELECTOR TWOMONGOLIAN " +
"FREE VARIATION SELECTOR THREEMONGOLIAN VOWEL SEPARATORMONGOLIAN FREE VAR" +
"IATION SELECTOR FOURMONGOLIAN DIGIT ZEROMONGOLIAN DIGIT ONEMONGOLIAN DIG" +
"IT TWOMONGOLIAN DIGIT THREEMONGOLIAN DIGIT FOURMONGOLIAN DIGIT FIVEMONGO" +
"LIAN DIGIT SIXMONGOLIAN DIGIT SEVENMONGOLIAN DIGIT EIGHTMONGOLIAN DIGIT " +
"NINEMONGOLIAN LETTER AMONGOLIAN LETTER EMONGOLIAN LETTER IMONGOLIAN LETT" +
"ER OMONGOLIAN LETTER UMONGOLIAN LETTER OEMONGOLIAN LETTER UEMONGOLIAN LE" +
"TTER EEMONGOLIAN LETTER NAMONGOLIAN LETTER ANGMONGOLIAN LETTER BAMONGOLI" +
"AN LETTER PAMONGOLIAN LETTER QAMONGOLIAN LETTER GAMONGOLIAN LETTER MAMON" +
"GOLIAN LETTER LAMONGOLIAN LETTER SAMONGOLIAN LETTER SHAMONGOLIAN LETTER " +
"TAMONGOLIAN LETTER DAMONGOLIAN LETTER CHAMONGOLIAN LETTER JAMONGOLIAN LE" +
"TTER YAMONGOLIAN LETTER RAMONGOLIAN LETTER WAMONGOLIAN LETTER FAMONGOLIA" +
"N LETTER KAMONGOLIAN LETTER KHAMONGOLIAN LETTER TSAMONGOLIAN LETTER ZAMO" +
"NGOLIAN LETTER HAAMONGOLIAN LETTER ZRAMONGOLIAN LETTER LHAMONGOLIAN LETT" +
"ER ZHIMONGOLIAN LETTER CHIMONGOLIAN LETTER TODO LONG VOWEL SIGNMONGOLIAN" +
" LETTER TODO EMONGOLIAN LETTER TODO IMONGOLIAN LETTER TODO OMONGOLIAN LE" +
"TTER TODO UMONGOLIAN LETTER TODO OEMONGOLIAN LETTER TODO UEMONGOLIAN LET" +
"TER TODO ANGMONGOLIAN LETTER TODO BAMONGOLIAN LETTER TODO PAMONGOLIAN LE" +
"TTER TODO QAMONGOLIAN LETTER TODO GAMONGOLIAN LETTER TODO MAMONGOLIAN LE" +
"TTER TODO TAMONGOLIAN LETTER TODO DAMONGOLIAN LETTER TODO CHAMONGOLIAN L" +
"ETTER TODO JAMONGOLIAN LETTER TODO TSAMONGOLIAN LETTER TODO YAMONGOLIAN " +
"LETTER TODO WAMONGOLIAN LETTER TODO KAMONGOLIAN LETTER TODO GAAMONGOLIAN") + ("" +
" LETTER TODO HAAMONGOLIAN LETTER TODO JIAMONGOLIAN LETTER TODO NIAMONGOL" +
"IAN LETTER TODO DZAMONGOLIAN LETTER SIBE EMONGOLIAN LETTER SIBE IMONGOLI" +
"AN LETTER SIBE IYMONGOLIAN LETTER SIBE UEMONGOLIAN LETTER SIBE UMONGOLIA" +
"N LETTER SIBE ANGMONGOLIAN LETTER SIBE KAMONGOLIAN LETTER SIBE GAMONGOLI" +
"AN LETTER SIBE HAMONGOLIAN LETTER SIBE PAMONGOLIAN LETTER SIBE SHAMONGOL" +
"IAN LETTER SIBE TAMONGOLIAN LETTER SIBE DAMONGOLIAN LETTER SIBE JAMONGOL" +
"IAN LETTER SIBE FAMONGOLIAN LETTER SIBE GAAMONGOLIAN LETTER SIBE HAAMONG" +
"OLIAN LETTER SIBE TSAMONGOLIAN LETTER SIBE ZAMONGOLIAN LETTER SIBE RAAMO" +
"NGOLIAN LETTER SIBE CHAMONGOLIAN LETTER SIBE ZHAMONGOLIAN LETTER MANCHU " +
"IMONGOLIAN LETTER MANCHU KAMONGOLIAN LETTER MANCHU RAMONGOLIAN LETTER MA" +
"NCHU FAMONGOLIAN LETTER MANCHU ZHAMONGOLIAN LETTER CHA WITH TWO DOTSMONG" +
"OLIAN LETTER ALI GALI ANUSVARA ONEMONGOLIAN LETTER ALI GALI VISARGA ONEM" +
"ONGOLIAN LETTER ALI GALI DAMARUMONGOLIAN LETTER ALI GALI UBADAMAMONGOLIA" +
"N LETTER ALI GALI INVERTED UBADAMAMONGOLIAN LETTER ALI GALI BALUDAMONGOL" +
"IAN LETTER ALI GALI THREE BALUDAMONGOLIAN LETTER ALI GALI AMONGOLIAN LET" +
"TER ALI GALI IMONGOLIAN LETTER ALI GALI KAMONGOLIAN LETTER ALI GALI NGAM" +
"ONGOLIAN LETTER ALI GALI CAMONGOLIAN LETTER ALI GALI TTAMONGOLIAN LETTER" +
" ALI GALI TTHAMONGOLIAN LETTER ALI GALI DDAMONGOLIAN LETTER ALI GALI NNA" +
"MONGOLIAN LETTER ALI GALI TAMONGOLIAN LETTER ALI GALI DAMONGOLIAN LETTER" +
" ALI GALI PAMONGOLIAN LETTER ALI GALI PHAMONGOLIAN LETTER ALI GALI SSAMO" +
"NGOLIAN LETTER ALI GALI ZHAMONGOLIAN LETTER ALI GALI ZAMONGOLIAN LETTER " +
"ALI GALI AHMONGOLIAN LETTER TODO ALI GALI TAMONGOLIAN LETTER TODO ALI GA" +
"LI ZHAMONGOLIAN LETTER MANCHU ALI GALI GHAMONGOLIAN LETTER MANCHU ALI GA" +
"LI NGAMONGOLIAN LETTER MANCHU ALI GALI CAMONGOLIAN LETTER MANCHU ALI GAL" +
"I JHAMONGOLIAN LETTER MANCHU ALI GALI TTAMONGOLIAN LETTER MANCHU ALI GAL" +
"I DDHAMONGOLIAN LETTER MANCHU ALI GALI TAMONGOLIAN LETTER MANCHU ALI GAL" +
"I DHAMONGOLIAN LETTER MANCHU ALI GALI SSAMONGOLIAN LETTER MANCHU ALI GAL" +
"I CYAMONGOLIAN LETTER MANCHU ALI GALI ZHAMONGOLIAN LETTER MANCHU ALI GAL" +
"I ZAMONGOLIAN LETTER ALI GALI HALF UMONGOLIAN LETTER ALI GALI HALF YAMON" +
"GOLIAN LETTER MANCHU ALI GALI BHAMONGOLIAN LETTER ALI GALI DAGALGAMONGOL" +
"IAN LETTER MANCHU ALI GALI LHACANADIAN SYLLABICS OYCANADIAN SYLLABICS AY" +
"CANADIAN SYLLABICS AAYCANADIAN SYLLABICS WAYCANADIAN SYLLABICS POYCANADI" +
"AN SYLLABICS PAYCANADIAN SYLLABICS PWOYCANADIAN SYLLABICS TAYCANADIAN SY" +
"LLABICS KAYCANADIAN SYLLABICS KWAYCANADIAN SYLLABICS MAYCANADIAN SYLLABI" +
"CS NOYCANADIAN SYLLABICS NAYCANADIAN SYLLABICS LAYCANADIAN SYLLABICS SOY" +
"CANADIAN SYLLABICS SAYCANADIAN SYLLABICS SHOYCANADIAN SYLLABICS SHAYCANA" +
"DIAN SYLLABICS SHWOYCANADIAN SYLLABICS YOYCANADIAN SYLLABICS YAYCANADIAN" +
" SYLLABICS RAYCANADIAN SYLLABICS NWICANADIAN SYLLABICS OJIBWAY NWICANADI" +
"AN SYLLABICS NWIICANADIAN SYLLABICS OJIBWAY NWIICANADIAN SYLLABICS NWOCA" +
"NADIAN SYLLABICS OJIBWAY NWOCANADIAN SYLLABICS NWOOCANADIAN SYLLABICS OJ" +
"IBWAY NWOOCANADIAN SYLLABICS RWEECANADIAN SYLLABICS RWICANADIAN SYLLABIC" +
"S RWIICANADIAN SYLLABICS RWOCANADIAN SYLLABICS RWOOCANADIAN SYLLABICS RW" +
"ACANADIAN SYLLABICS OJIBWAY PCANADIAN SYLLABICS OJIBWAY TCANADIAN SYLLAB" +
"ICS OJIBWAY KCANADIAN SYLLABICS OJIBWAY CCANADIAN SYLLABICS OJIBWAY MCAN" +
"ADIAN SYLLABICS OJIBWAY NCANADIAN SYLLABICS OJIBWAY SCANADIAN SYLLABICS " +
"OJIBWAY SHCANADIAN SYLLABICS EASTERN WCANADIAN SYLLABICS WESTERN WCANADI" +
"AN SYLLABICS FINAL SMALL RINGCANADIAN SYLLABICS FINAL RAISED DOTCANADIAN" +
" SYLLABICS R-CREE RWECANADIAN SYLLABICS WEST-CREE LOOCANADIAN SYLLABICS " +
"WEST-CREE LAACANADIAN SYLLABICS THWECANADIAN SYLLABICS THWACANADIAN SYLL" +
"ABICS TTHWECANADIAN SYLLABICS TTHOOCANADIAN SYLLABICS TTHAACANADIAN SYLL" +
"ABICS TLHWECANADIAN SYLLABICS TLHOOCANADIAN SYLLABICS SAYISI SHWECANADIA" +
"N SYLLABICS SAYISI SHOOCANADIAN SYLLABICS SAYISI HOOCANADIAN SYLLABICS C" +
"ARRIER GWUCANADIAN SYLLABICS CARRIER DENE GEECANADIAN SYLLABICS CARRIER " +
"GAACANADIAN SYLLABICS CARRIER GWACANADIAN SYLLABICS SAYISI JUUCANADIAN S" +
"YLLABICS CARRIER JWACANADIAN SYLLABICS BEAVER DENE LCANADIAN SYLLABICS B" +
"EAVER DENE RCANADIAN SYLLABICS CARRIER DENTAL SLIMBU VOWEL-CARRIER LETTE" +
"RLIMBU LETTER KALIMBU LETTER KHALIMBU LETTER GALIMBU LETTER GHALIMBU LET" +
"TER NGALIMBU LETTER CALIMBU LETTER CHALIMBU LETTER JALIMBU LETTER JHALIM" +
"BU LETTER YANLIMBU LETTER TALIMBU LETTER THALIMBU LETTER DALIMBU LETTER " +
"DHALIMBU LETTER NALIMBU LETTER PALIMBU LETTER PHALIMBU LETTER BALIMBU LE" +
"TTER BHALIMBU LETTER MALIMBU LETTER YALIMBU LETTER RALIMBU LETTER LALIMB" +
"U LETTER WALIMBU LETTER SHALIMBU LETTER SSALIMBU LETTER SALIMBU LETTER H" +
"ALIMBU LETTER GYANLIMBU LETTER TRALIMBU VOWEL SIGN ALIMBU VOWEL SIGN ILI" +
"MBU VOWEL SIGN ULIMBU VOWEL SIGN EELIMBU VOWEL SIGN AILIMBU VOWEL SIGN O") + ("" +
"OLIMBU VOWEL SIGN AULIMBU VOWEL SIGN ELIMBU VOWEL SIGN OLIMBU SUBJOINED " +
"LETTER YALIMBU SUBJOINED LETTER RALIMBU SUBJOINED LETTER WALIMBU SMALL L" +
"ETTER KALIMBU SMALL LETTER NGALIMBU SMALL LETTER ANUSVARALIMBU SMALL LET" +
"TER TALIMBU SMALL LETTER NALIMBU SMALL LETTER PALIMBU SMALL LETTER MALIM" +
"BU SMALL LETTER RALIMBU SMALL LETTER LALIMBU SIGN MUKPHRENGLIMBU SIGN KE" +
"MPHRENGLIMBU SIGN SA-ILIMBU SIGN LOOLIMBU EXCLAMATION MARKLIMBU QUESTION" +
" MARKLIMBU DIGIT ZEROLIMBU DIGIT ONELIMBU DIGIT TWOLIMBU DIGIT THREELIMB" +
"U DIGIT FOURLIMBU DIGIT FIVELIMBU DIGIT SIXLIMBU DIGIT SEVENLIMBU DIGIT " +
"EIGHTLIMBU DIGIT NINETAI LE LETTER KATAI LE LETTER XATAI LE LETTER NGATA" +
"I LE LETTER TSATAI LE LETTER SATAI LE LETTER YATAI LE LETTER TATAI LE LE" +
"TTER THATAI LE LETTER LATAI LE LETTER PATAI LE LETTER PHATAI LE LETTER M" +
"ATAI LE LETTER FATAI LE LETTER VATAI LE LETTER HATAI LE LETTER QATAI LE " +
"LETTER KHATAI LE 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 AI" +
"TAI LE LETTER TONE-2TAI LE LETTER TONE-3TAI LE LETTER TONE-4TAI LE LETTE" +
"R 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 L" +
"ETTER HIGH NGANEW TAI LUE LETTER LOW KANEW TAI LUE LETTER LOW XANEW TAI " +
"LUE LETTER LOW NGANEW TAI LUE LETTER HIGH TSANEW TAI LUE LETTER HIGH SAN" +
"EW TAI LUE LETTER HIGH YANEW TAI LUE LETTER LOW TSANEW TAI LUE LETTER LO" +
"W SANEW TAI LUE LETTER LOW YANEW TAI LUE LETTER HIGH TANEW TAI LUE LETTE" +
"R HIGH THANEW TAI LUE LETTER HIGH NANEW TAI LUE LETTER LOW TANEW TAI LUE" +
" LETTER LOW THANEW TAI LUE LETTER LOW NANEW TAI LUE LETTER HIGH PANEW TA" +
"I LUE LETTER HIGH PHANEW TAI LUE LETTER HIGH MANEW TAI LUE LETTER LOW PA" +
"NEW TAI LUE LETTER LOW PHANEW TAI LUE LETTER LOW MANEW TAI LUE LETTER HI" +
"GH FANEW TAI LUE LETTER HIGH VANEW TAI LUE LETTER HIGH LANEW TAI LUE LET" +
"TER LOW FANEW TAI LUE LETTER LOW VANEW TAI LUE LETTER LOW LANEW TAI LUE " +
"LETTER HIGH HANEW TAI LUE LETTER HIGH DANEW TAI LUE LETTER HIGH BANEW TA" +
"I LUE LETTER LOW HANEW TAI LUE LETTER LOW DANEW TAI LUE LETTER LOW BANEW" +
" TAI LUE LETTER HIGH KVANEW TAI LUE LETTER HIGH XVANEW TAI LUE LETTER LO" +
"W KVANEW TAI LUE LETTER LOW XVANEW TAI LUE LETTER HIGH SUANEW TAI LUE LE" +
"TTER 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 SI" +
"GN UUNEW TAI LUE VOWEL SIGN ENEW TAI LUE VOWEL SIGN AENEW TAI LUE VOWEL " +
"SIGN ONEW TAI LUE VOWEL SIGN OANEW TAI LUE VOWEL SIGN UENEW TAI LUE VOWE" +
"L SIGN AYNEW TAI LUE VOWEL SIGN AAYNEW TAI LUE VOWEL SIGN UYNEW TAI LUE " +
"VOWEL SIGN OYNEW TAI LUE VOWEL SIGN OAYNEW TAI LUE VOWEL SIGN UEYNEW TAI" +
" LUE VOWEL SIGN IYNEW TAI LUE LETTER FINAL VNEW TAI LUE LETTER FINAL NGN" +
"EW TAI LUE LETTER FINAL NNEW TAI LUE LETTER FINAL MNEW TAI LUE LETTER FI" +
"NAL KNEW TAI LUE LETTER FINAL DNEW TAI LUE LETTER FINAL BNEW TAI LUE TON" +
"E MARK-1NEW TAI LUE TONE MARK-2NEW TAI LUE DIGIT ZERONEW TAI LUE DIGIT O" +
"NENEW TAI LUE DIGIT TWONEW TAI LUE DIGIT THREENEW TAI LUE DIGIT FOURNEW " +
"TAI LUE DIGIT FIVENEW TAI LUE DIGIT SIXNEW TAI LUE DIGIT SEVENNEW TAI LU" +
"E DIGIT EIGHTNEW TAI LUE DIGIT NINENEW TAI LUE THAM DIGIT ONENEW TAI LUE" +
" SIGN LAENEW TAI LUE SIGN LAEVKHMER SYMBOL PATHAMASATKHMER SYMBOL MUOY K" +
"OETKHMER SYMBOL PII KOETKHMER SYMBOL BEI KOETKHMER SYMBOL BUON KOETKHMER" +
" SYMBOL PRAM KOETKHMER SYMBOL PRAM-MUOY KOETKHMER SYMBOL PRAM-PII KOETKH" +
"MER SYMBOL PRAM-BEI KOETKHMER SYMBOL PRAM-BUON KOETKHMER SYMBOL DAP KOET" +
"KHMER SYMBOL DAP-MUOY KOETKHMER SYMBOL DAP-PII KOETKHMER SYMBOL DAP-BEI " +
"KOETKHMER SYMBOL DAP-BUON KOETKHMER SYMBOL DAP-PRAM KOETKHMER SYMBOL TUT" +
"EYASATKHMER SYMBOL MUOY ROCKHMER SYMBOL PII ROCKHMER SYMBOL BEI ROCKHMER" +
" SYMBOL BUON ROCKHMER SYMBOL PRAM ROCKHMER SYMBOL PRAM-MUOY ROCKHMER SYM" +
"BOL PRAM-PII ROCKHMER SYMBOL PRAM-BEI ROCKHMER SYMBOL PRAM-BUON ROCKHMER" +
" SYMBOL DAP ROCKHMER SYMBOL DAP-MUOY ROCKHMER SYMBOL DAP-PII ROCKHMER SY" +
"MBOL DAP-BEI ROCKHMER SYMBOL DAP-BUON ROCKHMER SYMBOL DAP-PRAM ROCBUGINE" +
"SE LETTER KABUGINESE LETTER GABUGINESE LETTER NGABUGINESE LETTER NGKABUG" +
"INESE LETTER PABUGINESE LETTER BABUGINESE LETTER MABUGINESE LETTER MPABU" +
"GINESE LETTER TABUGINESE LETTER DABUGINESE LETTER NABUGINESE LETTER NRAB" +
"UGINESE LETTER CABUGINESE LETTER JABUGINESE LETTER NYABUGINESE LETTER NY" +
"CABUGINESE LETTER YABUGINESE LETTER RABUGINESE LETTER LABUGINESE LETTER " +
"VABUGINESE LETTER SABUGINESE LETTER ABUGINESE LETTER HABUGINESE VOWEL SI" +
"GN IBUGINESE VOWEL SIGN UBUGINESE VOWEL SIGN EBUGINESE VOWEL SIGN OBUGIN" +
"ESE VOWEL SIGN AEBUGINESE PALLAWABUGINESE END OF SECTIONTAI THAM LETTER ") + ("" +
"HIGH KATAI THAM LETTER HIGH KHATAI THAM LETTER HIGH KXATAI THAM LETTER L" +
"OW KATAI THAM LETTER LOW KXATAI THAM LETTER LOW KHATAI THAM LETTER NGATA" +
"I THAM LETTER HIGH CATAI THAM LETTER HIGH CHATAI THAM LETTER LOW CATAI T" +
"HAM LETTER LOW SATAI THAM LETTER LOW CHATAI THAM LETTER NYATAI THAM LETT" +
"ER RATATAI THAM LETTER HIGH RATHATAI THAM LETTER DATAI THAM LETTER LOW R" +
"ATHATAI THAM LETTER RANATAI THAM LETTER HIGH TATAI THAM LETTER HIGH THAT" +
"AI THAM LETTER LOW TATAI THAM LETTER LOW THATAI THAM LETTER NATAI THAM L" +
"ETTER BATAI THAM LETTER HIGH PATAI THAM LETTER HIGH PHATAI THAM LETTER H" +
"IGH FATAI THAM LETTER LOW PATAI THAM LETTER LOW FATAI THAM LETTER LOW PH" +
"ATAI THAM LETTER MATAI THAM LETTER LOW YATAI THAM LETTER HIGH YATAI THAM" +
" LETTER RATAI THAM LETTER RUETAI THAM LETTER LATAI THAM LETTER LUETAI TH" +
"AM LETTER WATAI THAM LETTER HIGH SHATAI THAM LETTER HIGH SSATAI THAM LET" +
"TER HIGH SATAI THAM LETTER HIGH HATAI THAM LETTER LLATAI THAM LETTER ATA" +
"I THAM LETTER LOW HATAI THAM LETTER ITAI THAM LETTER IITAI THAM LETTER U" +
"TAI THAM LETTER UUTAI THAM LETTER EETAI THAM LETTER OOTAI THAM LETTER LA" +
"ETAI THAM LETTER GREAT SATAI THAM CONSONANT SIGN MEDIAL RATAI THAM CONSO" +
"NANT SIGN MEDIAL LATAI THAM CONSONANT SIGN LA TANG LAITAI THAM SIGN MAI " +
"KANG LAITAI THAM CONSONANT SIGN FINAL NGATAI THAM CONSONANT SIGN LOW PAT" +
"AI THAM CONSONANT 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 TH" +
"AM VOWEL SIGN TALL AATAI THAM VOWEL SIGN ITAI THAM VOWEL SIGN IITAI THAM" +
" VOWEL SIGN UETAI THAM VOWEL SIGN UUETAI THAM VOWEL SIGN UTAI THAM VOWEL" +
" SIGN UUTAI THAM VOWEL SIGN OTAI THAM VOWEL SIGN OA BELOWTAI THAM VOWEL " +
"SIGN OYTAI THAM VOWEL SIGN ETAI THAM VOWEL SIGN AETAI THAM VOWEL SIGN OO" +
"TAI THAM VOWEL SIGN AITAI THAM VOWEL SIGN THAM AITAI THAM VOWEL SIGN OA " +
"ABOVETAI THAM SIGN MAI KANGTAI THAM SIGN TONE-1TAI THAM SIGN TONE-2TAI T" +
"HAM 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 KARAN" +
"TAI THAM COMBINING CRYPTOGRAMMIC DOTTAI THAM HORA DIGIT ZEROTAI THAM HOR" +
"A 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 THA" +
"M 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 THAM THAM DIGIT SEVENTAI THAM THAM DIGIT EIGHTTAI THAM THA" +
"M DIGIT NINETAI THAM SIGN WIANGTAI THAM SIGN WIANGWAAKTAI THAM SIGN SAWA" +
"NTAI THAM SIGN KEOWTAI THAM SIGN HOYTAI THAM SIGN DOKMAITAI THAM SIGN RE" +
"VERSED ROTATED RANATAI THAM SIGN MAI YAMOKTAI THAM SIGN KAANTAI THAM SIG" +
"N KAANKUUTAI THAM SIGN SATKAANTAI THAM SIGN SATKAANKUUTAI THAM SIGN HANG" +
"TAI THAM SIGN CAANGCOMBINING DOUBLED CIRCUMFLEX ACCENTCOMBINING DIAERESI" +
"S-RINGCOMBINING INFINITYCOMBINING DOWNWARDS ARROWCOMBINING TRIPLE DOTCOM" +
"BINING X-X BELOWCOMBINING WIGGLY LINE BELOWCOMBINING OPEN MARK BELOWCOMB" +
"INING DOUBLE OPEN MARK BELOWCOMBINING LIGHT CENTRALIZATION STROKE BELOWC" +
"OMBINING STRONG CENTRALIZATION STROKE BELOWCOMBINING PARENTHESES ABOVECO" +
"MBINING DOUBLE PARENTHESES ABOVECOMBINING PARENTHESES BELOWCOMBINING PAR" +
"ENTHESES OVERLAYCOMBINING LATIN SMALL LETTER W BELOWCOMBINING LATIN SMAL" +
"L LETTER TURNED W BELOWCOMBINING LEFT PARENTHESIS ABOVE LEFTCOMBINING RI" +
"GHT PARENTHESIS ABOVE RIGHTCOMBINING LEFT PARENTHESIS BELOW LEFTCOMBININ" +
"G RIGHT PARENTHESIS BELOW RIGHTCOMBINING SQUARE BRACKETS ABOVECOMBINING " +
"NUMBER SIGN ABOVECOMBINING INVERTED DOUBLE ARCH ABOVECOMBINING PLUS SIGN" +
" ABOVECOMBINING DOUBLE PLUS SIGN ABOVECOMBINING DOUBLE PLUS SIGN BELOWCO" +
"MBINING TRIPLE ACUTE ACCENTCOMBINING LATIN SMALL LETTER INSULAR GCOMBINI" +
"NG LATIN SMALL LETTER INSULAR RCOMBINING LATIN SMALL LETTER INSULAR TCOM" +
"BINING DOUBLE CARONCOMBINING VERTICAL-LINE-ACUTECOMBINING GRAVE-VERTICAL" +
"-LINECOMBINING VERTICAL-LINE-GRAVECOMBINING ACUTE-VERTICAL-LINECOMBINING" +
" VERTICAL-LINE-MACRONCOMBINING MACRON-VERTICAL-LINECOMBINING VERTICAL-LI" +
"NE-ACUTE-GRAVECOMBINING VERTICAL-LINE-GRAVE-ACUTECOMBINING MACRON-ACUTE-" +
"GRAVECOMBINING SHARP SIGNCOMBINING FLAT SIGNCOMBINING DOWN TACK ABOVECOM" +
"BINING DIAERESIS WITH RAISED LEFT DOTCOMBINING DOT-AND-RING BELOWCOMBINI" +
"NG LEFT TACK ABOVECOMBINING RIGHT TACK ABOVECOMBINING MINUS SIGN ABOVECO" +
"MBINING INVERTED BRIDGE ABOVECOMBINING SQUARE ABOVECOMBINING SEAGULL ABO" +
"VECOMBINING DOUBLE ARCH BELOWCOMBINING DOUBLE ARCH ABOVECOMBINING EQUALS" +
" SIGN ABOVECOMBINING LEFT ANGLE CENTRED ABOVECOMBINING UPWARDS ARROW ABO") + ("" +
"VECOMBINING DOUBLE RIGHTWARDS ARROW ABOVEBALINESE SIGN ULU RICEMBALINESE" +
" SIGN ULU CANDRABALINESE SIGN CECEKBALINESE SIGN SURANGBALINESE SIGN BIS" +
"AHBALINESE LETTER AKARABALINESE LETTER AKARA TEDUNGBALINESE LETTER IKARA" +
"BALINESE LETTER IKARA TEDUNGBALINESE LETTER UKARABALINESE LETTER UKARA T" +
"EDUNGBALINESE LETTER RA REPABALINESE LETTER RA REPA TEDUNGBALINESE LETTE" +
"R LA LENGABALINESE LETTER LA LENGA TEDUNGBALINESE LETTER EKARABALINESE L" +
"ETTER AIKARABALINESE LETTER OKARABALINESE LETTER OKARA TEDUNGBALINESE LE" +
"TTER KABALINESE LETTER KA MAHAPRANABALINESE LETTER GABALINESE LETTER GA " +
"GORABALINESE LETTER NGABALINESE LETTER CABALINESE LETTER CA LACABALINESE" +
" LETTER JABALINESE LETTER JA JERABALINESE LETTER NYABALINESE LETTER TA L" +
"ATIKBALINESE LETTER TA MURDA MAHAPRANABALINESE LETTER DA MURDA ALPAPRANA" +
"BALINESE LETTER DA MURDA MAHAPRANABALINESE LETTER NA RAMBATBALINESE LETT" +
"ER TABALINESE LETTER TA TAWABALINESE LETTER DABALINESE LETTER DA MADUBAL" +
"INESE LETTER NABALINESE LETTER PABALINESE LETTER PA KAPALBALINESE LETTER" +
" BABALINESE LETTER BA KEMBANGBALINESE LETTER MABALINESE LETTER YABALINES" +
"E LETTER RABALINESE LETTER LABALINESE LETTER WABALINESE LETTER SA SAGABA" +
"LINESE LETTER SA SAPABALINESE LETTER SABALINESE LETTER HABALINESE SIGN R" +
"EREKANBALINESE VOWEL SIGN TEDUNGBALINESE VOWEL SIGN ULUBALINESE VOWEL SI" +
"GN ULU SARIBALINESE VOWEL SIGN SUKUBALINESE VOWEL SIGN SUKU ILUTBALINESE" +
" VOWEL SIGN RA REPABALINESE VOWEL SIGN RA REPA TEDUNGBALINESE VOWEL SIGN" +
" LA LENGABALINESE VOWEL SIGN LA LENGA TEDUNGBALINESE VOWEL SIGN TALINGBA" +
"LINESE VOWEL SIGN TALING REPABALINESE VOWEL SIGN TALING TEDUNGBALINESE V" +
"OWEL SIGN TALING REPA TEDUNGBALINESE VOWEL SIGN PEPETBALINESE VOWEL SIGN" +
" PEPET TEDUNGBALINESE ADEG ADEGBALINESE LETTER KAF SASAKBALINESE LETTER " +
"KHOT SASAKBALINESE LETTER TZIR SASAKBALINESE LETTER EF SASAKBALINESE LET" +
"TER VE SASAKBALINESE LETTER ZAL SASAKBALINESE LETTER ASYURA SASAKBALINES" +
"E LETTER ARCHAIC JNYABALINESE INVERTED CARIK SIKIBALINESE INVERTED CARIK" +
" PARERENBALINESE DIGIT ZEROBALINESE DIGIT ONEBALINESE DIGIT TWOBALINESE " +
"DIGIT THREEBALINESE DIGIT FOURBALINESE DIGIT FIVEBALINESE DIGIT SIXBALIN" +
"ESE DIGIT SEVENBALINESE DIGIT EIGHTBALINESE DIGIT NINEBALINESE PANTIBALI" +
"NESE PAMADABALINESE WINDUBALINESE CARIK PAMUNGKAHBALINESE CARIK SIKIBALI" +
"NESE CARIK PARERENBALINESE PAMENENGBALINESE MUSICAL SYMBOL DONGBALINESE " +
"MUSICAL SYMBOL DENGBALINESE MUSICAL SYMBOL DUNGBALINESE MUSICAL SYMBOL D" +
"ANGBALINESE MUSICAL SYMBOL DANG SURANGBALINESE MUSICAL SYMBOL DINGBALINE" +
"SE MUSICAL SYMBOL DAENGBALINESE MUSICAL SYMBOL DEUNGBALINESE MUSICAL SYM" +
"BOL DAINGBALINESE MUSICAL SYMBOL DANG GEDEBALINESE MUSICAL SYMBOL COMBIN" +
"ING TEGEHBALINESE MUSICAL SYMBOL COMBINING ENDEPBALINESE MUSICAL SYMBOL " +
"COMBINING KEMPULBALINESE MUSICAL SYMBOL COMBINING KEMPLIBALINESE MUSICAL" +
" SYMBOL COMBINING JEGOGANBALINESE MUSICAL SYMBOL COMBINING KEMPUL WITH J" +
"EGOGANBALINESE MUSICAL SYMBOL COMBINING KEMPLI WITH JEGOGANBALINESE MUSI" +
"CAL SYMBOL COMBINING BENDEBALINESE MUSICAL SYMBOL COMBINING GONGBALINESE" +
" MUSICAL SYMBOL RIGHT-HAND OPEN DUGBALINESE MUSICAL SYMBOL RIGHT-HAND OP" +
"EN DAGBALINESE MUSICAL SYMBOL RIGHT-HAND CLOSED TUKBALINESE MUSICAL SYMB" +
"OL RIGHT-HAND CLOSED TAKBALINESE MUSICAL SYMBOL LEFT-HAND OPEN PANGBALIN" +
"ESE MUSICAL SYMBOL LEFT-HAND OPEN PUNGBALINESE MUSICAL SYMBOL LEFT-HAND " +
"CLOSED PLAKBALINESE MUSICAL SYMBOL LEFT-HAND CLOSED PLUKBALINESE MUSICAL" +
" SYMBOL LEFT-HAND OPEN PINGBALINESE PANTI LANTANGBALINESE PAMADA LANTANG" +
"BALINESE PANTI BAWAKSUNDANESE SIGN PANYECEKSUNDANESE SIGN PANGLAYARSUNDA" +
"NESE SIGN PANGWISADSUNDANESE LETTER ASUNDANESE LETTER ISUNDANESE LETTER " +
"USUNDANESE LETTER AESUNDANESE LETTER OSUNDANESE LETTER ESUNDANESE LETTER" +
" EUSUNDANESE LETTER KASUNDANESE LETTER QASUNDANESE LETTER GASUNDANESE LE" +
"TTER NGASUNDANESE LETTER CASUNDANESE LETTER JASUNDANESE LETTER ZASUNDANE" +
"SE LETTER NYASUNDANESE LETTER TASUNDANESE LETTER DASUNDANESE LETTER NASU" +
"NDANESE LETTER PASUNDANESE LETTER FASUNDANESE LETTER VASUNDANESE LETTER " +
"BASUNDANESE LETTER MASUNDANESE LETTER YASUNDANESE LETTER RASUNDANESE LET" +
"TER LASUNDANESE LETTER WASUNDANESE LETTER SASUNDANESE LETTER XASUNDANESE" +
" LETTER HASUNDANESE CONSONANT SIGN PAMINGKALSUNDANESE CONSONANT SIGN PAN" +
"YAKRASUNDANESE CONSONANT SIGN PANYIKUSUNDANESE VOWEL SIGN PANGHULUSUNDAN" +
"ESE VOWEL SIGN PANYUKUSUNDANESE VOWEL SIGN PANAELAENGSUNDANESE VOWEL SIG" +
"N PANOLONGSUNDANESE VOWEL SIGN PAMEPETSUNDANESE VOWEL SIGN PANEULEUNGSUN" +
"DANESE SIGN PAMAAEHSUNDANESE SIGN VIRAMASUNDANESE CONSONANT SIGN PASANGA" +
"N MASUNDANESE CONSONANT SIGN PASANGAN WASUNDANESE LETTER KHASUNDANESE LE" +
"TTER SYASUNDANESE DIGIT ZEROSUNDANESE DIGIT ONESUNDANESE DIGIT TWOSUNDAN" +
"ESE DIGIT THREESUNDANESE DIGIT FOURSUNDANESE DIGIT FIVESUNDANESE DIGIT S") + ("" +
"IXSUNDANESE DIGIT SEVENSUNDANESE DIGIT EIGHTSUNDANESE DIGIT NINESUNDANES" +
"E AVAGRAHASUNDANESE LETTER REUSUNDANESE LETTER LEUSUNDANESE LETTER BHASU" +
"NDANESE LETTER FINAL KSUNDANESE LETTER FINAL MBATAK LETTER ABATAK LETTER" +
" SIMALUNGUN ABATAK LETTER HABATAK LETTER SIMALUNGUN HABATAK LETTER MANDA" +
"ILING HABATAK LETTER BABATAK LETTER KARO BABATAK LETTER PABATAK LETTER S" +
"IMALUNGUN PABATAK LETTER NABATAK LETTER MANDAILING NABATAK LETTER WABATA" +
"K LETTER SIMALUNGUN WABATAK LETTER PAKPAK WABATAK LETTER GABATAK LETTER " +
"SIMALUNGUN GABATAK LETTER JABATAK LETTER DABATAK LETTER RABATAK LETTER S" +
"IMALUNGUN RABATAK LETTER MABATAK LETTER SIMALUNGUN MABATAK LETTER SOUTHE" +
"RN TABATAK LETTER NORTHERN TABATAK LETTER SABATAK LETTER SIMALUNGUN SABA" +
"TAK LETTER MANDAILING SABATAK LETTER YABATAK LETTER SIMALUNGUN YABATAK L" +
"ETTER NGABATAK LETTER LABATAK LETTER SIMALUNGUN LABATAK LETTER NYABATAK " +
"LETTER CABATAK LETTER NDABATAK LETTER MBABATAK LETTER IBATAK LETTER UBAT" +
"AK SIGN TOMPIBATAK VOWEL SIGN EBATAK VOWEL SIGN PAKPAK EBATAK VOWEL SIGN" +
" EEBATAK VOWEL SIGN IBATAK VOWEL SIGN KARO IBATAK VOWEL SIGN OBATAK VOWE" +
"L SIGN KARO OBATAK VOWEL SIGN UBATAK VOWEL SIGN U FOR SIMALUNGUN SABATAK" +
" CONSONANT SIGN NGBATAK CONSONANT SIGN HBATAK PANGOLATBATAK PANONGONANBA" +
"TAK SYMBOL BINDU NA METEKBATAK SYMBOL BINDU PINARBORASBATAK SYMBOL BINDU" +
" JUDULBATAK SYMBOL BINDU PANGOLATLEPCHA LETTER KALEPCHA LETTER KLALEPCHA" +
" LETTER KHALEPCHA LETTER GALEPCHA LETTER GLALEPCHA LETTER NGALEPCHA LETT" +
"ER CALEPCHA LETTER CHALEPCHA LETTER JALEPCHA LETTER NYALEPCHA LETTER TAL" +
"EPCHA LETTER THALEPCHA LETTER DALEPCHA LETTER NALEPCHA LETTER PALEPCHA L" +
"ETTER PLALEPCHA LETTER PHALEPCHA LETTER FALEPCHA LETTER FLALEPCHA LETTER" +
" BALEPCHA LETTER BLALEPCHA LETTER MALEPCHA LETTER MLALEPCHA LETTER TSALE" +
"PCHA LETTER TSHALEPCHA LETTER DZALEPCHA LETTER YALEPCHA LETTER RALEPCHA " +
"LETTER LALEPCHA LETTER HALEPCHA LETTER HLALEPCHA LETTER VALEPCHA LETTER " +
"SALEPCHA LETTER SHALEPCHA LETTER WALEPCHA LETTER ALEPCHA SUBJOINED LETTE" +
"R YALEPCHA SUBJOINED LETTER RALEPCHA VOWEL SIGN AALEPCHA VOWEL SIGN ILEP" +
"CHA VOWEL SIGN OLEPCHA VOWEL SIGN OOLEPCHA VOWEL SIGN ULEPCHA VOWEL SIGN" +
" UULEPCHA VOWEL SIGN ELEPCHA CONSONANT SIGN KLEPCHA CONSONANT SIGN MLEPC" +
"HA CONSONANT SIGN LLEPCHA CONSONANT SIGN NLEPCHA CONSONANT SIGN PLEPCHA " +
"CONSONANT SIGN RLEPCHA CONSONANT SIGN TLEPCHA CONSONANT SIGN NYIN-DOLEPC" +
"HA CONSONANT SIGN KANGLEPCHA SIGN RANLEPCHA SIGN NUKTALEPCHA PUNCTUATION" +
" TA-ROLLEPCHA PUNCTUATION NYET THYOOM TA-ROLLEPCHA PUNCTUATION CER-WALEP" +
"CHA PUNCTUATION TSHOOK CER-WALEPCHA PUNCTUATION TSHOOKLEPCHA DIGIT ZEROL" +
"EPCHA DIGIT ONELEPCHA DIGIT TWOLEPCHA DIGIT THREELEPCHA DIGIT FOURLEPCHA" +
" DIGIT FIVELEPCHA DIGIT SIXLEPCHA DIGIT SEVENLEPCHA DIGIT EIGHTLEPCHA DI" +
"GIT NINELEPCHA LETTER TTALEPCHA LETTER TTHALEPCHA LETTER DDAOL CHIKI DIG" +
"IT ZEROOL CHIKI DIGIT ONEOL CHIKI DIGIT TWOOL CHIKI DIGIT THREEOL CHIKI " +
"DIGIT FOUROL CHIKI DIGIT FIVEOL CHIKI DIGIT SIXOL CHIKI DIGIT SEVENOL CH" +
"IKI DIGIT EIGHTOL CHIKI DIGIT NINEOL CHIKI LETTER LAOL CHIKI LETTER ATOL" +
" CHIKI LETTER AGOL CHIKI LETTER ANGOL CHIKI LETTER ALOL CHIKI LETTER LAA" +
"OL CHIKI LETTER AAKOL CHIKI LETTER AAJOL CHIKI LETTER AAMOL CHIKI LETTER" +
" AAWOL CHIKI LETTER LIOL CHIKI LETTER ISOL CHIKI LETTER IHOL CHIKI LETTE" +
"R INYOL CHIKI LETTER IROL CHIKI LETTER LUOL CHIKI LETTER UCOL CHIKI LETT" +
"ER UDOL CHIKI LETTER UNNOL CHIKI LETTER UYOL CHIKI LETTER LEOL CHIKI LET" +
"TER EPOL CHIKI LETTER EDDOL CHIKI LETTER ENOL CHIKI LETTER ERROL CHIKI L" +
"ETTER LOOL CHIKI LETTER OTTOL CHIKI LETTER OBOL CHIKI LETTER OVOL CHIKI " +
"LETTER OHOL CHIKI MU TTUDDAGOL CHIKI GAAHLAA TTUDDAAGOL CHIKI MU-GAAHLAA" +
" TTUDDAAGOL CHIKI RELAAOL CHIKI PHAARKAAOL CHIKI AHADOL CHIKI PUNCTUATIO" +
"N MUCAADOL CHIKI PUNCTUATION DOUBLE MUCAADCYRILLIC SMALL LETTER ROUNDED " +
"VECYRILLIC SMALL LETTER LONG-LEGGED DECYRILLIC SMALL LETTER NARROW OCYRI" +
"LLIC SMALL LETTER WIDE ESCYRILLIC SMALL LETTER TALL TECYRILLIC SMALL LET" +
"TER THREE-LEGGED TECYRILLIC SMALL LETTER TALL HARD SIGNCYRILLIC SMALL LE" +
"TTER TALL YATCYRILLIC SMALL LETTER UNBLENDED UKCYRILLIC CAPITAL LETTER T" +
"JECYRILLIC SMALL LETTER TJEGEORGIAN MTAVRULI CAPITAL LETTER ANGEORGIAN M" +
"TAVRULI CAPITAL LETTER BANGEORGIAN MTAVRULI CAPITAL LETTER GANGEORGIAN M" +
"TAVRULI CAPITAL LETTER DONGEORGIAN MTAVRULI CAPITAL LETTER ENGEORGIAN MT" +
"AVRULI CAPITAL LETTER VINGEORGIAN MTAVRULI CAPITAL LETTER ZENGEORGIAN MT" +
"AVRULI CAPITAL LETTER TANGEORGIAN MTAVRULI CAPITAL LETTER INGEORGIAN MTA" +
"VRULI CAPITAL LETTER KANGEORGIAN MTAVRULI CAPITAL LETTER LASGEORGIAN MTA" +
"VRULI CAPITAL LETTER MANGEORGIAN MTAVRULI CAPITAL LETTER NARGEORGIAN MTA" +
"VRULI CAPITAL LETTER ONGEORGIAN MTAVRULI CAPITAL LETTER PARGEORGIAN MTAV" +
"RULI CAPITAL LETTER ZHARGEORGIAN MTAVRULI CAPITAL LETTER RAEGEORGIAN MTA") + ("" +
"VRULI CAPITAL LETTER SANGEORGIAN MTAVRULI CAPITAL LETTER TARGEORGIAN MTA" +
"VRULI CAPITAL LETTER UNGEORGIAN MTAVRULI CAPITAL LETTER PHARGEORGIAN MTA" +
"VRULI CAPITAL LETTER KHARGEORGIAN MTAVRULI CAPITAL LETTER GHANGEORGIAN M" +
"TAVRULI CAPITAL LETTER QARGEORGIAN MTAVRULI CAPITAL 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 XANGEORGIA" +
"N MTAVRULI CAPITAL LETTER JHANGEORGIAN MTAVRULI CAPITAL LETTER HAEGEORGI" +
"AN MTAVRULI CAPITAL LETTER HEGEORGIAN MTAVRULI CAPITAL LETTER HIEGEORGIA" +
"N MTAVRULI CAPITAL LETTER WEGEORGIAN MTAVRULI CAPITAL LETTER HARGEORGIAN" +
" MTAVRULI CAPITAL LETTER HOEGEORGIAN MTAVRULI CAPITAL LETTER FIGEORGIAN " +
"MTAVRULI CAPITAL LETTER YNGEORGIAN MTAVRULI CAPITAL LETTER ELIFIGEORGIAN" +
" MTAVRULI CAPITAL LETTER TURNED GANGEORGIAN MTAVRULI CAPITAL LETTER AING" +
"EORGIAN MTAVRULI CAPITAL LETTER AENGEORGIAN MTAVRULI CAPITAL LETTER HARD" +
" SIGNGEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGNSUNDANESE PUNCTUATION B" +
"INDU SURYASUNDANESE PUNCTUATION BINDU PANGLONGSUNDANESE PUNCTUATION BIND" +
"U PURNAMASUNDANESE PUNCTUATION BINDU CAKRASUNDANESE PUNCTUATION BINDU LE" +
"U SATANGASUNDANESE PUNCTUATION BINDU KA SATANGASUNDANESE PUNCTUATION BIN" +
"DU DA SATANGASUNDANESE PUNCTUATION BINDU BA SATANGAVEDIC TONE KARSHANAVE" +
"DIC TONE SHARAVEDIC TONE PRENKHAVEDIC SIGN NIHSHVASAVEDIC SIGN YAJURVEDI" +
"C MIDLINE SVARITAVEDIC TONE YAJURVEDIC AGGRAVATED INDEPENDENT SVARITAVED" +
"IC TONE YAJURVEDIC INDEPENDENT SVARITAVEDIC TONE YAJURVEDIC KATHAKA INDE" +
"PENDENT SVARITAVEDIC TONE CANDRA BELOWVEDIC TONE YAJURVEDIC KATHAKA INDE" +
"PENDENT SVARITA SCHROEDERVEDIC TONE DOUBLE SVARITAVEDIC TONE TRIPLE SVAR" +
"ITAVEDIC TONE KATHAKA ANUDATTAVEDIC TONE DOT BELOWVEDIC TONE TWO DOTS BE" +
"LOWVEDIC TONE THREE DOTS BELOWVEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT S" +
"VARITAVEDIC TONE ATHARVAVEDIC INDEPENDENT SVARITAVEDIC SIGN VISARGA SVAR" +
"ITAVEDIC SIGN VISARGA UDATTAVEDIC SIGN REVERSED VISARGA UDATTAVEDIC SIGN" +
" VISARGA ANUDATTAVEDIC SIGN REVERSED VISARGA ANUDATTAVEDIC SIGN VISARGA " +
"UDATTA WITH TAILVEDIC SIGN VISARGA ANUDATTA WITH TAILVEDIC SIGN ANUSVARA" +
" ANTARGOMUKHAVEDIC SIGN ANUSVARA BAHIRGOMUKHAVEDIC SIGN ANUSVARA VAMAGOM" +
"UKHAVEDIC SIGN ANUSVARA VAMAGOMUKHA WITH TAILVEDIC SIGN TIRYAKVEDIC SIGN" +
" HEXIFORM LONG ANUSVARAVEDIC SIGN LONG ANUSVARAVEDIC SIGN RTHANG LONG AN" +
"USVARAVEDIC SIGN ANUSVARA UBHAYATO MUKHAVEDIC SIGN ARDHAVISARGAVEDIC SIG" +
"N ROTATED ARDHAVISARGAVEDIC TONE CANDRA ABOVEVEDIC SIGN JIHVAMULIYAVEDIC" +
" SIGN UPADHMANIYAVEDIC SIGN ATIKRAMAVEDIC TONE RING ABOVEVEDIC TONE DOUB" +
"LE RING ABOVEVEDIC SIGN DOUBLE ANUSVARA ANTARGOMUKHALATIN LETTER SMALL C" +
"APITAL ALATIN LETTER SMALL CAPITAL AELATIN SMALL LETTER TURNED AELATIN L" +
"ETTER SMALL CAPITAL BARRED BLATIN LETTER SMALL CAPITAL CLATIN LETTER SMA" +
"LL CAPITAL DLATIN LETTER SMALL CAPITAL ETHLATIN LETTER SMALL CAPITAL ELA" +
"TIN SMALL LETTER TURNED OPEN ELATIN SMALL LETTER TURNED ILATIN LETTER SM" +
"ALL CAPITAL JLATIN LETTER SMALL CAPITAL KLATIN LETTER SMALL CAPITAL L WI" +
"TH STROKELATIN LETTER SMALL CAPITAL MLATIN LETTER SMALL CAPITAL REVERSED" +
" NLATIN LETTER SMALL CAPITAL OLATIN LETTER SMALL CAPITAL OPEN OLATIN SMA" +
"LL LETTER SIDEWAYS OLATIN SMALL LETTER SIDEWAYS OPEN OLATIN SMALL LETTER" +
" SIDEWAYS O WITH STROKELATIN SMALL LETTER TURNED OELATIN LETTER SMALL CA" +
"PITAL OULATIN SMALL LETTER TOP HALF OLATIN SMALL LETTER BOTTOM HALF OLAT" +
"IN LETTER SMALL CAPITAL PLATIN LETTER SMALL CAPITAL REVERSED RLATIN LETT" +
"ER SMALL CAPITAL TURNED RLATIN LETTER SMALL CAPITAL TLATIN LETTER SMALL " +
"CAPITAL ULATIN SMALL LETTER SIDEWAYS ULATIN SMALL LETTER SIDEWAYS DIAERE" +
"SIZED ULATIN SMALL LETTER SIDEWAYS TURNED MLATIN LETTER SMALL CAPITAL VL" +
"ATIN LETTER SMALL CAPITAL WLATIN LETTER SMALL CAPITAL ZLATIN LETTER SMAL" +
"L CAPITAL EZHLATIN LETTER VOICED LARYNGEAL SPIRANTLATIN LETTER AINGREEK " +
"LETTER SMALL CAPITAL GAMMAGREEK LETTER SMALL CAPITAL LAMDAGREEK LETTER S" +
"MALL CAPITAL PIGREEK LETTER SMALL CAPITAL RHOGREEK LETTER SMALL CAPITAL " +
"PSICYRILLIC LETTER SMALL CAPITAL ELMODIFIER LETTER CAPITAL AMODIFIER LET" +
"TER CAPITAL AEMODIFIER LETTER CAPITAL BMODIFIER LETTER CAPITAL BARRED BM" +
"ODIFIER LETTER CAPITAL DMODIFIER LETTER CAPITAL EMODIFIER LETTER CAPITAL" +
" REVERSED EMODIFIER LETTER CAPITAL GMODIFIER LETTER CAPITAL HMODIFIER LE" +
"TTER CAPITAL IMODIFIER LETTER CAPITAL JMODIFIER LETTER CAPITAL KMODIFIER" +
" LETTER CAPITAL LMODIFIER LETTER CAPITAL MMODIFIER LETTER CAPITAL NMODIF" +
"IER LETTER CAPITAL REVERSED NMODIFIER LETTER CAPITAL OMODIFIER LETTER CA" +
"PITAL OUMODIFIER LETTER CAPITAL PMODIFIER LETTER CAPITAL RMODIFIER LETTE" +
"R CAPITAL TMODIFIER LETTER CAPITAL UMODIFIER LETTER CAPITAL WMODIFIER LE") + ("" +
"TTER SMALL AMODIFIER LETTER SMALL TURNED AMODIFIER LETTER SMALL ALPHAMOD" +
"IFIER LETTER SMALL TURNED AEMODIFIER LETTER SMALL BMODIFIER LETTER SMALL" +
" DMODIFIER LETTER SMALL EMODIFIER LETTER SMALL SCHWAMODIFIER LETTER SMAL" +
"L OPEN EMODIFIER LETTER SMALL TURNED OPEN EMODIFIER LETTER SMALL GMODIFI" +
"ER LETTER SMALL TURNED IMODIFIER LETTER SMALL KMODIFIER LETTER SMALL MMO" +
"DIFIER LETTER SMALL ENGMODIFIER LETTER SMALL OMODIFIER LETTER SMALL OPEN" +
" OMODIFIER LETTER SMALL TOP HALF OMODIFIER LETTER SMALL BOTTOM HALF OMOD" +
"IFIER LETTER SMALL PMODIFIER LETTER SMALL TMODIFIER LETTER SMALL UMODIFI" +
"ER LETTER SMALL SIDEWAYS UMODIFIER LETTER SMALL TURNED MMODIFIER LETTER " +
"SMALL VMODIFIER LETTER SMALL AINMODIFIER LETTER SMALL BETAMODIFIER LETTE" +
"R SMALL GREEK GAMMAMODIFIER LETTER SMALL DELTAMODIFIER LETTER SMALL GREE" +
"K PHIMODIFIER LETTER SMALL CHILATIN SUBSCRIPT SMALL LETTER ILATIN SUBSCR" +
"IPT SMALL LETTER RLATIN SUBSCRIPT SMALL LETTER ULATIN SUBSCRIPT SMALL LE" +
"TTER VGREEK SUBSCRIPT SMALL LETTER BETAGREEK SUBSCRIPT SMALL LETTER GAMM" +
"AGREEK SUBSCRIPT SMALL LETTER RHOGREEK SUBSCRIPT SMALL LETTER PHIGREEK S" +
"UBSCRIPT SMALL LETTER CHILATIN SMALL LETTER UELATIN SMALL LETTER B WITH " +
"MIDDLE TILDELATIN SMALL LETTER D WITH MIDDLE TILDELATIN SMALL LETTER F W" +
"ITH MIDDLE TILDELATIN SMALL LETTER M WITH MIDDLE TILDELATIN SMALL LETTER" +
" N WITH MIDDLE TILDELATIN SMALL LETTER P WITH MIDDLE TILDELATIN SMALL LE" +
"TTER R WITH MIDDLE TILDELATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TI" +
"LDELATIN SMALL LETTER S WITH MIDDLE TILDELATIN SMALL LETTER T WITH MIDDL" +
"E TILDELATIN SMALL LETTER Z WITH MIDDLE TILDELATIN SMALL LETTER TURNED G" +
"MODIFIER LETTER CYRILLIC ENLATIN SMALL LETTER INSULAR GLATIN SMALL LETTE" +
"R TH WITH STRIKETHROUGHLATIN SMALL CAPITAL LETTER I WITH STROKELATIN SMA" +
"LL LETTER IOTA WITH STROKELATIN SMALL LETTER P WITH STROKELATIN SMALL CA" +
"PITAL LETTER U WITH STROKELATIN SMALL LETTER UPSILON WITH STROKELATIN SM" +
"ALL LETTER B WITH PALATAL HOOKLATIN SMALL LETTER D WITH PALATAL HOOKLATI" +
"N SMALL LETTER F WITH PALATAL HOOKLATIN SMALL LETTER G WITH PALATAL HOOK" +
"LATIN SMALL LETTER K WITH PALATAL HOOKLATIN SMALL LETTER L WITH PALATAL " +
"HOOKLATIN SMALL LETTER M WITH PALATAL HOOKLATIN SMALL LETTER N WITH PALA" +
"TAL HOOKLATIN SMALL LETTER P WITH PALATAL HOOKLATIN SMALL LETTER R WITH " +
"PALATAL HOOKLATIN SMALL LETTER S WITH PALATAL HOOKLATIN SMALL LETTER ESH" +
" WITH PALATAL HOOKLATIN SMALL LETTER V WITH PALATAL HOOKLATIN SMALL LETT" +
"ER X WITH PALATAL HOOKLATIN SMALL LETTER Z WITH PALATAL HOOKLATIN SMALL " +
"LETTER A WITH RETROFLEX HOOKLATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK" +
"LATIN SMALL LETTER D WITH HOOK AND TAILLATIN SMALL LETTER E WITH RETROFL" +
"EX HOOKLATIN SMALL LETTER OPEN E WITH RETROFLEX HOOKLATIN SMALL LETTER R" +
"EVERSED OPEN E WITH RETROFLEX HOOKLATIN SMALL LETTER SCHWA WITH RETROFLE" +
"X HOOKLATIN SMALL LETTER I WITH RETROFLEX HOOKLATIN SMALL LETTER OPEN O " +
"WITH RETROFLEX HOOKLATIN SMALL LETTER ESH WITH RETROFLEX HOOKLATIN SMALL" +
" LETTER U WITH RETROFLEX HOOKLATIN SMALL LETTER EZH WITH RETROFLEX HOOKM" +
"ODIFIER LETTER SMALL TURNED ALPHAMODIFIER LETTER SMALL CMODIFIER LETTER " +
"SMALL C WITH CURLMODIFIER LETTER SMALL ETHMODIFIER LETTER SMALL REVERSED" +
" OPEN EMODIFIER LETTER SMALL FMODIFIER LETTER SMALL DOTLESS J WITH STROK" +
"EMODIFIER LETTER SMALL SCRIPT GMODIFIER LETTER SMALL TURNED HMODIFIER LE" +
"TTER SMALL I WITH STROKEMODIFIER LETTER SMALL IOTAMODIFIER LETTER SMALL " +
"CAPITAL IMODIFIER LETTER SMALL CAPITAL I WITH STROKEMODIFIER LETTER SMAL" +
"L J WITH CROSSED-TAILMODIFIER LETTER SMALL L WITH RETROFLEX HOOKMODIFIER" +
" LETTER SMALL L WITH PALATAL HOOKMODIFIER LETTER SMALL CAPITAL LMODIFIER" +
" LETTER SMALL M WITH HOOKMODIFIER LETTER SMALL TURNED M WITH LONG LEGMOD" +
"IFIER LETTER SMALL N WITH LEFT HOOKMODIFIER LETTER SMALL N WITH RETROFLE" +
"X HOOKMODIFIER LETTER SMALL CAPITAL NMODIFIER LETTER SMALL BARRED OMODIF" +
"IER LETTER SMALL PHIMODIFIER LETTER SMALL S WITH HOOKMODIFIER LETTER SMA" +
"LL ESHMODIFIER LETTER SMALL T WITH PALATAL HOOKMODIFIER LETTER SMALL U B" +
"ARMODIFIER LETTER SMALL UPSILONMODIFIER LETTER SMALL CAPITAL UMODIFIER L" +
"ETTER SMALL V WITH HOOKMODIFIER LETTER SMALL TURNED VMODIFIER LETTER SMA" +
"LL ZMODIFIER LETTER SMALL Z WITH RETROFLEX HOOKMODIFIER LETTER SMALL Z W" +
"ITH CURLMODIFIER LETTER SMALL EZHMODIFIER LETTER SMALL THETACOMBINING DO" +
"TTED GRAVE ACCENTCOMBINING DOTTED ACUTE ACCENTCOMBINING SNAKE BELOWCOMBI" +
"NING SUSPENSION MARKCOMBINING MACRON-ACUTECOMBINING GRAVE-MACRONCOMBININ" +
"G MACRON-GRAVECOMBINING ACUTE-MACRONCOMBINING GRAVE-ACUTE-GRAVECOMBINING" +
" ACUTE-GRAVE-ACUTECOMBINING LATIN SMALL LETTER R BELOWCOMBINING BREVE-MA" +
"CRONCOMBINING MACRON-BREVECOMBINING DOUBLE CIRCUMFLEX ABOVECOMBINING OGO" +
"NEK ABOVECOMBINING ZIGZAG BELOWCOMBINING IS BELOWCOMBINING UR ABOVECOMBI") + ("" +
"NING US ABOVECOMBINING LATIN SMALL LETTER FLATTENED OPEN A ABOVECOMBININ" +
"G LATIN SMALL LETTER AECOMBINING LATIN SMALL LETTER AOCOMBINING LATIN SM" +
"ALL LETTER AVCOMBINING LATIN SMALL LETTER C CEDILLACOMBINING LATIN SMALL" +
" LETTER INSULAR DCOMBINING LATIN SMALL LETTER ETHCOMBINING LATIN SMALL L" +
"ETTER GCOMBINING LATIN LETTER SMALL CAPITAL GCOMBINING LATIN SMALL LETTE" +
"R KCOMBINING LATIN SMALL LETTER LCOMBINING LATIN LETTER SMALL CAPITAL LC" +
"OMBINING LATIN LETTER SMALL CAPITAL MCOMBINING LATIN SMALL LETTER NCOMBI" +
"NING LATIN LETTER SMALL CAPITAL NCOMBINING LATIN LETTER SMALL CAPITAL RC" +
"OMBINING LATIN SMALL LETTER R ROTUNDACOMBINING LATIN SMALL LETTER SCOMBI" +
"NING LATIN SMALL LETTER LONG SCOMBINING LATIN SMALL LETTER ZCOMBINING LA" +
"TIN SMALL LETTER ALPHACOMBINING LATIN SMALL LETTER BCOMBINING LATIN SMAL" +
"L LETTER BETACOMBINING LATIN SMALL LETTER SCHWACOMBINING LATIN SMALL LET" +
"TER FCOMBINING LATIN SMALL LETTER L WITH DOUBLE MIDDLE TILDECOMBINING LA" +
"TIN SMALL LETTER O WITH LIGHT CENTRALIZATION STROKECOMBINING LATIN SMALL" +
" LETTER PCOMBINING LATIN SMALL LETTER ESHCOMBINING LATIN SMALL LETTER U " +
"WITH LIGHT CENTRALIZATION STROKECOMBINING LATIN SMALL LETTER WCOMBINING " +
"LATIN SMALL LETTER A WITH DIAERESISCOMBINING LATIN SMALL LETTER O WITH D" +
"IAERESISCOMBINING LATIN SMALL LETTER U WITH DIAERESISCOMBINING UP TACK A" +
"BOVECOMBINING KAVYKA ABOVE RIGHTCOMBINING KAVYKA ABOVE LEFTCOMBINING DOT" +
" ABOVE LEFTCOMBINING WIDE INVERTED BRIDGE BELOWCOMBINING DOT BELOW LEFTC" +
"OMBINING DELETION MARKCOMBINING DOUBLE INVERTED BREVE BELOWCOMBINING ALM" +
"OST EQUAL TO BELOWCOMBINING LEFT ARROWHEAD ABOVECOMBINING RIGHT ARROWHEA" +
"D AND DOWN ARROWHEAD BELOWLATIN CAPITAL LETTER A WITH RING BELOWLATIN SM" +
"ALL LETTER A WITH RING BELOWLATIN CAPITAL LETTER B WITH DOT ABOVELATIN S" +
"MALL LETTER B WITH DOT ABOVELATIN CAPITAL LETTER B WITH DOT BELOWLATIN S" +
"MALL LETTER B WITH DOT BELOWLATIN CAPITAL LETTER B WITH LINE BELOWLATIN " +
"SMALL LETTER B WITH LINE BELOWLATIN CAPITAL LETTER C WITH CEDILLA AND AC" +
"UTELATIN SMALL LETTER C WITH CEDILLA AND ACUTELATIN CAPITAL LETTER D WIT" +
"H DOT ABOVELATIN SMALL LETTER D WITH DOT ABOVELATIN CAPITAL LETTER D WIT" +
"H DOT BELOWLATIN SMALL LETTER D WITH DOT BELOWLATIN CAPITAL LETTER D WIT" +
"H LINE BELOWLATIN SMALL LETTER D WITH LINE BELOWLATIN CAPITAL LETTER D W" +
"ITH CEDILLALATIN SMALL LETTER D WITH CEDILLALATIN CAPITAL LETTER D WITH " +
"CIRCUMFLEX BELOWLATIN SMALL LETTER D WITH CIRCUMFLEX BELOWLATIN CAPITAL " +
"LETTER E WITH MACRON AND GRAVELATIN SMALL LETTER E WITH MACRON AND GRAVE" +
"LATIN CAPITAL LETTER E WITH MACRON AND ACUTELATIN SMALL LETTER E WITH MA" +
"CRON AND ACUTELATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOWLATIN SMALL LE" +
"TTER E WITH CIRCUMFLEX BELOWLATIN CAPITAL LETTER E WITH TILDE BELOWLATIN" +
" SMALL LETTER E WITH TILDE BELOWLATIN CAPITAL LETTER E WITH CEDILLA AND " +
"BREVELATIN SMALL LETTER E WITH CEDILLA AND BREVELATIN CAPITAL LETTER F W" +
"ITH DOT ABOVELATIN SMALL LETTER F WITH DOT ABOVELATIN CAPITAL LETTER G W" +
"ITH MACRONLATIN SMALL LETTER G WITH MACRONLATIN CAPITAL LETTER H WITH DO" +
"T ABOVELATIN SMALL LETTER H WITH DOT ABOVELATIN CAPITAL LETTER H WITH DO" +
"T BELOWLATIN SMALL LETTER H WITH DOT BELOWLATIN CAPITAL LETTER H WITH DI" +
"AERESISLATIN SMALL LETTER H WITH DIAERESISLATIN CAPITAL LETTER H WITH CE" +
"DILLALATIN SMALL LETTER H WITH CEDILLALATIN CAPITAL LETTER H WITH BREVE " +
"BELOWLATIN SMALL LETTER H WITH BREVE BELOWLATIN CAPITAL LETTER I WITH TI" +
"LDE BELOWLATIN SMALL LETTER I WITH TILDE BELOWLATIN CAPITAL LETTER I WIT" +
"H 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 WITH DOT BELOWLATIN CAPITAL " +
"LETTER K WITH LINE BELOWLATIN SMALL LETTER K WITH LINE BELOWLATIN CAPITA" +
"L LETTER L WITH DOT BELOWLATIN SMALL LETTER L WITH DOT BELOWLATIN CAPITA" +
"L LETTER L WITH DOT BELOW AND MACRONLATIN SMALL LETTER L WITH DOT BELOW " +
"AND MACRONLATIN CAPITAL LETTER L WITH LINE BELOWLATIN SMALL LETTER L WIT" +
"H LINE BELOWLATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOWLATIN SMALL LETT" +
"ER L WITH CIRCUMFLEX BELOWLATIN CAPITAL LETTER M WITH ACUTELATIN SMALL L" +
"ETTER M WITH ACUTELATIN CAPITAL LETTER M WITH DOT ABOVELATIN SMALL LETTE" +
"R M WITH DOT ABOVELATIN CAPITAL LETTER M WITH DOT BELOWLATIN SMALL LETTE" +
"R M WITH DOT BELOWLATIN CAPITAL LETTER N WITH DOT ABOVELATIN SMALL LETTE" +
"R N WITH DOT ABOVELATIN CAPITAL LETTER N WITH DOT BELOWLATIN SMALL LETTE" +
"R N WITH DOT BELOWLATIN CAPITAL LETTER N WITH LINE BELOWLATIN SMALL LETT" +
"ER N WITH LINE BELOWLATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOWLATIN SM" +
"ALL LETTER N WITH CIRCUMFLEX BELOWLATIN CAPITAL LETTER O WITH TILDE AND " +
"ACUTELATIN SMALL LETTER O WITH TILDE AND ACUTELATIN CAPITAL LETTER O WIT") + ("" +
"H TILDE AND DIAERESISLATIN SMALL LETTER O WITH TILDE AND DIAERESISLATIN " +
"CAPITAL LETTER O WITH MACRON AND GRAVELATIN SMALL LETTER O WITH MACRON A" +
"ND GRAVELATIN CAPITAL LETTER O WITH MACRON AND ACUTELATIN SMALL LETTER O" +
" WITH MACRON AND ACUTELATIN CAPITAL LETTER P WITH ACUTELATIN SMALL LETTE" +
"R 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 SMAL" +
"L LETTER R WITH DOT BELOW AND MACRONLATIN CAPITAL LETTER R WITH LINE BEL" +
"OWLATIN SMALL LETTER R WITH LINE BELOWLATIN CAPITAL LETTER S WITH DOT AB" +
"OVELATIN SMALL LETTER S WITH DOT ABOVELATIN CAPITAL LETTER S WITH DOT BE" +
"LOWLATIN SMALL LETTER S WITH DOT BELOWLATIN CAPITAL LETTER S WITH ACUTE " +
"AND DOT ABOVELATIN SMALL LETTER S WITH ACUTE AND DOT ABOVELATIN CAPITAL " +
"LETTER S WITH CARON AND DOT ABOVELATIN SMALL LETTER S WITH CARON AND DOT" +
" ABOVELATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVELATIN SMALL LET" +
"TER S WITH DOT BELOW AND DOT ABOVELATIN CAPITAL LETTER T WITH DOT ABOVEL" +
"ATIN SMALL LETTER T WITH DOT ABOVELATIN CAPITAL LETTER T WITH DOT BELOWL" +
"ATIN SMALL LETTER T WITH DOT BELOWLATIN CAPITAL LETTER T WITH LINE BELOW" +
"LATIN SMALL LETTER T WITH LINE BELOWLATIN CAPITAL LETTER T WITH CIRCUMFL" +
"EX BELOWLATIN SMALL LETTER T WITH CIRCUMFLEX BELOWLATIN CAPITAL LETTER U" +
" WITH DIAERESIS BELOWLATIN SMALL LETTER U WITH DIAERESIS BELOWLATIN CAPI" +
"TAL LETTER U WITH TILDE BELOWLATIN SMALL LETTER U WITH TILDE BELOWLATIN " +
"CAPITAL LETTER U WITH CIRCUMFLEX BELOWLATIN SMALL LETTER U WITH CIRCUMFL" +
"EX BELOWLATIN CAPITAL LETTER U WITH TILDE AND ACUTELATIN SMALL LETTER U " +
"WITH TILDE AND ACUTELATIN CAPITAL LETTER U WITH MACRON AND DIAERESISLATI" +
"N SMALL LETTER U WITH MACRON AND DIAERESISLATIN CAPITAL LETTER V WITH TI" +
"LDELATIN SMALL LETTER V WITH TILDELATIN CAPITAL LETTER V WITH DOT BELOWL" +
"ATIN SMALL LETTER V WITH DOT BELOWLATIN CAPITAL LETTER W WITH GRAVELATIN" +
" SMALL LETTER W WITH GRAVELATIN CAPITAL LETTER W WITH ACUTELATIN SMALL L" +
"ETTER W WITH ACUTELATIN CAPITAL LETTER W WITH DIAERESISLATIN SMALL LETTE" +
"R W WITH DIAERESISLATIN CAPITAL LETTER W WITH DOT ABOVELATIN SMALL LETTE" +
"R W WITH DOT ABOVELATIN CAPITAL LETTER W WITH DOT BELOWLATIN SMALL LETTE" +
"R W WITH DOT BELOWLATIN CAPITAL LETTER X WITH DOT ABOVELATIN SMALL LETTE" +
"R X WITH DOT ABOVELATIN CAPITAL LETTER X WITH DIAERESISLATIN SMALL LETTE" +
"R X WITH DIAERESISLATIN CAPITAL LETTER Y WITH DOT ABOVELATIN SMALL LETTE" +
"R Y WITH DOT ABOVELATIN CAPITAL LETTER Z WITH CIRCUMFLEXLATIN SMALL LETT" +
"ER Z WITH CIRCUMFLEXLATIN CAPITAL LETTER Z WITH DOT BELOWLATIN SMALL LET" +
"TER Z WITH DOT BELOWLATIN CAPITAL LETTER Z WITH LINE BELOWLATIN SMALL LE" +
"TTER Z WITH LINE BELOWLATIN SMALL LETTER H WITH LINE BELOWLATIN SMALL LE" +
"TTER T WITH DIAERESISLATIN SMALL LETTER W WITH RING ABOVELATIN SMALL LET" +
"TER Y WITH RING ABOVELATIN SMALL LETTER A WITH RIGHT HALF RINGLATIN SMAL" +
"L LETTER LONG S WITH DOT ABOVELATIN SMALL LETTER LONG S WITH DIAGONAL ST" +
"ROKELATIN SMALL LETTER LONG S WITH HIGH STROKELATIN CAPITAL LETTER SHARP" +
" SLATIN SMALL LETTER DELTALATIN CAPITAL LETTER A WITH DOT BELOWLATIN SMA" +
"LL LETTER A WITH DOT BELOWLATIN CAPITAL LETTER A WITH HOOK ABOVELATIN SM" +
"ALL LETTER A WITH HOOK ABOVELATIN CAPITAL LETTER A WITH CIRCUMFLEX AND A" +
"CUTELATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTELATIN CAPITAL LETTER A" +
" WITH CIRCUMFLEX AND GRAVELATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE" +
"LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVELATIN SMALL LETTER " +
"A WITH CIRCUMFLEX AND HOOK ABOVELATIN CAPITAL LETTER A WITH CIRCUMFLEX A" +
"ND TILDELATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDELATIN CAPITAL LETT" +
"ER A WITH CIRCUMFLEX AND DOT BELOWLATIN SMALL LETTER A WITH CIRCUMFLEX A" +
"ND DOT BELOWLATIN CAPITAL LETTER A WITH BREVE AND ACUTELATIN SMALL LETTE" +
"R A WITH BREVE AND ACUTELATIN CAPITAL LETTER A WITH BREVE AND GRAVELATIN" +
" SMALL LETTER A WITH BREVE AND GRAVELATIN CAPITAL LETTER A WITH BREVE AN" +
"D HOOK ABOVELATIN SMALL LETTER A WITH BREVE AND HOOK ABOVELATIN CAPITAL " +
"LETTER A WITH BREVE AND TILDELATIN SMALL LETTER A WITH BREVE AND TILDELA" +
"TIN CAPITAL LETTER A WITH BREVE AND DOT BELOWLATIN SMALL LETTER A WITH B" +
"REVE AND DOT BELOWLATIN CAPITAL LETTER E WITH DOT BELOWLATIN SMALL LETTE" +
"R E WITH DOT BELOWLATIN CAPITAL LETTER E WITH HOOK ABOVELATIN SMALL LETT" +
"ER E WITH HOOK ABOVELATIN CAPITAL LETTER E WITH TILDELATIN SMALL LETTER " +
"E WITH TILDELATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTELATIN SMALL " +
"LETTER E WITH CIRCUMFLEX AND ACUTELATIN CAPITAL LETTER E WITH CIRCUMFLEX" +
" AND GRAVELATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVELATIN CAPITAL LE") + ("" +
"TTER E WITH CIRCUMFLEX AND HOOK ABOVELATIN SMALL LETTER E WITH CIRCUMFLE" +
"X AND HOOK ABOVELATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDELATIN SM" +
"ALL LETTER E WITH CIRCUMFLEX AND TILDELATIN CAPITAL LETTER E WITH CIRCUM" +
"FLEX AND DOT BELOWLATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOWLATI" +
"N CAPITAL LETTER I WITH HOOK ABOVELATIN SMALL LETTER I WITH HOOK ABOVELA" +
"TIN CAPITAL LETTER I WITH DOT BELOWLATIN SMALL LETTER I WITH DOT BELOWLA" +
"TIN CAPITAL LETTER O WITH DOT BELOWLATIN SMALL LETTER O WITH DOT BELOWLA" +
"TIN CAPITAL LETTER O WITH HOOK ABOVELATIN SMALL LETTER O WITH HOOK ABOVE" +
"LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTELATIN SMALL LETTER O WIT" +
"H CIRCUMFLEX AND ACUTELATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVELA" +
"TIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVELATIN CAPITAL LETTER O WITH " +
"CIRCUMFLEX AND HOOK ABOVELATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK A" +
"BOVELATIN 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 LE" +
"TTER O WITH HORN AND ACUTELATIN SMALL LETTER O WITH HORN AND ACUTELATIN " +
"CAPITAL LETTER O WITH HORN AND GRAVELATIN SMALL LETTER O WITH HORN AND G" +
"RAVELATIN 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 CAPITAL LETTER O WITH HORN AND D" +
"OT 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 HOOK ABOVELATIN CAPITAL LETT" +
"ER U WITH HORN AND ACUTELATIN SMALL LETTER U WITH HORN AND ACUTELATIN CA" +
"PITAL LETTER U WITH HORN AND GRAVELATIN SMALL LETTER U WITH HORN AND GRA" +
"VELATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVELATIN SMALL LETTER U WI" +
"TH HORN AND HOOK ABOVELATIN CAPITAL LETTER U WITH HORN AND TILDELATIN SM" +
"ALL LETTER U WITH HORN AND TILDELATIN CAPITAL LETTER U WITH HORN AND DOT" +
" BELOWLATIN SMALL LETTER U WITH HORN AND DOT BELOWLATIN CAPITAL LETTER Y" +
" WITH GRAVELATIN SMALL LETTER Y WITH GRAVELATIN CAPITAL LETTER Y WITH DO" +
"T BELOWLATIN SMALL LETTER Y WITH DOT BELOWLATIN CAPITAL LETTER Y WITH HO" +
"OK ABOVELATIN SMALL LETTER Y WITH HOOK ABOVELATIN CAPITAL LETTER Y WITH " +
"TILDELATIN SMALL LETTER Y WITH TILDELATIN CAPITAL LETTER MIDDLE-WELSH LL" +
"LATIN SMALL LETTER MIDDLE-WELSH LLLATIN CAPITAL LETTER MIDDLE-WELSH VLAT" +
"IN SMALL LETTER MIDDLE-WELSH VLATIN CAPITAL LETTER Y WITH LOOPLATIN SMAL" +
"L LETTER Y WITH LOOPGREEK SMALL LETTER ALPHA WITH PSILIGREEK SMALL LETTE" +
"R ALPHA WITH DASIAGREEK SMALL LETTER ALPHA WITH PSILI AND VARIAGREEK SMA" +
"LL LETTER ALPHA WITH DASIA AND VARIAGREEK SMALL LETTER ALPHA WITH PSILI " +
"AND OXIAGREEK SMALL LETTER ALPHA WITH DASIA AND OXIAGREEK SMALL LETTER A" +
"LPHA WITH PSILI AND PERISPOMENIGREEK SMALL LETTER ALPHA WITH DASIA AND P" +
"ERISPOMENIGREEK CAPITAL LETTER ALPHA WITH PSILIGREEK CAPITAL LETTER ALPH" +
"A WITH DASIAGREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIAGREEK CAPITAL" +
" LETTER ALPHA WITH DASIA AND VARIAGREEK CAPITAL LETTER ALPHA WITH PSILI " +
"AND OXIAGREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIAGREEK CAPITAL LETT" +
"ER ALPHA WITH PSILI AND PERISPOMENIGREEK CAPITAL LETTER ALPHA WITH DASIA" +
" AND PERISPOMENIGREEK SMALL LETTER EPSILON WITH PSILIGREEK SMALL LETTER " +
"EPSILON WITH DASIAGREEK SMALL LETTER EPSILON WITH PSILI AND VARIAGREEK S" +
"MALL LETTER EPSILON WITH DASIA AND VARIAGREEK SMALL LETTER EPSILON WITH " +
"PSILI AND OXIAGREEK SMALL LETTER EPSILON WITH DASIA AND OXIAGREEK CAPITA" +
"L LETTER EPSILON WITH PSILIGREEK CAPITAL LETTER EPSILON WITH DASIAGREEK " +
"CAPITAL LETTER EPSILON WITH PSILI AND VARIAGREEK CAPITAL LETTER EPSILON " +
"WITH DASIA AND VARIAGREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIAGREE" +
"K CAPITAL LETTER EPSILON WITH DASIA AND OXIAGREEK SMALL LETTER ETA WITH " +
"PSILIGREEK SMALL LETTER ETA WITH DASIAGREEK SMALL LETTER ETA WITH PSILI " +
"AND VARIAGREEK SMALL LETTER ETA WITH DASIA AND VARIAGREEK SMALL LETTER E" +
"TA WITH PSILI AND OXIAGREEK SMALL LETTER ETA WITH DASIA AND OXIAGREEK SM" +
"ALL LETTER ETA WITH PSILI AND PERISPOMENIGREEK SMALL LETTER ETA WITH DAS" +
"IA AND PERISPOMENIGREEK CAPITAL LETTER ETA WITH PSILIGREEK CAPITAL LETTE" +
"R ETA WITH DASIAGREEK CAPITAL LETTER ETA WITH PSILI AND VARIAGREEK CAPIT" +
"AL LETTER ETA WITH DASIA AND VARIAGREEK CAPITAL LETTER ETA WITH PSILI AN" +
"D OXIAGREEK CAPITAL LETTER ETA WITH DASIA AND OXIAGREEK CAPITAL LETTER E" +
"TA WITH PSILI AND PERISPOMENIGREEK CAPITAL LETTER ETA WITH DASIA AND PER" +
"ISPOMENIGREEK SMALL LETTER IOTA WITH PSILIGREEK SMALL LETTER IOTA WITH D" +
"ASIAGREEK SMALL LETTER IOTA WITH PSILI AND VARIAGREEK SMALL LETTER IOTA ") + ("" +
"WITH DASIA AND VARIAGREEK SMALL LETTER IOTA WITH PSILI AND OXIAGREEK SMA" +
"LL LETTER IOTA WITH DASIA AND OXIAGREEK SMALL LETTER IOTA WITH PSILI AND" +
" PERISPOMENIGREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENIGREEK CAPI" +
"TAL LETTER IOTA WITH PSILIGREEK CAPITAL LETTER IOTA WITH DASIAGREEK CAPI" +
"TAL LETTER IOTA WITH PSILI AND VARIAGREEK CAPITAL LETTER IOTA WITH DASIA" +
" AND VARIAGREEK CAPITAL LETTER IOTA WITH PSILI AND OXIAGREEK CAPITAL LET" +
"TER IOTA WITH DASIA AND OXIAGREEK CAPITAL LETTER IOTA WITH PSILI AND PER" +
"ISPOMENIGREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENIGREEK SMALL " +
"LETTER OMICRON WITH PSILIGREEK SMALL LETTER OMICRON WITH DASIAGREEK SMAL" +
"L LETTER OMICRON WITH PSILI AND VARIAGREEK SMALL LETTER OMICRON WITH DAS" +
"IA AND VARIAGREEK SMALL LETTER OMICRON WITH PSILI AND OXIAGREEK SMALL LE" +
"TTER OMICRON WITH DASIA AND OXIAGREEK CAPITAL LETTER OMICRON WITH PSILIG" +
"REEK CAPITAL LETTER OMICRON WITH DASIAGREEK CAPITAL LETTER OMICRON WITH " +
"PSILI AND VARIAGREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIAGREEK CA" +
"PITAL LETTER OMICRON WITH PSILI AND OXIAGREEK CAPITAL LETTER OMICRON WIT" +
"H DASIA AND OXIAGREEK SMALL LETTER UPSILON WITH PSILIGREEK SMALL LETTER " +
"UPSILON WITH DASIAGREEK SMALL LETTER UPSILON WITH PSILI AND VARIAGREEK S" +
"MALL 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 UPSILON WITH DASIAGREEK CAPIT" +
"AL LETTER UPSILON WITH DASIA AND VARIAGREEK CAPITAL LETTER UPSILON WITH " +
"DASIA AND OXIAGREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENIGRE" +
"EK SMALL LETTER OMEGA WITH PSILIGREEK SMALL LETTER OMEGA WITH DASIAGREEK" +
" SMALL LETTER OMEGA WITH PSILI AND VARIAGREEK SMALL LETTER OMEGA WITH DA" +
"SIA AND VARIAGREEK SMALL LETTER OMEGA WITH PSILI AND OXIAGREEK SMALL LET" +
"TER OMEGA WITH DASIA AND OXIAGREEK SMALL LETTER OMEGA WITH PSILI AND PER" +
"ISPOMENIGREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENIGREEK CAPITAL" +
" LETTER OMEGA WITH PSILIGREEK CAPITAL LETTER OMEGA WITH DASIAGREEK CAPIT" +
"AL LETTER OMEGA WITH PSILI AND VARIAGREEK CAPITAL LETTER OMEGA WITH DASI" +
"A AND VARIAGREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIAGREEK CAPITAL L" +
"ETTER OMEGA WITH DASIA AND OXIAGREEK CAPITAL LETTER OMEGA WITH PSILI AND" +
" PERISPOMENIGREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENIGREEK S" +
"MALL LETTER ALPHA WITH VARIAGREEK SMALL LETTER ALPHA WITH OXIAGREEK SMAL" +
"L LETTER EPSILON WITH VARIAGREEK SMALL LETTER EPSILON WITH OXIAGREEK SMA" +
"LL LETTER ETA WITH VARIAGREEK SMALL LETTER ETA WITH OXIAGREEK SMALL LETT" +
"ER IOTA WITH VARIAGREEK SMALL LETTER IOTA WITH OXIAGREEK SMALL LETTER OM" +
"ICRON WITH VARIAGREEK SMALL LETTER OMICRON WITH OXIAGREEK SMALL LETTER U" +
"PSILON WITH VARIAGREEK SMALL LETTER UPSILON WITH OXIAGREEK SMALL LETTER " +
"OMEGA WITH VARIAGREEK SMALL LETTER OMEGA WITH OXIAGREEK SMALL LETTER ALP" +
"HA WITH PSILI AND YPOGEGRAMMENIGREEK SMALL LETTER ALPHA WITH DASIA AND Y" +
"POGEGRAMMENIGREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMM" +
"ENIGREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENIGREEK " +
"SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENIGREEK SMALL LETT" +
"ER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENIGREEK SMALL LETTER ALPHA W" +
"ITH PSILI AND PERISPOMENI AND YPOGEGRAMMENIGREEK SMALL LETTER ALPHA WITH" +
" DASIA AND PERISPOMENI AND YPOGEGRAMMENIGREEK CAPITAL LETTER ALPHA WITH " +
"PSILI AND PROSGEGRAMMENIGREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGE" +
"GRAMMENIGREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMME" +
"NIGREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENIGREE" +
"K CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENIGREEK CAPIT" +
"AL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENIGREEK CAPITAL LETT" +
"ER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENIGREEK CAPITAL LETT" +
"ER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENIGREEK SMALL LETTER" +
" ETA WITH PSILI AND YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH DASIA AND Y" +
"POGEGRAMMENIGREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMEN" +
"IGREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENIGREEK SMAL" +
"L LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENIGREEK SMALL LETTER ETA" +
" WITH DASIA AND OXIA AND YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH PSILI " +
"AND PERISPOMENI AND YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH DASIA AND P" +
"ERISPOMENI AND YPOGEGRAMMENIGREEK CAPITAL LETTER ETA WITH PSILI AND PROS" +
"GEGRAMMENIGREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENIGREEK CA" +
"PITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENIGREEK CAPITAL LE" +
"TTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER ETA") + ("" +
" WITH PSILI AND OXIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER ETA WITH DAS" +
"IA AND OXIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER ETA WITH PSILI AND PE" +
"RISPOMENI AND PROSGEGRAMMENIGREEK CAPITAL LETTER ETA WITH DASIA AND PERI" +
"SPOMENI AND PROSGEGRAMMENIGREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEG" +
"RAMMENIGREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENIGREEK SMALL " +
"LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENIGREEK SMALL LETTER OM" +
"EGA WITH DASIA AND VARIA AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WITH " +
"PSILI AND OXIA AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WITH DASIA AND " +
"OXIA AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMEN" +
"I AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI A" +
"ND YPOGEGRAMMENIGREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI" +
"GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENIGREEK CAPITAL LE" +
"TTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER O" +
"MEGA WITH DASIA AND VARIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER OMEGA W" +
"ITH PSILI AND OXIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER OMEGA WITH DAS" +
"IA AND OXIA AND PROSGEGRAMMENIGREEK CAPITAL LETTER OMEGA WITH PSILI AND " +
"PERISPOMENI AND PROSGEGRAMMENIGREEK CAPITAL LETTER OMEGA WITH DASIA AND " +
"PERISPOMENI AND PROSGEGRAMMENIGREEK SMALL LETTER ALPHA WITH VRACHYGREEK " +
"SMALL LETTER ALPHA WITH MACRONGREEK SMALL LETTER ALPHA WITH VARIA AND YP" +
"OGEGRAMMENIGREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENIGREEK SMALL LETTER" +
" ALPHA WITH OXIA AND YPOGEGRAMMENIGREEK SMALL LETTER ALPHA WITH PERISPOM" +
"ENIGREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENIGREEK CAPI" +
"TAL LETTER ALPHA WITH VRACHYGREEK CAPITAL LETTER ALPHA WITH MACRONGREEK " +
"CAPITAL LETTER ALPHA WITH VARIAGREEK CAPITAL LETTER ALPHA WITH OXIAGREEK" +
" CAPITAL LETTER ALPHA WITH PROSGEGRAMMENIGREEK KORONISGREEK PROSGEGRAMME" +
"NIGREEK PSILIGREEK PERISPOMENIGREEK DIALYTIKA AND PERISPOMENIGREEK SMALL" +
" LETTER ETA WITH VARIA AND YPOGEGRAMMENIGREEK SMALL LETTER ETA WITH YPOG" +
"EGRAMMENIGREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENIGREEK SMALL L" +
"ETTER ETA WITH PERISPOMENIGREEK SMALL LETTER ETA WITH PERISPOMENI AND YP" +
"OGEGRAMMENIGREEK CAPITAL LETTER EPSILON WITH VARIAGREEK CAPITAL LETTER E" +
"PSILON WITH OXIAGREEK CAPITAL LETTER ETA WITH VARIAGREEK CAPITAL LETTER " +
"ETA WITH OXIAGREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENIGREEK PSILI AND" +
" VARIAGREEK PSILI AND OXIAGREEK PSILI AND PERISPOMENIGREEK SMALL LETTER " +
"IOTA WITH VRACHYGREEK SMALL LETTER IOTA WITH MACRONGREEK SMALL LETTER IO" +
"TA WITH DIALYTIKA AND VARIAGREEK SMALL LETTER IOTA WITH DIALYTIKA AND OX" +
"IAGREEK SMALL LETTER IOTA WITH PERISPOMENIGREEK SMALL LETTER IOTA WITH D" +
"IALYTIKA AND PERISPOMENIGREEK CAPITAL LETTER IOTA WITH VRACHYGREEK CAPIT" +
"AL LETTER IOTA WITH MACRONGREEK CAPITAL LETTER IOTA WITH VARIAGREEK CAPI" +
"TAL LETTER IOTA WITH OXIAGREEK DASIA AND VARIAGREEK DASIA AND OXIAGREEK " +
"DASIA AND PERISPOMENIGREEK SMALL LETTER UPSILON WITH VRACHYGREEK SMALL L" +
"ETTER UPSILON WITH MACRONGREEK SMALL LETTER UPSILON WITH DIALYTIKA AND V" +
"ARIAGREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIAGREEK SMALL LETTER" +
" RHO WITH PSILIGREEK SMALL LETTER RHO WITH DASIAGREEK SMALL LETTER UPSIL" +
"ON WITH PERISPOMENIGREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPO" +
"MENIGREEK CAPITAL LETTER UPSILON WITH VRACHYGREEK 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 VA" +
"RIA AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENIGREEK SM" +
"ALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENIGREEK SMALL LETTER OMEGA WIT" +
"H PERISPOMENIGREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI" +
"GREEK CAPITAL LETTER OMICRON WITH VARIAGREEK CAPITAL LETTER OMICRON WITH" +
" OXIAGREEK CAPITAL LETTER OMEGA WITH VARIAGREEK CAPITAL LETTER OMEGA WIT" +
"H OXIAGREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENIGREEK OXIAGREEK DASI" +
"AEN QUADEM QUADEN SPACEEM SPACETHREE-PER-EM SPACEFOUR-PER-EM SPACESIX-PE" +
"R-EM SPACEFIGURE SPACEPUNCTUATION SPACETHIN SPACEHAIR SPACEZERO WIDTH SP" +
"ACEZERO WIDTH NON-JOINERZERO WIDTH JOINERLEFT-TO-RIGHT MARKRIGHT-TO-LEFT" +
" MARKHYPHENNON-BREAKING HYPHENFIGURE DASHEN DASHEM DASHHORIZONTAL BARDOU" +
"BLE VERTICAL LINEDOUBLE LOW LINELEFT SINGLE QUOTATION MARKRIGHT SINGLE Q" +
"UOTATION MARKSINGLE LOW-9 QUOTATION MARKSINGLE HIGH-REVERSED-9 QUOTATION" +
" MARKLEFT DOUBLE QUOTATION MARKRIGHT DOUBLE QUOTATION MARKDOUBLE LOW-9 Q" +
"UOTATION MARKDOUBLE HIGH-REVERSED-9 QUOTATION MARKDAGGERDOUBLE DAGGERBUL" +
"LETTRIANGULAR BULLETONE DOT LEADERTWO DOT LEADERHORIZONTAL ELLIPSISHYPHE" +
"NATION POINTLINE SEPARATORPARAGRAPH SEPARATORLEFT-TO-RIGHT EMBEDDINGRIGH") + ("" +
"T-TO-LEFT EMBEDDINGPOP DIRECTIONAL FORMATTINGLEFT-TO-RIGHT OVERRIDERIGHT" +
"-TO-LEFT OVERRIDENARROW NO-BREAK SPACEPER MILLE SIGNPER TEN THOUSAND SIG" +
"NPRIMEDOUBLE PRIMETRIPLE PRIMEREVERSED PRIMEREVERSED DOUBLE PRIMEREVERSE" +
"D TRIPLE PRIMECARETSINGLE LEFT-POINTING ANGLE QUOTATION MARKSINGLE RIGHT" +
"-POINTING ANGLE QUOTATION MARKREFERENCE MARKDOUBLE EXCLAMATION MARKINTER" +
"ROBANGOVERLINEUNDERTIECHARACTER TIECARET INSERTION POINTASTERISMHYPHEN B" +
"ULLETFRACTION SLASHLEFT SQUARE BRACKET WITH QUILLRIGHT SQUARE BRACKET WI" +
"TH QUILLDOUBLE QUESTION MARKQUESTION EXCLAMATION MARKEXCLAMATION QUESTIO" +
"N MARKTIRONIAN SIGN ETREVERSED PILCROW SIGNBLACK LEFTWARDS BULLETBLACK R" +
"IGHTWARDS BULLETLOW ASTERISKREVERSED SEMICOLONCLOSE UPTWO ASTERISKS ALIG" +
"NED VERTICALLYCOMMERCIAL MINUS SIGNSWUNG DASHINVERTED UNDERTIEFLOWER PUN" +
"CTUATION MARKTHREE DOT PUNCTUATIONQUADRUPLE PRIMEFOUR DOT PUNCTUATIONFIV" +
"E DOT PUNCTUATIONTWO DOT PUNCTUATIONFOUR DOT MARKDOTTED CROSSTRICOLONVER" +
"TICAL FOUR DOTSMEDIUM MATHEMATICAL SPACEWORD JOINERFUNCTION APPLICATIONI" +
"NVISIBLE TIMESINVISIBLE SEPARATORINVISIBLE PLUSLEFT-TO-RIGHT ISOLATERIGH" +
"T-TO-LEFT ISOLATEFIRST STRONG ISOLATEPOP DIRECTIONAL ISOLATEINHIBIT SYMM" +
"ETRIC SWAPPINGACTIVATE SYMMETRIC SWAPPINGINHIBIT ARABIC FORM SHAPINGACTI" +
"VATE ARABIC FORM SHAPINGNATIONAL DIGIT SHAPESNOMINAL DIGIT SHAPESSUPERSC" +
"RIPT ZEROSUPERSCRIPT LATIN SMALL LETTER ISUPERSCRIPT FOURSUPERSCRIPT FIV" +
"ESUPERSCRIPT SIXSUPERSCRIPT SEVENSUPERSCRIPT EIGHTSUPERSCRIPT NINESUPERS" +
"CRIPT PLUS SIGNSUPERSCRIPT MINUSSUPERSCRIPT EQUALS SIGNSUPERSCRIPT LEFT " +
"PARENTHESISSUPERSCRIPT RIGHT PARENTHESISSUPERSCRIPT LATIN SMALL LETTER N" +
"SUBSCRIPT ZEROSUBSCRIPT ONESUBSCRIPT TWOSUBSCRIPT THREESUBSCRIPT FOURSUB" +
"SCRIPT FIVESUBSCRIPT SIXSUBSCRIPT SEVENSUBSCRIPT EIGHTSUBSCRIPT NINESUBS" +
"CRIPT PLUS SIGNSUBSCRIPT MINUSSUBSCRIPT EQUALS SIGNSUBSCRIPT LEFT PARENT" +
"HESISSUBSCRIPT RIGHT PARENTHESISLATIN SUBSCRIPT SMALL LETTER ALATIN SUBS" +
"CRIPT SMALL LETTER ELATIN SUBSCRIPT SMALL LETTER OLATIN SUBSCRIPT SMALL " +
"LETTER XLATIN SUBSCRIPT SMALL LETTER SCHWALATIN SUBSCRIPT SMALL LETTER H" +
"LATIN SUBSCRIPT SMALL LETTER KLATIN SUBSCRIPT SMALL LETTER LLATIN SUBSCR" +
"IPT SMALL LETTER MLATIN SUBSCRIPT SMALL LETTER NLATIN SUBSCRIPT SMALL LE" +
"TTER PLATIN SUBSCRIPT SMALL LETTER SLATIN SUBSCRIPT SMALL LETTER TEURO-C" +
"URRENCY SIGNCOLON SIGNCRUZEIRO SIGNFRENCH FRANC SIGNLIRA SIGNMILL SIGNNA" +
"IRA SIGNPESETA SIGNRUPEE SIGNWON SIGNNEW SHEQEL SIGNDONG SIGNEURO SIGNKI" +
"P SIGNTUGRIK SIGNDRACHMA SIGNGERMAN PENNY SIGNPESO SIGNGUARANI SIGNAUSTR" +
"AL SIGNHRYVNIA SIGNCEDI SIGNLIVRE TOURNOIS SIGNSPESMILO SIGNTENGE SIGNIN" +
"DIAN RUPEE SIGNTURKISH LIRA SIGNNORDIC MARK SIGNMANAT SIGNRUBLE SIGNLARI" +
" SIGNBITCOIN SIGNSOM SIGNSAUDI RIYAL SIGNCOMBINING LEFT HARPOON ABOVECOM" +
"BINING RIGHT HARPOON ABOVECOMBINING LONG VERTICAL LINE OVERLAYCOMBINING " +
"SHORT VERTICAL LINE OVERLAYCOMBINING ANTICLOCKWISE ARROW ABOVECOMBINING " +
"CLOCKWISE ARROW ABOVECOMBINING LEFT ARROW ABOVECOMBINING RIGHT ARROW ABO" +
"VECOMBINING RING OVERLAYCOMBINING CLOCKWISE RING OVERLAYCOMBINING ANTICL" +
"OCKWISE RING OVERLAYCOMBINING THREE DOTS ABOVECOMBINING FOUR DOTS ABOVEC" +
"OMBINING ENCLOSING CIRCLECOMBINING ENCLOSING SQUARECOMBINING ENCLOSING D" +
"IAMONDCOMBINING ENCLOSING CIRCLE BACKSLASHCOMBINING LEFT RIGHT ARROW ABO" +
"VECOMBINING ENCLOSING SCREENCOMBINING ENCLOSING KEYCAPCOMBINING ENCLOSIN" +
"G UPWARD POINTING TRIANGLECOMBINING REVERSE SOLIDUS OVERLAYCOMBINING DOU" +
"BLE VERTICAL STROKE OVERLAYCOMBINING ANNUITY SYMBOLCOMBINING TRIPLE UNDE" +
"RDOTCOMBINING WIDE BRIDGE ABOVECOMBINING LEFTWARDS ARROW OVERLAYCOMBININ" +
"G LONG DOUBLE SOLIDUS OVERLAYCOMBINING RIGHTWARDS HARPOON WITH BARB DOWN" +
"WARDSCOMBINING LEFTWARDS HARPOON WITH BARB DOWNWARDSCOMBINING LEFT ARROW" +
" BELOWCOMBINING RIGHT ARROW BELOWCOMBINING ASTERISK ABOVEACCOUNT OFADDRE" +
"SSED TO THE SUBJECTDOUBLE-STRUCK CAPITAL CDEGREE CELSIUSCENTRE LINE SYMB" +
"OLCARE OFCADA UNAEULER CONSTANTSCRUPLEDEGREE FAHRENHEITSCRIPT SMALL GSCR" +
"IPT CAPITAL HBLACK-LETTER CAPITAL HDOUBLE-STRUCK CAPITAL HPLANCK CONSTAN" +
"TPLANCK CONSTANT OVER TWO PISCRIPT CAPITAL IBLACK-LETTER CAPITAL ISCRIPT" +
" CAPITAL LSCRIPT SMALL LL B BAR SYMBOLDOUBLE-STRUCK CAPITAL NNUMERO SIGN" +
"SOUND RECORDING COPYRIGHTSCRIPT CAPITAL PDOUBLE-STRUCK CAPITAL PDOUBLE-S" +
"TRUCK CAPITAL QSCRIPT CAPITAL RBLACK-LETTER CAPITAL RDOUBLE-STRUCK CAPIT" +
"AL RPRESCRIPTION TAKERESPONSESERVICE MARKTELEPHONE SIGNTRADE MARK SIGNVE" +
"RSICLEDOUBLE-STRUCK CAPITAL ZOUNCE SIGNOHM SIGNINVERTED OHM SIGNBLACK-LE" +
"TTER CAPITAL ZTURNED GREEK SMALL LETTER IOTAKELVIN SIGNANGSTROM SIGNSCRI" +
"PT CAPITAL BBLACK-LETTER CAPITAL CESTIMATED SYMBOLSCRIPT SMALL ESCRIPT C" +
"APITAL ESCRIPT CAPITAL FTURNED CAPITAL FSCRIPT CAPITAL MSCRIPT SMALL OAL" +
"EF SYMBOLBET SYMBOLGIMEL SYMBOLDALET SYMBOLINFORMATION SOURCEROTATED CAP") + ("" +
"ITAL QFACSIMILE SIGNDOUBLE-STRUCK SMALL PIDOUBLE-STRUCK SMALL GAMMADOUBL" +
"E-STRUCK CAPITAL GAMMADOUBLE-STRUCK CAPITAL PIDOUBLE-STRUCK N-ARY SUMMAT" +
"IONTURNED SANS-SERIF CAPITAL GTURNED SANS-SERIF CAPITAL LREVERSED SANS-S" +
"ERIF CAPITAL LTURNED SANS-SERIF CAPITAL YDOUBLE-STRUCK ITALIC CAPITAL DD" +
"OUBLE-STRUCK ITALIC SMALL DDOUBLE-STRUCK ITALIC SMALL EDOUBLE-STRUCK ITA" +
"LIC SMALL IDOUBLE-STRUCK ITALIC SMALL JPROPERTY LINETURNED AMPERSANDPER " +
"SIGNAKTIESELSKABTURNED SMALL FSYMBOL FOR SAMARITAN SOURCEVULGAR FRACTION" +
" ONE SEVENTHVULGAR FRACTION ONE NINTHVULGAR FRACTION ONE TENTHVULGAR FRA" +
"CTION ONE THIRDVULGAR FRACTION TWO THIRDSVULGAR FRACTION ONE FIFTHVULGAR" +
" FRACTION TWO FIFTHSVULGAR FRACTION THREE FIFTHSVULGAR FRACTION FOUR FIF" +
"THSVULGAR FRACTION ONE SIXTHVULGAR FRACTION FIVE SIXTHSVULGAR FRACTION O" +
"NE EIGHTHVULGAR FRACTION THREE EIGHTHSVULGAR FRACTION FIVE EIGHTHSVULGAR" +
" FRACTION SEVEN EIGHTHSFRACTION NUMERATOR ONEROMAN NUMERAL ONEROMAN NUME" +
"RAL TWOROMAN NUMERAL THREEROMAN NUMERAL FOURROMAN NUMERAL FIVEROMAN NUME" +
"RAL SIXROMAN NUMERAL SEVENROMAN NUMERAL EIGHTROMAN NUMERAL NINEROMAN NUM" +
"ERAL TENROMAN NUMERAL ELEVENROMAN NUMERAL TWELVEROMAN NUMERAL FIFTYROMAN" +
" NUMERAL ONE HUNDREDROMAN NUMERAL FIVE HUNDREDROMAN NUMERAL ONE THOUSAND" +
"SMALL ROMAN NUMERAL ONESMALL ROMAN NUMERAL TWOSMALL ROMAN NUMERAL THREES" +
"MALL ROMAN NUMERAL FOURSMALL ROMAN NUMERAL FIVESMALL ROMAN NUMERAL SIXSM" +
"ALL ROMAN NUMERAL SEVENSMALL ROMAN NUMERAL EIGHTSMALL ROMAN NUMERAL NINE" +
"SMALL ROMAN NUMERAL TENSMALL ROMAN NUMERAL ELEVENSMALL ROMAN NUMERAL TWE" +
"LVESMALL ROMAN NUMERAL FIFTYSMALL ROMAN NUMERAL ONE HUNDREDSMALL ROMAN N" +
"UMERAL FIVE HUNDREDSMALL ROMAN NUMERAL ONE THOUSANDROMAN NUMERAL ONE THO" +
"USAND C DROMAN NUMERAL FIVE THOUSANDROMAN NUMERAL TEN THOUSANDROMAN NUME" +
"RAL REVERSED ONE HUNDREDLATIN SMALL LETTER REVERSED CROMAN NUMERAL SIX L" +
"ATE FORMROMAN NUMERAL FIFTY EARLY FORMROMAN NUMERAL FIFTY THOUSANDROMAN " +
"NUMERAL ONE HUNDRED THOUSANDVULGAR FRACTION ZERO THIRDSTURNED DIGIT TWOT" +
"URNED DIGIT THREELEFTWARDS ARROWUPWARDS ARROWRIGHTWARDS ARROWDOWNWARDS A" +
"RROWLEFT RIGHT ARROWUP DOWN ARROWNORTH WEST ARROWNORTH EAST ARROWSOUTH E" +
"AST ARROWSOUTH WEST ARROWLEFTWARDS ARROW WITH STROKERIGHTWARDS ARROW WIT" +
"H STROKELEFTWARDS WAVE ARROWRIGHTWARDS WAVE ARROWLEFTWARDS TWO HEADED AR" +
"ROWUPWARDS TWO HEADED ARROWRIGHTWARDS TWO HEADED ARROWDOWNWARDS TWO HEAD" +
"ED ARROWLEFTWARDS ARROW WITH TAILRIGHTWARDS ARROW WITH TAILLEFTWARDS ARR" +
"OW FROM BARUPWARDS ARROW FROM BARRIGHTWARDS ARROW FROM BARDOWNWARDS ARRO" +
"W FROM BARUP DOWN ARROW WITH BASELEFTWARDS ARROW WITH HOOKRIGHTWARDS ARR" +
"OW WITH HOOKLEFTWARDS ARROW WITH LOOPRIGHTWARDS ARROW WITH LOOPLEFT RIGH" +
"T WAVE ARROWLEFT RIGHT ARROW WITH STROKEDOWNWARDS ZIGZAG ARROWUPWARDS AR" +
"ROW WITH TIP LEFTWARDSUPWARDS ARROW WITH TIP RIGHTWARDSDOWNWARDS ARROW W" +
"ITH TIP LEFTWARDSDOWNWARDS ARROW WITH TIP RIGHTWARDSRIGHTWARDS ARROW WIT" +
"H CORNER DOWNWARDSDOWNWARDS ARROW WITH CORNER LEFTWARDSANTICLOCKWISE TOP" +
" SEMICIRCLE ARROWCLOCKWISE TOP SEMICIRCLE ARROWNORTH WEST ARROW TO LONG " +
"BARLEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BARANTICLOCKWISE OPEN" +
" CIRCLE ARROWCLOCKWISE OPEN CIRCLE ARROWLEFTWARDS HARPOON WITH BARB UPWA" +
"RDSLEFTWARDS HARPOON WITH BARB DOWNWARDSUPWARDS HARPOON WITH BARB RIGHTW" +
"ARDSUPWARDS HARPOON WITH BARB LEFTWARDSRIGHTWARDS HARPOON WITH BARB UPWA" +
"RDSRIGHTWARDS HARPOON WITH BARB DOWNWARDSDOWNWARDS HARPOON WITH BARB RIG" +
"HTWARDSDOWNWARDS HARPOON WITH BARB LEFTWARDSRIGHTWARDS ARROW OVER LEFTWA" +
"RDS ARROWUPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROWLEFTWARDS ARROW OVER " +
"RIGHTWARDS ARROWLEFTWARDS PAIRED ARROWSUPWARDS PAIRED ARROWSRIGHTWARDS P" +
"AIRED ARROWSDOWNWARDS PAIRED ARROWSLEFTWARDS HARPOON OVER RIGHTWARDS HAR" +
"POONRIGHTWARDS HARPOON OVER LEFTWARDS HARPOONLEFTWARDS DOUBLE ARROW WITH" +
" STROKELEFT RIGHT DOUBLE ARROW WITH STROKERIGHTWARDS DOUBLE ARROW WITH S" +
"TROKELEFTWARDS DOUBLE ARROWUPWARDS DOUBLE ARROWRIGHTWARDS DOUBLE ARROWDO" +
"WNWARDS DOUBLE ARROWLEFT RIGHT DOUBLE ARROWUP DOWN DOUBLE ARROWNORTH WES" +
"T DOUBLE ARROWNORTH EAST DOUBLE ARROWSOUTH EAST DOUBLE ARROWSOUTH WEST D" +
"OUBLE ARROWLEFTWARDS TRIPLE ARROWRIGHTWARDS TRIPLE ARROWLEFTWARDS SQUIGG" +
"LE ARROWRIGHTWARDS SQUIGGLE ARROWUPWARDS ARROW WITH DOUBLE STROKEDOWNWAR" +
"DS ARROW WITH DOUBLE STROKELEFTWARDS DASHED ARROWUPWARDS DASHED ARROWRIG" +
"HTWARDS DASHED ARROWDOWNWARDS DASHED ARROWLEFTWARDS ARROW TO BARRIGHTWAR" +
"DS ARROW TO BARLEFTWARDS WHITE ARROWUPWARDS WHITE ARROWRIGHTWARDS WHITE " +
"ARROWDOWNWARDS WHITE ARROWUPWARDS WHITE ARROW FROM BARUPWARDS WHITE ARRO" +
"W ON PEDESTALUPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BARUPWARDS " +
"WHITE ARROW ON PEDESTAL WITH VERTICAL BARUPWARDS WHITE DOUBLE ARROWUPWAR" +
"DS WHITE DOUBLE ARROW ON PEDESTALRIGHTWARDS WHITE ARROW FROM WALLNORTH W") + ("" +
"EST ARROW TO CORNERSOUTH EAST ARROW TO CORNERUP DOWN WHITE ARROWRIGHT AR" +
"ROW WITH SMALL CIRCLEDOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROWTHREE RIG" +
"HTWARDS ARROWSLEFTWARDS ARROW WITH VERTICAL STROKERIGHTWARDS ARROW WITH " +
"VERTICAL STROKELEFT RIGHT ARROW WITH VERTICAL STROKELEFTWARDS ARROW WITH" +
" DOUBLE VERTICAL STROKERIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKELEFT " +
"RIGHT ARROW WITH DOUBLE VERTICAL STROKELEFTWARDS OPEN-HEADED ARROWRIGHTW" +
"ARDS OPEN-HEADED ARROWLEFT RIGHT OPEN-HEADED ARROWFOR ALLCOMPLEMENTPARTI" +
"AL DIFFERENTIALTHERE EXISTSTHERE DOES NOT EXISTEMPTY SETINCREMENTNABLAEL" +
"EMENT OFNOT AN ELEMENT OFSMALL ELEMENT OFCONTAINS AS MEMBERDOES NOT CONT" +
"AIN AS MEMBERSMALL CONTAINS AS MEMBEREND OF PROOFN-ARY PRODUCTN-ARY COPR" +
"ODUCTN-ARY SUMMATIONMINUS SIGNMINUS-OR-PLUS SIGNDOT PLUSDIVISION SLASHSE" +
"T MINUSASTERISK OPERATORRING OPERATORBULLET OPERATORSQUARE ROOTCUBE ROOT" +
"FOURTH ROOTPROPORTIONAL TOINFINITYRIGHT ANGLEANGLEMEASURED ANGLESPHERICA" +
"L ANGLEDIVIDESDOES NOT DIVIDEPARALLEL TONOT PARALLEL TOLOGICAL ANDLOGICA" +
"L ORINTERSECTIONUNIONINTEGRALDOUBLE INTEGRALTRIPLE INTEGRALCONTOUR INTEG" +
"RALSURFACE INTEGRALVOLUME INTEGRALCLOCKWISE INTEGRALCLOCKWISE CONTOUR IN" +
"TEGRALANTICLOCKWISE CONTOUR INTEGRALTHEREFOREBECAUSERATIOPROPORTIONDOT M" +
"INUSEXCESSGEOMETRIC PROPORTIONHOMOTHETICTILDE OPERATORREVERSED TILDEINVE" +
"RTED LAZY SSINE WAVEWREATH PRODUCTNOT TILDEMINUS TILDEASYMPTOTICALLY EQU" +
"AL TONOT ASYMPTOTICALLY EQUAL TOAPPROXIMATELY EQUAL TOAPPROXIMATELY BUT " +
"NOT ACTUALLY EQUAL TONEITHER APPROXIMATELY NOR ACTUALLY EQUAL TOALMOST E" +
"QUAL TONOT ALMOST EQUAL TOALMOST EQUAL OR EQUAL TOTRIPLE TILDEALL EQUAL " +
"TOEQUIVALENT TOGEOMETRICALLY EQUIVALENT TODIFFERENCE BETWEENAPPROACHES T" +
"HE LIMITGEOMETRICALLY EQUAL TOAPPROXIMATELY EQUAL TO OR THE IMAGE OFIMAG" +
"E OF OR APPROXIMATELY EQUAL TOCOLON EQUALSEQUALS COLONRING IN EQUAL TORI" +
"NG EQUAL TOCORRESPONDS TOESTIMATESEQUIANGULAR TOSTAR EQUALSDELTA EQUAL T" +
"OEQUAL TO BY DEFINITIONMEASURED BYQUESTIONED EQUAL TONOT EQUAL TOIDENTIC" +
"AL TONOT IDENTICAL TOSTRICTLY EQUIVALENT TOLESS-THAN OR EQUAL TOGREATER-" +
"THAN OR EQUAL TOLESS-THAN OVER EQUAL TOGREATER-THAN OVER EQUAL TOLESS-TH" +
"AN BUT NOT EQUAL TOGREATER-THAN BUT NOT EQUAL TOMUCH LESS-THANMUCH GREAT" +
"ER-THANBETWEENNOT EQUIVALENT TONOT LESS-THANNOT GREATER-THANNEITHER LESS" +
"-THAN NOR EQUAL TONEITHER GREATER-THAN NOR EQUAL TOLESS-THAN OR EQUIVALE" +
"NT TOGREATER-THAN OR EQUIVALENT TONEITHER LESS-THAN NOR EQUIVALENT TONEI" +
"THER GREATER-THAN NOR EQUIVALENT TOLESS-THAN OR GREATER-THANGREATER-THAN" +
" OR LESS-THANNEITHER LESS-THAN NOR GREATER-THANNEITHER GREATER-THAN NOR " +
"LESS-THANPRECEDESSUCCEEDSPRECEDES OR EQUAL TOSUCCEEDS OR EQUAL TOPRECEDE" +
"S OR EQUIVALENT TOSUCCEEDS OR EQUIVALENT TODOES NOT PRECEDEDOES NOT SUCC" +
"EEDSUBSET OFSUPERSET OFNOT A SUBSET OFNOT A SUPERSET OFSUBSET OF OR EQUA" +
"L TOSUPERSET OF OR EQUAL TONEITHER A SUBSET OF NOR EQUAL TONEITHER A SUP" +
"ERSET OF NOR EQUAL TOSUBSET OF WITH NOT EQUAL TOSUPERSET OF WITH NOT EQU" +
"AL TOMULTISETMULTISET MULTIPLICATIONMULTISET UNIONSQUARE IMAGE OFSQUARE " +
"ORIGINAL OFSQUARE IMAGE OF OR EQUAL TOSQUARE ORIGINAL OF OR EQUAL TOSQUA" +
"RE CAPSQUARE CUPCIRCLED PLUSCIRCLED MINUSCIRCLED TIMESCIRCLED DIVISION S" +
"LASHCIRCLED DOT OPERATORCIRCLED RING OPERATORCIRCLED ASTERISK OPERATORCI" +
"RCLED EQUALSCIRCLED DASHSQUARED PLUSSQUARED MINUSSQUARED TIMESSQUARED DO" +
"T OPERATORRIGHT TACKLEFT TACKDOWN TACKUP TACKASSERTIONMODELSTRUEFORCESTR" +
"IPLE VERTICAL BAR RIGHT TURNSTILEDOUBLE VERTICAL BAR DOUBLE RIGHT TURNST" +
"ILEDOES NOT PROVENOT TRUEDOES NOT FORCENEGATED DOUBLE VERTICAL BAR DOUBL" +
"E RIGHT TURNSTILEPRECEDES UNDER RELATIONSUCCEEDS UNDER RELATIONNORMAL SU" +
"BGROUP OFCONTAINS AS NORMAL SUBGROUPNORMAL SUBGROUP OF OR EQUAL TOCONTAI" +
"NS AS NORMAL SUBGROUP OR EQUAL TOORIGINAL OFIMAGE OFMULTIMAPHERMITIAN CO" +
"NJUGATE MATRIXINTERCALATEXORNANDNORRIGHT ANGLE WITH ARCRIGHT TRIANGLEN-A" +
"RY LOGICAL ANDN-ARY LOGICAL ORN-ARY INTERSECTIONN-ARY UNIONDIAMOND OPERA" +
"TORDOT OPERATORSTAR OPERATORDIVISION TIMESBOWTIELEFT NORMAL FACTOR SEMID" +
"IRECT PRODUCTRIGHT NORMAL FACTOR SEMIDIRECT PRODUCTLEFT SEMIDIRECT PRODU" +
"CTRIGHT SEMIDIRECT PRODUCTREVERSED TILDE EQUALSCURLY LOGICAL ORCURLY LOG" +
"ICAL ANDDOUBLE SUBSETDOUBLE SUPERSETDOUBLE INTERSECTIONDOUBLE UNIONPITCH" +
"FORKEQUAL AND PARALLEL TOLESS-THAN WITH DOTGREATER-THAN WITH DOTVERY MUC" +
"H LESS-THANVERY MUCH GREATER-THANLESS-THAN EQUAL TO OR GREATER-THANGREAT" +
"ER-THAN EQUAL TO OR LESS-THANEQUAL TO OR LESS-THANEQUAL TO OR GREATER-TH" +
"ANEQUAL TO OR PRECEDESEQUAL TO OR SUCCEEDSDOES NOT PRECEDE OR EQUALDOES " +
"NOT SUCCEED OR EQUALNOT SQUARE IMAGE OF OR EQUAL TONOT SQUARE ORIGINAL O" +
"F OR EQUAL TOSQUARE IMAGE OF OR NOT EQUAL TOSQUARE ORIGINAL OF OR NOT EQ" +
"UAL TOLESS-THAN BUT NOT EQUIVALENT TOGREATER-THAN BUT NOT EQUIVALENT TOP") + ("" +
"RECEDES BUT NOT EQUIVALENT TOSUCCEEDS BUT NOT EQUIVALENT TONOT NORMAL SU" +
"BGROUP OFDOES NOT CONTAIN AS NORMAL SUBGROUPNOT NORMAL SUBGROUP OF OR EQ" +
"UAL TODOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUALVERTICAL ELLIPSISMIDLI" +
"NE HORIZONTAL ELLIPSISUP RIGHT DIAGONAL ELLIPSISDOWN RIGHT DIAGONAL ELLI" +
"PSISELEMENT OF WITH LONG HORIZONTAL STROKEELEMENT OF WITH VERTICAL BAR A" +
"T END OF HORIZONTAL STROKESMALL ELEMENT OF WITH VERTICAL BAR AT END OF H" +
"ORIZONTAL STROKEELEMENT OF WITH DOT ABOVEELEMENT OF WITH OVERBARSMALL EL" +
"EMENT OF WITH OVERBARELEMENT OF WITH UNDERBARELEMENT OF WITH TWO HORIZON" +
"TAL STROKESCONTAINS WITH LONG HORIZONTAL STROKECONTAINS WITH VERTICAL BA" +
"R AT END OF HORIZONTAL STROKESMALL CONTAINS WITH VERTICAL BAR AT END OF " +
"HORIZONTAL STROKECONTAINS WITH OVERBARSMALL CONTAINS WITH OVERBARZ NOTAT" +
"ION BAG MEMBERSHIPDIAMETER SIGNELECTRIC ARROWHOUSEUP ARROWHEADDOWN ARROW" +
"HEADPROJECTIVEPERSPECTIVEWAVY LINELEFT CEILINGRIGHT CEILINGLEFT FLOORRIG" +
"HT FLOORBOTTOM RIGHT CROPBOTTOM LEFT CROPTOP RIGHT CROPTOP LEFT CROPREVE" +
"RSED NOT SIGNSQUARE LOZENGEARCSEGMENTSECTORTELEPHONE RECORDERPOSITION IN" +
"DICATORVIEWDATA SQUAREPLACE OF INTEREST SIGNTURNED NOT SIGNWATCHHOURGLAS" +
"STOP LEFT CORNERTOP RIGHT CORNERBOTTOM LEFT CORNERBOTTOM RIGHT CORNERTOP" +
" HALF INTEGRALBOTTOM HALF INTEGRALFROWNSMILEUP ARROWHEAD BETWEEN TWO HOR" +
"IZONTAL BARSOPTION KEYERASE TO THE RIGHTX IN A RECTANGLE BOXKEYBOARDLEFT" +
"-POINTING ANGLE BRACKETRIGHT-POINTING ANGLE BRACKETERASE TO THE LEFTBENZ" +
"ENE RINGCYLINDRICITYALL AROUND-PROFILESYMMETRYTOTAL RUNOUTDIMENSION ORIG" +
"INCONICAL TAPERSLOPECOUNTERBORECOUNTERSINKAPL FUNCTIONAL SYMBOL I-BEAMAP" +
"L FUNCTIONAL SYMBOL SQUISH QUADAPL FUNCTIONAL SYMBOL QUAD EQUALAPL FUNCT" +
"IONAL SYMBOL QUAD DIVIDEAPL FUNCTIONAL SYMBOL QUAD DIAMONDAPL FUNCTIONAL" +
" SYMBOL QUAD JOTAPL FUNCTIONAL SYMBOL QUAD CIRCLEAPL FUNCTIONAL SYMBOL C" +
"IRCLE STILEAPL FUNCTIONAL SYMBOL CIRCLE JOTAPL FUNCTIONAL SYMBOL SLASH B" +
"ARAPL FUNCTIONAL SYMBOL BACKSLASH BARAPL FUNCTIONAL SYMBOL QUAD SLASHAPL" +
" FUNCTIONAL SYMBOL QUAD BACKSLASHAPL FUNCTIONAL SYMBOL QUAD LESS-THANAPL" +
" FUNCTIONAL SYMBOL QUAD GREATER-THANAPL FUNCTIONAL SYMBOL LEFTWARDS VANE" +
"APL FUNCTIONAL SYMBOL RIGHTWARDS VANEAPL FUNCTIONAL SYMBOL QUAD LEFTWARD" +
"S ARROWAPL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROWAPL FUNCTIONAL SYMBOL " +
"CIRCLE BACKSLASHAPL FUNCTIONAL SYMBOL DOWN TACK UNDERBARAPL FUNCTIONAL S" +
"YMBOL DELTA STILEAPL FUNCTIONAL SYMBOL QUAD DOWN CARETAPL FUNCTIONAL SYM" +
"BOL QUAD DELTAAPL FUNCTIONAL SYMBOL DOWN TACK JOTAPL FUNCTIONAL SYMBOL U" +
"PWARDS VANEAPL FUNCTIONAL SYMBOL QUAD UPWARDS ARROWAPL FUNCTIONAL SYMBOL" +
" UP TACK OVERBARAPL FUNCTIONAL SYMBOL DEL STILEAPL FUNCTIONAL SYMBOL QUA" +
"D UP CARETAPL FUNCTIONAL SYMBOL QUAD DELAPL FUNCTIONAL SYMBOL UP TACK JO" +
"TAPL FUNCTIONAL SYMBOL DOWNWARDS VANEAPL FUNCTIONAL SYMBOL QUAD DOWNWARD" +
"S ARROWAPL FUNCTIONAL SYMBOL QUOTE UNDERBARAPL FUNCTIONAL SYMBOL DELTA U" +
"NDERBARAPL FUNCTIONAL SYMBOL DIAMOND UNDERBARAPL FUNCTIONAL SYMBOL JOT U" +
"NDERBARAPL FUNCTIONAL SYMBOL CIRCLE UNDERBARAPL FUNCTIONAL SYMBOL UP SHO" +
"E JOTAPL FUNCTIONAL SYMBOL QUOTE QUADAPL FUNCTIONAL SYMBOL CIRCLE STARAP" +
"L FUNCTIONAL SYMBOL QUAD COLONAPL FUNCTIONAL SYMBOL UP TACK DIAERESISAPL" +
" FUNCTIONAL SYMBOL DEL DIAERESISAPL FUNCTIONAL SYMBOL STAR DIAERESISAPL " +
"FUNCTIONAL SYMBOL JOT DIAERESISAPL FUNCTIONAL SYMBOL CIRCLE DIAERESISAPL" +
" FUNCTIONAL SYMBOL DOWN SHOE STILEAPL FUNCTIONAL SYMBOL LEFT SHOE STILEA" +
"PL FUNCTIONAL SYMBOL TILDE DIAERESISAPL FUNCTIONAL SYMBOL GREATER-THAN D" +
"IAERESISAPL FUNCTIONAL SYMBOL COMMA BARAPL FUNCTIONAL SYMBOL DEL TILDEAP" +
"L FUNCTIONAL SYMBOL ZILDEAPL FUNCTIONAL SYMBOL STILE TILDEAPL FUNCTIONAL" +
" SYMBOL SEMICOLON UNDERBARAPL FUNCTIONAL SYMBOL QUAD NOT EQUALAPL FUNCTI" +
"ONAL SYMBOL QUAD QUESTIONAPL FUNCTIONAL SYMBOL DOWN CARET TILDEAPL FUNCT" +
"IONAL SYMBOL UP CARET TILDEAPL FUNCTIONAL SYMBOL IOTAAPL FUNCTIONAL SYMB" +
"OL RHOAPL FUNCTIONAL SYMBOL OMEGAAPL FUNCTIONAL SYMBOL ALPHA UNDERBARAPL" +
" FUNCTIONAL SYMBOL EPSILON UNDERBARAPL FUNCTIONAL SYMBOL IOTA UNDERBARAP" +
"L FUNCTIONAL SYMBOL OMEGA UNDERBARAPL FUNCTIONAL SYMBOL ALPHANOT CHECK M" +
"ARKRIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROWSHOULDERED OPEN BOXBELL SYMBOL" +
"VERTICAL LINE WITH MIDDLE DOTINSERTION SYMBOLCONTINUOUS UNDERLINE SYMBOL" +
"DISCONTINUOUS UNDERLINE SYMBOLEMPHASIS SYMBOLCOMPOSITION SYMBOLWHITE SQU" +
"ARE WITH CENTRE VERTICAL LINEENTER SYMBOLALTERNATIVE KEY SYMBOLHELM SYMB" +
"OLCIRCLED HORIZONTAL BAR WITH NOTCHCIRCLED TRIANGLE DOWNBROKEN CIRCLE WI" +
"TH NORTHWEST ARROWUNDO SYMBOLMONOSTABLE SYMBOLHYSTERESIS SYMBOLOPEN-CIRC" +
"UIT-OUTPUT H-TYPE SYMBOLOPEN-CIRCUIT-OUTPUT L-TYPE SYMBOLPASSIVE-PULL-DO" +
"WN-OUTPUT SYMBOLPASSIVE-PULL-UP-OUTPUT SYMBOLDIRECT CURRENT SYMBOL FORM " +
"TWOSOFTWARE-FUNCTION SYMBOLAPL FUNCTIONAL SYMBOL QUADDECIMAL SEPARATOR K") + ("" +
"EY SYMBOLPREVIOUS PAGENEXT PAGEPRINT SCREEN SYMBOLCLEAR SCREEN SYMBOLLEF" +
"T PARENTHESIS UPPER HOOKLEFT PARENTHESIS EXTENSIONLEFT PARENTHESIS LOWER" +
" HOOKRIGHT PARENTHESIS UPPER HOOKRIGHT PARENTHESIS EXTENSIONRIGHT PARENT" +
"HESIS LOWER HOOKLEFT SQUARE BRACKET UPPER CORNERLEFT SQUARE BRACKET EXTE" +
"NSIONLEFT SQUARE BRACKET LOWER CORNERRIGHT SQUARE BRACKET UPPER CORNERRI" +
"GHT SQUARE BRACKET EXTENSIONRIGHT SQUARE BRACKET LOWER CORNERLEFT CURLY " +
"BRACKET UPPER HOOKLEFT CURLY BRACKET MIDDLE PIECELEFT CURLY BRACKET LOWE" +
"R HOOKCURLY BRACKET EXTENSIONRIGHT CURLY BRACKET UPPER HOOKRIGHT CURLY B" +
"RACKET MIDDLE PIECERIGHT CURLY BRACKET LOWER HOOKINTEGRAL EXTENSIONHORIZ" +
"ONTAL LINE EXTENSIONUPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTIONUPPER" +
" RIGHT OR LOWER LEFT CURLY BRACKET SECTIONSUMMATION TOPSUMMATION BOTTOMT" +
"OP SQUARE BRACKETBOTTOM SQUARE BRACKETBOTTOM SQUARE BRACKET OVER TOP SQU" +
"ARE BRACKETRADICAL SYMBOL BOTTOMLEFT VERTICAL BOX LINERIGHT VERTICAL BOX" +
" LINEHORIZONTAL SCAN LINE-1HORIZONTAL SCAN LINE-3HORIZONTAL SCAN LINE-7H" +
"ORIZONTAL SCAN LINE-9DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHTDENTIS" +
"TRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHTDENTISTRY SYMBOL LIGHT VERTICA" +
"L WITH CIRCLEDENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLEDENTI" +
"STRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLEDENTISTRY SYMBOL LIGHT VE" +
"RTICAL WITH TRIANGLEDENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIA" +
"NGLEDENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLEDENTISTRY SYMB" +
"OL LIGHT VERTICAL AND WAVEDENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WIT" +
"H WAVEDENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVEDENTISTRY SYMBOL" +
" LIGHT DOWN AND HORIZONTALDENTISTRY SYMBOL LIGHT UP AND HORIZONTALDENTIS" +
"TRY SYMBOL LIGHT VERTICAL AND TOP LEFTDENTISTRY SYMBOL LIGHT VERTICAL AN" +
"D BOTTOM LEFTSQUARE FOOTRETURN SYMBOLEJECT SYMBOLVERTICAL LINE EXTENSION" +
"METRICAL BREVEMETRICAL LONG OVER SHORTMETRICAL SHORT OVER LONGMETRICAL L" +
"ONG OVER TWO SHORTSMETRICAL TWO SHORTS OVER LONGMETRICAL TWO SHORTS JOIN" +
"EDMETRICAL TRISEMEMETRICAL TETRASEMEMETRICAL PENTASEMEEARTH GROUNDFUSETO" +
"P PARENTHESISBOTTOM PARENTHESISTOP CURLY BRACKETBOTTOM CURLY BRACKETTOP " +
"TORTOISE SHELL BRACKETBOTTOM TORTOISE SHELL BRACKETWHITE TRAPEZIUMBENZEN" +
"E RING WITH CIRCLESTRAIGHTNESSFLATNESSAC CURRENTELECTRICAL INTERSECTIOND" +
"ECIMAL EXPONENT SYMBOLBLACK RIGHT-POINTING DOUBLE TRIANGLEBLACK LEFT-POI" +
"NTING DOUBLE TRIANGLEBLACK UP-POINTING DOUBLE TRIANGLEBLACK DOWN-POINTIN" +
"G DOUBLE TRIANGLEBLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BARB" +
"LACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BARBLACK RIGHT-POINTING" +
" TRIANGLE WITH DOUBLE VERTICAL BARALARM CLOCKSTOPWATCHTIMER CLOCKHOURGLA" +
"SS WITH FLOWING SANDBLACK MEDIUM LEFT-POINTING TRIANGLEBLACK MEDIUM RIGH" +
"T-POINTING TRIANGLEBLACK MEDIUM UP-POINTING TRIANGLEBLACK MEDIUM DOWN-PO" +
"INTING TRIANGLEDOUBLE VERTICAL BARBLACK SQUARE FOR STOPBLACK CIRCLE FOR " +
"RECORDPOWER SYMBOLPOWER ON-OFF SYMBOLPOWER ON SYMBOLPOWER SLEEP SYMBOLOB" +
"SERVER EYE SYMBOLSYMBOL FOR NULLSYMBOL FOR START OF HEADINGSYMBOL FOR ST" +
"ART OF TEXTSYMBOL FOR END OF TEXTSYMBOL FOR END OF TRANSMISSIONSYMBOL FO" +
"R ENQUIRYSYMBOL FOR ACKNOWLEDGESYMBOL FOR BELLSYMBOL FOR BACKSPACESYMBOL" +
" FOR HORIZONTAL TABULATIONSYMBOL FOR LINE FEEDSYMBOL FOR VERTICAL TABULA" +
"TIONSYMBOL FOR FORM FEEDSYMBOL FOR CARRIAGE RETURNSYMBOL FOR SHIFT OUTSY" +
"MBOL FOR SHIFT INSYMBOL FOR DATA LINK ESCAPESYMBOL FOR DEVICE CONTROL ON" +
"ESYMBOL FOR DEVICE CONTROL TWOSYMBOL FOR DEVICE CONTROL THREESYMBOL FOR " +
"DEVICE CONTROL FOURSYMBOL FOR NEGATIVE ACKNOWLEDGESYMBOL FOR SYNCHRONOUS" +
" IDLESYMBOL FOR END OF TRANSMISSION BLOCKSYMBOL FOR CANCELSYMBOL FOR END" +
" OF MEDIUMSYMBOL FOR SUBSTITUTESYMBOL FOR ESCAPESYMBOL FOR FILE SEPARATO" +
"RSYMBOL FOR GROUP SEPARATORSYMBOL FOR RECORD SEPARATORSYMBOL FOR UNIT SE" +
"PARATORSYMBOL FOR SPACESYMBOL FOR DELETEBLANK SYMBOLOPEN BOXSYMBOL FOR N" +
"EWLINESYMBOL FOR DELETE FORM TWOSYMBOL FOR SUBSTITUTE FORM TWOSYMBOL FOR" +
" DELETE SQUARE CHECKER BOARD FORMSYMBOL FOR DELETE RECTANGULAR CHECKER B" +
"OARD FORMSYMBOL FOR DELETE MEDIUM SHADE FORMOCR HOOKOCR CHAIROCR FORKOCR" +
" INVERTED FORKOCR BELT BUCKLEOCR BOW TIEOCR BRANCH BANK IDENTIFICATIONOC" +
"R AMOUNT OF CHECKOCR DASHOCR CUSTOMER ACCOUNT NUMBEROCR DOUBLE BACKSLASH" +
"CIRCLED DIGIT ONECIRCLED DIGIT TWOCIRCLED DIGIT THREECIRCLED DIGIT FOURC" +
"IRCLED DIGIT FIVECIRCLED DIGIT SIXCIRCLED DIGIT SEVENCIRCLED DIGIT EIGHT" +
"CIRCLED DIGIT NINECIRCLED NUMBER TENCIRCLED NUMBER ELEVENCIRCLED NUMBER " +
"TWELVECIRCLED NUMBER THIRTEENCIRCLED NUMBER FOURTEENCIRCLED NUMBER FIFTE" +
"ENCIRCLED NUMBER SIXTEENCIRCLED NUMBER SEVENTEENCIRCLED NUMBER EIGHTEENC" +
"IRCLED NUMBER NINETEENCIRCLED NUMBER TWENTYPARENTHESIZED DIGIT ONEPARENT" +
"HESIZED DIGIT TWOPARENTHESIZED DIGIT THREEPARENTHESIZED DIGIT FOURPARENT") + ("" +
"HESIZED DIGIT FIVEPARENTHESIZED DIGIT SIXPARENTHESIZED DIGIT SEVENPARENT" +
"HESIZED DIGIT EIGHTPARENTHESIZED DIGIT NINEPARENTHESIZED NUMBER TENPAREN" +
"THESIZED NUMBER ELEVENPARENTHESIZED NUMBER TWELVEPARENTHESIZED NUMBER TH" +
"IRTEENPARENTHESIZED NUMBER FOURTEENPARENTHESIZED NUMBER FIFTEENPARENTHES" +
"IZED NUMBER SIXTEENPARENTHESIZED NUMBER SEVENTEENPARENTHESIZED NUMBER EI" +
"GHTEENPARENTHESIZED NUMBER NINETEENPARENTHESIZED NUMBER TWENTYDIGIT ONE " +
"FULL STOPDIGIT TWO FULL STOPDIGIT THREE FULL STOPDIGIT FOUR FULL STOPDIG" +
"IT FIVE FULL STOPDIGIT SIX FULL STOPDIGIT SEVEN FULL STOPDIGIT EIGHT FUL" +
"L STOPDIGIT NINE FULL STOPNUMBER TEN FULL STOPNUMBER ELEVEN FULL STOPNUM" +
"BER TWELVE FULL STOPNUMBER THIRTEEN FULL STOPNUMBER FOURTEEN FULL STOPNU" +
"MBER FIFTEEN FULL STOPNUMBER SIXTEEN FULL STOPNUMBER SEVENTEEN FULL STOP" +
"NUMBER EIGHTEEN FULL STOPNUMBER NINETEEN FULL STOPNUMBER TWENTY FULL STO" +
"PPARENTHESIZED LATIN SMALL LETTER APARENTHESIZED LATIN SMALL LETTER BPAR" +
"ENTHESIZED LATIN SMALL LETTER CPARENTHESIZED LATIN SMALL LETTER DPARENTH" +
"ESIZED LATIN SMALL LETTER EPARENTHESIZED LATIN SMALL LETTER FPARENTHESIZ" +
"ED LATIN SMALL LETTER GPARENTHESIZED LATIN SMALL LETTER HPARENTHESIZED L" +
"ATIN SMALL LETTER IPARENTHESIZED LATIN SMALL LETTER JPARENTHESIZED LATIN" +
" SMALL LETTER KPARENTHESIZED LATIN SMALL LETTER LPARENTHESIZED LATIN SMA" +
"LL LETTER MPARENTHESIZED LATIN SMALL LETTER NPARENTHESIZED LATIN SMALL L" +
"ETTER OPARENTHESIZED LATIN SMALL LETTER PPARENTHESIZED LATIN SMALL LETTE" +
"R QPARENTHESIZED LATIN SMALL LETTER RPARENTHESIZED LATIN SMALL LETTER SP" +
"ARENTHESIZED LATIN SMALL LETTER TPARENTHESIZED LATIN SMALL LETTER UPAREN" +
"THESIZED LATIN SMALL LETTER VPARENTHESIZED LATIN SMALL LETTER WPARENTHES" +
"IZED LATIN SMALL LETTER XPARENTHESIZED LATIN SMALL LETTER YPARENTHESIZED" +
" LATIN SMALL LETTER ZCIRCLED LATIN CAPITAL LETTER ACIRCLED LATIN CAPITAL" +
" LETTER BCIRCLED LATIN CAPITAL LETTER CCIRCLED LATIN CAPITAL LETTER DCIR" +
"CLED LATIN CAPITAL LETTER ECIRCLED LATIN CAPITAL LETTER FCIRCLED LATIN C" +
"APITAL LETTER GCIRCLED LATIN CAPITAL LETTER HCIRCLED LATIN CAPITAL LETTE" +
"R ICIRCLED LATIN CAPITAL LETTER JCIRCLED LATIN CAPITAL LETTER KCIRCLED L" +
"ATIN CAPITAL LETTER LCIRCLED LATIN CAPITAL LETTER MCIRCLED LATIN CAPITAL" +
" LETTER NCIRCLED LATIN CAPITAL LETTER OCIRCLED LATIN CAPITAL LETTER PCIR" +
"CLED LATIN CAPITAL LETTER QCIRCLED LATIN CAPITAL LETTER RCIRCLED LATIN C" +
"APITAL LETTER SCIRCLED LATIN CAPITAL LETTER TCIRCLED LATIN CAPITAL LETTE" +
"R UCIRCLED LATIN CAPITAL LETTER VCIRCLED LATIN CAPITAL LETTER WCIRCLED L" +
"ATIN CAPITAL LETTER XCIRCLED LATIN CAPITAL LETTER YCIRCLED LATIN CAPITAL" +
" LETTER ZCIRCLED LATIN SMALL LETTER ACIRCLED LATIN SMALL LETTER BCIRCLED" +
" LATIN SMALL LETTER CCIRCLED LATIN SMALL LETTER DCIRCLED LATIN SMALL LET" +
"TER ECIRCLED LATIN SMALL LETTER FCIRCLED LATIN SMALL LETTER GCIRCLED LAT" +
"IN SMALL LETTER HCIRCLED LATIN SMALL LETTER ICIRCLED LATIN SMALL LETTER " +
"JCIRCLED LATIN SMALL LETTER KCIRCLED LATIN SMALL LETTER LCIRCLED LATIN S" +
"MALL LETTER MCIRCLED LATIN SMALL LETTER NCIRCLED LATIN SMALL LETTER OCIR" +
"CLED 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 LETTER VCIRCLED LATIN SMALL LET" +
"TER WCIRCLED LATIN SMALL LETTER XCIRCLED LATIN SMALL LETTER YCIRCLED LAT" +
"IN SMALL LETTER ZCIRCLED DIGIT ZERONEGATIVE CIRCLED NUMBER ELEVENNEGATIV" +
"E CIRCLED NUMBER TWELVENEGATIVE CIRCLED NUMBER THIRTEENNEGATIVE CIRCLED " +
"NUMBER FOURTEENNEGATIVE CIRCLED NUMBER FIFTEENNEGATIVE CIRCLED NUMBER SI" +
"XTEENNEGATIVE CIRCLED NUMBER SEVENTEENNEGATIVE CIRCLED NUMBER EIGHTEENNE" +
"GATIVE CIRCLED NUMBER NINETEENNEGATIVE CIRCLED NUMBER TWENTYDOUBLE CIRCL" +
"ED DIGIT ONEDOUBLE CIRCLED DIGIT TWODOUBLE CIRCLED DIGIT THREEDOUBLE CIR" +
"CLED DIGIT FOURDOUBLE CIRCLED DIGIT FIVEDOUBLE CIRCLED DIGIT SIXDOUBLE C" +
"IRCLED DIGIT SEVENDOUBLE CIRCLED DIGIT EIGHTDOUBLE CIRCLED DIGIT NINEDOU" +
"BLE CIRCLED NUMBER TENNEGATIVE CIRCLED DIGIT ZEROBOX DRAWINGS LIGHT HORI" +
"ZONTALBOX DRAWINGS HEAVY HORIZONTALBOX DRAWINGS LIGHT VERTICALBOX DRAWIN" +
"GS HEAVY VERTICALBOX DRAWINGS LIGHT TRIPLE DASH HORIZONTALBOX DRAWINGS H" +
"EAVY TRIPLE DASH HORIZONTALBOX DRAWINGS LIGHT TRIPLE DASH VERTICALBOX DR" +
"AWINGS HEAVY TRIPLE DASH VERTICALBOX DRAWINGS LIGHT QUADRUPLE DASH HORIZ" +
"ONTALBOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTALBOX DRAWINGS LIGHT QUAD" +
"RUPLE DASH VERTICALBOX DRAWINGS HEAVY QUADRUPLE DASH VERTICALBOX DRAWING" +
"S LIGHT DOWN AND RIGHTBOX DRAWINGS DOWN LIGHT AND RIGHT HEAVYBOX DRAWING" +
"S DOWN HEAVY AND RIGHT LIGHTBOX DRAWINGS HEAVY DOWN AND RIGHTBOX DRAWING" +
"S LIGHT DOWN AND LEFTBOX DRAWINGS DOWN LIGHT AND LEFT HEAVYBOX DRAWINGS " +
"DOWN HEAVY AND LEFT LIGHTBOX DRAWINGS HEAVY DOWN AND LEFTBOX DRAWINGS LI") + ("" +
"GHT UP AND RIGHTBOX DRAWINGS UP LIGHT AND RIGHT HEAVYBOX DRAWINGS UP HEA" +
"VY AND RIGHT LIGHTBOX DRAWINGS HEAVY UP AND RIGHTBOX DRAWINGS LIGHT UP A" +
"ND LEFTBOX DRAWINGS UP LIGHT AND LEFT HEAVYBOX DRAWINGS UP HEAVY AND LEF" +
"T LIGHTBOX DRAWINGS HEAVY UP AND LEFTBOX DRAWINGS LIGHT VERTICAL AND RIG" +
"HTBOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVYBOX DRAWINGS UP HEAVY AND R" +
"IGHT DOWN LIGHTBOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHTBOX DRAWINGS VE" +
"RTICAL HEAVY AND RIGHT LIGHTBOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVYBO" +
"X 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 DOWN LIGHTBOX DRAWINGS DOWN HE" +
"AVY AND LEFT UP LIGHTBOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHTBOX DRAWI" +
"NGS DOWN LIGHT AND LEFT UP HEAVYBOX DRAWINGS UP LIGHT AND LEFT DOWN HEAV" +
"YBOX DRAWINGS HEAVY VERTICAL AND LEFTBOX DRAWINGS LIGHT DOWN AND HORIZON" +
"TALBOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHTBOX DRAWINGS RIGHT HEAVY " +
"AND LEFT DOWN LIGHTBOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVYBOX DRAWI" +
"NGS DOWN HEAVY AND HORIZONTAL LIGHTBOX DRAWINGS RIGHT LIGHT AND LEFT DOW" +
"N HEAVYBOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVYBOX DRAWINGS HEAVY DO" +
"WN AND HORIZONTALBOX DRAWINGS LIGHT UP AND HORIZONTALBOX DRAWINGS LEFT H" +
"EAVY AND RIGHT UP LIGHTBOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHTBOX DRA" +
"WINGS UP LIGHT AND HORIZONTAL HEAVYBOX DRAWINGS UP HEAVY AND HORIZONTAL " +
"LIGHTBOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVYBOX DRAWINGS LEFT LIGHT A" +
"ND RIGHT UP HEAVYBOX DRAWINGS HEAVY UP AND HORIZONTALBOX DRAWINGS LIGHT " +
"VERTICAL AND HORIZONTALBOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHTB" +
"OX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHTBOX DRAWINGS VERTICAL LIG" +
"HT AND HORIZONTAL HEAVYBOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHTBO" +
"X DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHTBOX DRAWINGS VERTICAL HEAVY" +
" AND HORIZONTAL LIGHTBOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHTBOX " +
"DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHTBOX DRAWINGS LEFT DOWN HEAVY " +
"AND RIGHT UP LIGHTBOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHTBOX DRA" +
"WINGS DOWN LIGHT AND UP HORIZONTAL HEAVYBOX DRAWINGS UP LIGHT AND DOWN H" +
"ORIZONTAL HEAVYBOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVYBOX DRAWI" +
"NGS LEFT LIGHT AND RIGHT VERTICAL HEAVYBOX DRAWINGS HEAVY VERTICAL AND H" +
"ORIZONTALBOX DRAWINGS LIGHT DOUBLE DASH HORIZONTALBOX DRAWINGS HEAVY DOU" +
"BLE DASH HORIZONTALBOX DRAWINGS LIGHT DOUBLE DASH VERTICALBOX DRAWINGS H" +
"EAVY DOUBLE DASH VERTICALBOX DRAWINGS DOUBLE HORIZONTALBOX DRAWINGS DOUB" +
"LE VERTICALBOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLEBOX DRAWINGS DOWN DO" +
"UBLE AND RIGHT SINGLEBOX DRAWINGS DOUBLE DOWN AND RIGHTBOX DRAWINGS DOWN" +
" SINGLE AND LEFT DOUBLEBOX DRAWINGS DOWN DOUBLE AND LEFT SINGLEBOX DRAWI" +
"NGS DOUBLE DOWN AND LEFTBOX DRAWINGS UP SINGLE AND RIGHT DOUBLEBOX DRAWI" +
"NGS UP DOUBLE AND RIGHT SINGLEBOX DRAWINGS DOUBLE UP AND RIGHTBOX DRAWIN" +
"GS UP SINGLE AND LEFT DOUBLEBOX DRAWINGS UP DOUBLE AND LEFT SINGLEBOX DR" +
"AWINGS DOUBLE UP AND LEFTBOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLEBO" +
"X DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLEBOX DRAWINGS DOUBLE VERTICAL " +
"AND RIGHTBOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLEBOX DRAWINGS VERTIC" +
"AL DOUBLE AND LEFT SINGLEBOX DRAWINGS DOUBLE VERTICAL AND LEFTBOX DRAWIN" +
"GS DOWN SINGLE AND HORIZONTAL DOUBLEBOX DRAWINGS DOWN DOUBLE AND HORIZON" +
"TAL SINGLEBOX DRAWINGS DOUBLE DOWN AND HORIZONTALBOX DRAWINGS UP SINGLE " +
"AND HORIZONTAL DOUBLEBOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLEBOX DRA" +
"WINGS DOUBLE UP AND HORIZONTALBOX DRAWINGS VERTICAL SINGLE AND HORIZONTA" +
"L DOUBLEBOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLEBOX DRAWINGS D" +
"OUBLE VERTICAL AND HORIZONTALBOX DRAWINGS LIGHT ARC DOWN AND RIGHTBOX DR" +
"AWINGS LIGHT ARC DOWN AND LEFTBOX DRAWINGS LIGHT ARC UP AND LEFTBOX DRAW" +
"INGS LIGHT ARC UP AND RIGHTBOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LO" +
"WER LEFTBOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHTBOX DRAWING" +
"S LIGHT DIAGONAL CROSSBOX DRAWINGS LIGHT LEFTBOX DRAWINGS LIGHT UPBOX DR" +
"AWINGS LIGHT RIGHTBOX DRAWINGS LIGHT DOWNBOX DRAWINGS HEAVY LEFTBOX DRAW" +
"INGS HEAVY UPBOX DRAWINGS HEAVY RIGHTBOX DRAWINGS HEAVY DOWNBOX DRAWINGS" +
" LIGHT LEFT AND HEAVY RIGHTBOX DRAWINGS LIGHT UP AND HEAVY DOWNBOX DRAWI" +
"NGS HEAVY LEFT AND LIGHT RIGHTBOX DRAWINGS HEAVY UP AND LIGHT DOWNUPPER " +
"HALF BLOCKLOWER ONE EIGHTH BLOCKLOWER ONE QUARTER BLOCKLOWER THREE EIGHT" +
"HS BLOCKLOWER HALF BLOCKLOWER FIVE EIGHTHS BLOCKLOWER THREE QUARTERS BLO" +
"CKLOWER SEVEN EIGHTHS BLOCKFULL BLOCKLEFT SEVEN EIGHTHS BLOCKLEFT THREE " +
"QUARTERS BLOCKLEFT FIVE EIGHTHS BLOCKLEFT HALF BLOCKLEFT THREE EIGHTHS B" +
"LOCKLEFT ONE QUARTER BLOCKLEFT ONE EIGHTH BLOCKRIGHT HALF BLOCKLIGHT SHA") + ("" +
"DEMEDIUM SHADEDARK SHADEUPPER ONE EIGHTH BLOCKRIGHT ONE EIGHTH BLOCKQUAD" +
"RANT LOWER LEFTQUADRANT LOWER RIGHTQUADRANT UPPER LEFTQUADRANT UPPER LEF" +
"T AND LOWER LEFT AND LOWER RIGHTQUADRANT UPPER LEFT AND LOWER RIGHTQUADR" +
"ANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFTQUADRANT UPPER LEFT AND UPP" +
"ER RIGHT AND LOWER RIGHTQUADRANT UPPER RIGHTQUADRANT UPPER RIGHT AND LOW" +
"ER LEFTQUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHTBLACK SQUAREWH" +
"ITE SQUAREWHITE SQUARE WITH ROUNDED CORNERSWHITE SQUARE CONTAINING BLACK" +
" SMALL SQUARESQUARE WITH HORIZONTAL FILLSQUARE WITH VERTICAL FILLSQUARE " +
"WITH ORTHOGONAL CROSSHATCH FILLSQUARE WITH UPPER LEFT TO LOWER RIGHT FIL" +
"LSQUARE WITH UPPER RIGHT TO LOWER LEFT FILLSQUARE WITH DIAGONAL CROSSHAT" +
"CH FILLBLACK SMALL SQUAREWHITE SMALL SQUAREBLACK RECTANGLEWHITE RECTANGL" +
"EBLACK VERTICAL RECTANGLEWHITE VERTICAL RECTANGLEBLACK PARALLELOGRAMWHIT" +
"E PARALLELOGRAMBLACK UP-POINTING TRIANGLEWHITE UP-POINTING TRIANGLEBLACK" +
" UP-POINTING SMALL TRIANGLEWHITE UP-POINTING SMALL TRIANGLEBLACK RIGHT-P" +
"OINTING TRIANGLEWHITE RIGHT-POINTING TRIANGLEBLACK RIGHT-POINTING SMALL " +
"TRIANGLEWHITE RIGHT-POINTING SMALL TRIANGLEBLACK RIGHT-POINTING POINTERW" +
"HITE RIGHT-POINTING POINTERBLACK DOWN-POINTING TRIANGLEWHITE DOWN-POINTI" +
"NG TRIANGLEBLACK DOWN-POINTING SMALL TRIANGLEWHITE DOWN-POINTING SMALL T" +
"RIANGLEBLACK LEFT-POINTING TRIANGLEWHITE LEFT-POINTING TRIANGLEBLACK LEF" +
"T-POINTING SMALL TRIANGLEWHITE LEFT-POINTING SMALL TRIANGLEBLACK LEFT-PO" +
"INTING POINTERWHITE LEFT-POINTING POINTERBLACK DIAMONDWHITE DIAMONDWHITE" +
" DIAMOND CONTAINING BLACK SMALL DIAMONDFISHEYELOZENGEWHITE CIRCLEDOTTED " +
"CIRCLECIRCLE WITH VERTICAL FILLBULLSEYEBLACK CIRCLECIRCLE WITH LEFT HALF" +
" BLACKCIRCLE WITH RIGHT HALF BLACKCIRCLE WITH LOWER HALF BLACKCIRCLE WIT" +
"H UPPER HALF BLACKCIRCLE WITH UPPER RIGHT QUADRANT BLACKCIRCLE WITH ALL " +
"BUT UPPER LEFT QUADRANT BLACKLEFT HALF BLACK CIRCLERIGHT HALF BLACK CIRC" +
"LEINVERSE BULLETINVERSE WHITE CIRCLEUPPER HALF INVERSE WHITE CIRCLELOWER" +
" HALF INVERSE WHITE CIRCLEUPPER LEFT QUADRANT CIRCULAR ARCUPPER RIGHT QU" +
"ADRANT CIRCULAR ARCLOWER RIGHT QUADRANT CIRCULAR ARCLOWER LEFT QUADRANT " +
"CIRCULAR ARCUPPER HALF CIRCLELOWER HALF CIRCLEBLACK LOWER RIGHT TRIANGLE" +
"BLACK LOWER LEFT TRIANGLEBLACK UPPER LEFT TRIANGLEBLACK UPPER RIGHT TRIA" +
"NGLEWHITE BULLETSQUARE WITH LEFT HALF BLACKSQUARE WITH RIGHT HALF BLACKS" +
"QUARE WITH UPPER LEFT DIAGONAL HALF BLACKSQUARE WITH LOWER RIGHT DIAGONA" +
"L HALF BLACKWHITE SQUARE WITH VERTICAL BISECTING LINEWHITE UP-POINTING T" +
"RIANGLE WITH DOTUP-POINTING TRIANGLE WITH LEFT HALF BLACKUP-POINTING TRI" +
"ANGLE WITH RIGHT HALF BLACKLARGE CIRCLEWHITE SQUARE WITH UPPER LEFT QUAD" +
"RANTWHITE SQUARE WITH LOWER LEFT QUADRANTWHITE SQUARE WITH LOWER RIGHT Q" +
"UADRANTWHITE SQUARE WITH UPPER RIGHT QUADRANTWHITE CIRCLE WITH UPPER LEF" +
"T QUADRANTWHITE CIRCLE WITH LOWER LEFT QUADRANTWHITE CIRCLE WITH LOWER R" +
"IGHT QUADRANTWHITE CIRCLE WITH UPPER RIGHT QUADRANTUPPER LEFT TRIANGLEUP" +
"PER RIGHT TRIANGLELOWER LEFT TRIANGLEWHITE MEDIUM SQUAREBLACK MEDIUM SQU" +
"AREWHITE MEDIUM SMALL SQUAREBLACK MEDIUM SMALL SQUARELOWER RIGHT TRIANGL" +
"EBLACK SUN WITH RAYSCLOUDUMBRELLASNOWMANCOMETBLACK STARWHITE STARLIGHTNI" +
"NGTHUNDERSTORMSUNASCENDING NODEDESCENDING NODECONJUNCTIONOPPOSITIONBLACK" +
" TELEPHONEWHITE TELEPHONEBALLOT BOXBALLOT BOX WITH CHECKBALLOT BOX WITH " +
"XSALTIREUMBRELLA WITH RAIN DROPSHOT BEVERAGEWHITE SHOGI PIECEBLACK SHOGI" +
" PIECESHAMROCKREVERSED ROTATED FLORAL HEART BULLETBLACK LEFT POINTING IN" +
"DEXBLACK RIGHT POINTING INDEXWHITE LEFT POINTING INDEXWHITE UP POINTING " +
"INDEXWHITE RIGHT POINTING INDEXWHITE DOWN POINTING INDEXSKULL AND CROSSB" +
"ONESCAUTION SIGNRADIOACTIVE SIGNBIOHAZARD SIGNCADUCEUSANKHORTHODOX CROSS" +
"CHI RHOCROSS OF LORRAINECROSS OF JERUSALEMSTAR AND CRESCENTFARSI SYMBOLA" +
"DI SHAKTIHAMMER AND SICKLEPEACE SYMBOLYIN YANGTRIGRAM FOR HEAVENTRIGRAM " +
"FOR LAKETRIGRAM FOR FIRETRIGRAM FOR THUNDERTRIGRAM FOR WINDTRIGRAM FOR W" +
"ATERTRIGRAM FOR MOUNTAINTRIGRAM FOR EARTHWHEEL OF DHARMAWHITE FROWNING F" +
"ACEWHITE SMILING FACEBLACK SMILING FACEWHITE SUN WITH RAYSFIRST QUARTER " +
"MOONLAST QUARTER MOONMERCURYFEMALE SIGNEARTHMALE SIGNJUPITERSATURNURANUS" +
"NEPTUNEPLUTOARIESTAURUSGEMINICANCERLEOVIRGOLIBRASCORPIUSSAGITTARIUSCAPRI" +
"CORNAQUARIUSPISCESWHITE CHESS KINGWHITE CHESS QUEENWHITE CHESS ROOKWHITE" +
" CHESS BISHOPWHITE CHESS KNIGHTWHITE CHESS PAWNBLACK CHESS KINGBLACK CHE" +
"SS QUEENBLACK CHESS ROOKBLACK CHESS BISHOPBLACK CHESS KNIGHTBLACK CHESS " +
"PAWNBLACK SPADE SUITWHITE HEART SUITWHITE DIAMOND SUITBLACK CLUB SUITWHI" +
"TE SPADE SUITBLACK HEART SUITBLACK DIAMOND SUITWHITE CLUB SUITHOT SPRING" +
"SQUARTER NOTEEIGHTH NOTEBEAMED EIGHTH NOTESBEAMED SIXTEENTH NOTESMUSIC F" +
"LAT SIGNMUSIC NATURAL SIGNMUSIC SHARP SIGNWEST SYRIAC CROSSEAST SYRIAC C") + ("" +
"ROSSUNIVERSAL RECYCLING SYMBOLRECYCLING SYMBOL FOR TYPE-1 PLASTICSRECYCL" +
"ING SYMBOL FOR TYPE-2 PLASTICSRECYCLING SYMBOL FOR TYPE-3 PLASTICSRECYCL" +
"ING SYMBOL FOR TYPE-4 PLASTICSRECYCLING SYMBOL FOR TYPE-5 PLASTICSRECYCL" +
"ING SYMBOL FOR TYPE-6 PLASTICSRECYCLING SYMBOL FOR TYPE-7 PLASTICSRECYCL" +
"ING SYMBOL FOR GENERIC MATERIALSBLACK UNIVERSAL RECYCLING SYMBOLRECYCLED" +
" PAPER SYMBOLPARTIALLY-RECYCLED PAPER SYMBOLPERMANENT PAPER SIGNWHEELCHA" +
"IR SYMBOLDIE FACE-1DIE FACE-2DIE FACE-3DIE FACE-4DIE FACE-5DIE FACE-6WHI" +
"TE CIRCLE WITH DOT RIGHTWHITE CIRCLE WITH TWO DOTSBLACK CIRCLE WITH WHIT" +
"E DOT RIGHTBLACK CIRCLE WITH TWO WHITE DOTSMONOGRAM FOR YANGMONOGRAM FOR" +
" YINDIGRAM FOR GREATER YANGDIGRAM FOR LESSER YINDIGRAM FOR LESSER YANGDI" +
"GRAM FOR GREATER YINWHITE FLAGBLACK FLAGHAMMER AND PICKANCHORCROSSED SWO" +
"RDSSTAFF OF AESCULAPIUSSCALESALEMBICFLOWERGEARSTAFF OF HERMESATOM SYMBOL" +
"FLEUR-DE-LISOUTLINED WHITE STARTHREE LINES CONVERGING RIGHTTHREE LINES C" +
"ONVERGING LEFTWARNING SIGNHIGH VOLTAGE SIGNDOUBLED FEMALE SIGNDOUBLED MA" +
"LE SIGNINTERLOCKED FEMALE AND MALE SIGNMALE AND FEMALE SIGNMALE WITH STR" +
"OKE SIGNMALE WITH STROKE AND MALE AND FEMALE SIGNVERTICAL MALE WITH STRO" +
"KE SIGNHORIZONTAL MALE WITH STROKE SIGNMEDIUM WHITE CIRCLEMEDIUM BLACK C" +
"IRCLEMEDIUM SMALL WHITE CIRCLEMARRIAGE SYMBOLDIVORCE SYMBOLUNMARRIED PAR" +
"TNERSHIP SYMBOLCOFFINFUNERAL URNNEUTERCERESPALLASJUNOVESTACHIRONBLACK MO" +
"ON LILITHSEXTILESEMISEXTILEQUINCUNXSESQUIQUADRATESOCCER BALLBASEBALLSQUA" +
"RED KEYWHITE DRAUGHTS MANWHITE DRAUGHTS KINGBLACK DRAUGHTS MANBLACK DRAU" +
"GHTS KINGSNOWMAN WITHOUT SNOWSUN BEHIND CLOUDRAINBLACK SNOWMANTHUNDER CL" +
"OUD AND RAINTURNED WHITE SHOGI PIECETURNED BLACK SHOGI PIECEWHITE DIAMON" +
"D IN SQUARECROSSING LANESDISABLED CAROPHIUCHUSPICKCAR SLIDINGHELMET WITH" +
" WHITE CROSSCIRCLED CROSSING LANESCHAINSNO ENTRYALTERNATE ONE-WAY LEFT W" +
"AY TRAFFICBLACK TWO-WAY LEFT WAY TRAFFICWHITE TWO-WAY LEFT WAY TRAFFICBL" +
"ACK LEFT LANE MERGEWHITE LEFT LANE MERGEDRIVE SLOW SIGNHEAVY WHITE DOWN-" +
"POINTING TRIANGLELEFT CLOSED ENTRYSQUARED SALTIREFALLING DIAGONAL IN WHI" +
"TE CIRCLE IN BLACK SQUAREBLACK TRUCKRESTRICTED LEFT ENTRY-1RESTRICTED LE" +
"FT ENTRY-2ASTRONOMICAL SYMBOL FOR URANUSHEAVY CIRCLE WITH STROKE AND TWO" +
" DOTS ABOVEPENTAGRAMRIGHT-HANDED INTERLACED PENTAGRAMLEFT-HANDED INTERLA" +
"CED PENTAGRAMINVERTED PENTAGRAMBLACK CROSS ON SHIELDSHINTO SHRINECHURCHC" +
"ASTLEHISTORIC SITEGEAR WITHOUT HUBGEAR WITH HANDLESMAP SYMBOL FOR LIGHTH" +
"OUSEMOUNTAINUMBRELLA ON GROUNDFOUNTAINFLAG IN HOLEFERRYSAILBOATSQUARE FO" +
"UR CORNERSSKIERICE SKATEPERSON WITH BALLTENTJAPANESE BANK SYMBOLHEADSTON" +
"E GRAVEYARD SYMBOLFUEL PUMPCUP ON BLACK SQUAREWHITE FLAG WITH HORIZONTAL" +
" MIDDLE BLACK STRIPEBLACK SAFETY SCISSORSUPPER BLADE SCISSORSBLACK SCISS" +
"ORSLOWER BLADE SCISSORSWHITE SCISSORSWHITE HEAVY CHECK MARKTELEPHONE LOC" +
"ATION SIGNTAPE DRIVEAIRPLANEENVELOPERAISED FISTRAISED HANDVICTORY HANDWR" +
"ITING HANDLOWER RIGHT PENCILPENCILUPPER RIGHT PENCILWHITE NIBBLACK NIBCH" +
"ECK MARKHEAVY CHECK MARKMULTIPLICATION XHEAVY MULTIPLICATION XBALLOT XHE" +
"AVY BALLOT XOUTLINED GREEK CROSSHEAVY GREEK CROSSOPEN CENTRE CROSSHEAVY " +
"OPEN CENTRE CROSSLATIN CROSSSHADOWED WHITE LATIN CROSSOUTLINED LATIN CRO" +
"SSMALTESE CROSSSTAR OF DAVIDFOUR TEARDROP-SPOKED ASTERISKFOUR BALLOON-SP" +
"OKED ASTERISKHEAVY FOUR BALLOON-SPOKED ASTERISKFOUR CLUB-SPOKED ASTERISK" +
"BLACK FOUR POINTED STARWHITE FOUR POINTED STARSPARKLESSTRESS OUTLINED WH" +
"ITE STARCIRCLED WHITE STAROPEN CENTRE BLACK STARBLACK CENTRE WHITE STARO" +
"UTLINED BLACK STARHEAVY OUTLINED BLACK STARPINWHEEL STARSHADOWED WHITE S" +
"TARHEAVY ASTERISKOPEN CENTRE ASTERISKEIGHT SPOKED ASTERISKEIGHT POINTED " +
"BLACK STAREIGHT POINTED PINWHEEL STARSIX POINTED BLACK STAREIGHT POINTED" +
" RECTILINEAR BLACK STARHEAVY EIGHT POINTED RECTILINEAR BLACK STARTWELVE " +
"POINTED BLACK STARSIXTEEN POINTED ASTERISKTEARDROP-SPOKED ASTERISKOPEN C" +
"ENTRE TEARDROP-SPOKED ASTERISKHEAVY TEARDROP-SPOKED ASTERISKSIX PETALLED" +
" BLACK AND WHITE FLORETTEBLACK FLORETTEWHITE FLORETTEEIGHT PETALLED OUTL" +
"INED BLACK FLORETTECIRCLED OPEN CENTRE EIGHT POINTED STARHEAVY TEARDROP-" +
"SPOKED PINWHEEL ASTERISKSNOWFLAKETIGHT TRIFOLIATE SNOWFLAKEHEAVY CHEVRON" +
" SNOWFLAKESPARKLEHEAVY SPARKLEBALLOON-SPOKED ASTERISKEIGHT TEARDROP-SPOK" +
"ED PROPELLER ASTERISKHEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISKCROSS" +
" MARKSHADOWED WHITE CIRCLENEGATIVE SQUARED CROSS MARKLOWER RIGHT DROP-SH" +
"ADOWED WHITE SQUAREUPPER RIGHT DROP-SHADOWED WHITE SQUARELOWER RIGHT SHA" +
"DOWED WHITE SQUAREUPPER RIGHT SHADOWED WHITE SQUAREBLACK QUESTION MARK O" +
"RNAMENTWHITE QUESTION MARK ORNAMENTWHITE EXCLAMATION MARK ORNAMENTBLACK " +
"DIAMOND MINUS WHITE XHEAVY EXCLAMATION MARK SYMBOLLIGHT VERTICAL BARMEDI" +
"UM VERTICAL BARHEAVY VERTICAL BARHEAVY SINGLE TURNED COMMA QUOTATION MAR") + ("" +
"K ORNAMENTHEAVY SINGLE COMMA QUOTATION MARK ORNAMENTHEAVY DOUBLE TURNED " +
"COMMA QUOTATION MARK ORNAMENTHEAVY DOUBLE COMMA QUOTATION MARK ORNAMENTH" +
"EAVY LOW SINGLE COMMA QUOTATION MARK ORNAMENTHEAVY LOW DOUBLE COMMA QUOT" +
"ATION MARK ORNAMENTCURVED STEM PARAGRAPH SIGN ORNAMENTHEAVY EXCLAMATION " +
"MARK ORNAMENTHEAVY HEART EXCLAMATION MARK ORNAMENTHEAVY BLACK HEARTROTAT" +
"ED HEAVY BLACK HEART BULLETFLORAL HEARTROTATED FLORAL HEART BULLETMEDIUM" +
" LEFT PARENTHESIS ORNAMENTMEDIUM RIGHT PARENTHESIS ORNAMENTMEDIUM FLATTE" +
"NED LEFT PARENTHESIS ORNAMENTMEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT" +
"MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENTMEDIUM RIGHT-POINTING ANGLE B" +
"RACKET ORNAMENTHEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENTHEAVY RI" +
"GHT-POINTING ANGLE QUOTATION MARK ORNAMENTHEAVY LEFT-POINTING ANGLE BRAC" +
"KET ORNAMENTHEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENTLIGHT LEFT TORTOI" +
"SE SHELL BRACKET ORNAMENTLIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENTMEDI" +
"UM LEFT CURLY BRACKET ORNAMENTMEDIUM RIGHT CURLY BRACKET ORNAMENTDINGBAT" +
" NEGATIVE CIRCLED DIGIT ONEDINGBAT NEGATIVE CIRCLED DIGIT TWODINGBAT NEG" +
"ATIVE CIRCLED DIGIT THREEDINGBAT NEGATIVE CIRCLED DIGIT FOURDINGBAT NEGA" +
"TIVE CIRCLED DIGIT FIVEDINGBAT NEGATIVE CIRCLED DIGIT SIXDINGBAT NEGATIV" +
"E CIRCLED DIGIT SEVENDINGBAT NEGATIVE CIRCLED DIGIT EIGHTDINGBAT NEGATIV" +
"E CIRCLED DIGIT NINEDINGBAT NEGATIVE CIRCLED NUMBER TENDINGBAT CIRCLED S" +
"ANS-SERIF DIGIT ONEDINGBAT CIRCLED SANS-SERIF DIGIT TWODINGBAT CIRCLED S" +
"ANS-SERIF DIGIT THREEDINGBAT CIRCLED SANS-SERIF DIGIT FOURDINGBAT CIRCLE" +
"D SANS-SERIF DIGIT FIVEDINGBAT CIRCLED SANS-SERIF DIGIT SIXDINGBAT CIRCL" +
"ED SANS-SERIF DIGIT SEVENDINGBAT CIRCLED SANS-SERIF DIGIT EIGHTDINGBAT C" +
"IRCLED SANS-SERIF DIGIT NINEDINGBAT CIRCLED SANS-SERIF NUMBER TENDINGBAT" +
" NEGATIVE CIRCLED SANS-SERIF DIGIT ONEDINGBAT NEGATIVE CIRCLED SANS-SERI" +
"F DIGIT TWODINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREEDINGBAT NEGATI" +
"VE CIRCLED SANS-SERIF DIGIT FOURDINGBAT NEGATIVE CIRCLED SANS-SERIF DIGI" +
"T FIVEDINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIXDINGBAT NEGATIVE CIRC" +
"LED SANS-SERIF DIGIT SEVENDINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGH" +
"TDINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINEDINGBAT NEGATIVE CIRCLED " +
"SANS-SERIF NUMBER TENHEAVY WIDE-HEADED RIGHTWARDS ARROWHEAVY PLUS SIGNHE" +
"AVY MINUS SIGNHEAVY DIVISION SIGNHEAVY SOUTH EAST ARROWHEAVY RIGHTWARDS " +
"ARROWHEAVY NORTH EAST ARROWDRAFTING POINT RIGHTWARDS ARROWHEAVY ROUND-TI" +
"PPED RIGHTWARDS ARROWTRIANGLE-HEADED RIGHTWARDS ARROWHEAVY TRIANGLE-HEAD" +
"ED RIGHTWARDS ARROWDASHED TRIANGLE-HEADED RIGHTWARDS ARROWHEAVY DASHED T" +
"RIANGLE-HEADED RIGHTWARDS ARROWBLACK RIGHTWARDS ARROWTHREE-D TOP-LIGHTED" +
" RIGHTWARDS ARROWHEADTHREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEADBLACK RI" +
"GHTWARDS ARROWHEADHEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROWHEAVY" +
" BLACK CURVED UPWARDS AND RIGHTWARDS ARROWSQUAT BLACK RIGHTWARDS ARROWHE" +
"AVY CONCAVE-POINTED BLACK RIGHTWARDS ARROWRIGHT-SHADED WHITE RIGHTWARDS " +
"ARROWLEFT-SHADED WHITE RIGHTWARDS ARROWBACK-TILTED SHADOWED WHITE RIGHTW" +
"ARDS ARROWFRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROWHEAVY LOWER RIGHT-" +
"SHADOWED WHITE RIGHTWARDS ARROWHEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWAR" +
"DS ARROWNOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROWCURLY LOOPNOT" +
"CHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROWCIRCLED HEAVY WHITE RIGH" +
"TWARDS ARROWWHITE-FEATHERED RIGHTWARDS ARROWBLACK-FEATHERED SOUTH EAST A" +
"RROWBLACK-FEATHERED RIGHTWARDS ARROWBLACK-FEATHERED NORTH EAST ARROWHEAV" +
"Y BLACK-FEATHERED SOUTH EAST ARROWHEAVY BLACK-FEATHERED RIGHTWARDS ARROW" +
"HEAVY BLACK-FEATHERED NORTH EAST ARROWTEARDROP-BARBED RIGHTWARDS ARROWHE" +
"AVY TEARDROP-SHANKED RIGHTWARDS ARROWWEDGE-TAILED RIGHTWARDS ARROWHEAVY " +
"WEDGE-TAILED RIGHTWARDS ARROWOPEN-OUTLINED RIGHTWARDS ARROWDOUBLE CURLY " +
"LOOPTHREE DIMENSIONAL ANGLEWHITE TRIANGLE CONTAINING SMALL WHITE TRIANGL" +
"EPERPENDICULAROPEN SUBSETOPEN SUPERSETLEFT S-SHAPED BAG DELIMITERRIGHT S" +
"-SHAPED BAG DELIMITEROR WITH DOT INSIDEREVERSE SOLIDUS PRECEDING SUBSETS" +
"UPERSET PRECEDING SOLIDUSVERTICAL BAR WITH HORIZONTAL STROKEMATHEMATICAL" +
" RISING DIAGONALLONG DIVISIONMATHEMATICAL FALLING DIAGONALSQUARED LOGICA" +
"L ANDSQUARED LOGICAL ORWHITE DIAMOND WITH CENTRED DOTAND WITH DOTELEMENT" +
" OF OPENING UPWARDSLOWER RIGHT CORNER WITH DOTUPPER LEFT CORNER WITH DOT" +
"LEFT OUTER JOINRIGHT OUTER JOINFULL OUTER JOINLARGE UP TACKLARGE DOWN TA" +
"CKLEFT AND RIGHT DOUBLE TURNSTILELEFT AND RIGHT TACKLEFT MULTIMAPLONG RI" +
"GHT TACKLONG LEFT TACKUP TACK WITH CIRCLE ABOVELOZENGE DIVIDED BY HORIZO" +
"NTAL RULEWHITE CONCAVE-SIDED DIAMONDWHITE CONCAVE-SIDED DIAMOND WITH LEF" +
"TWARDS TICKWHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICKWHITE SQUARE " +
"WITH LEFTWARDS TICKWHITE SQUARE WITH RIGHTWARDS TICKMATHEMATICAL LEFT WH") + ("" +
"ITE SQUARE BRACKETMATHEMATICAL RIGHT WHITE SQUARE BRACKETMATHEMATICAL LE" +
"FT ANGLE BRACKETMATHEMATICAL RIGHT ANGLE BRACKETMATHEMATICAL LEFT DOUBLE" +
" ANGLE BRACKETMATHEMATICAL RIGHT DOUBLE ANGLE BRACKETMATHEMATICAL LEFT W" +
"HITE TORTOISE SHELL BRACKETMATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACK" +
"ETMATHEMATICAL LEFT FLATTENED PARENTHESISMATHEMATICAL RIGHT FLATTENED PA" +
"RENTHESISUPWARDS QUADRUPLE ARROWDOWNWARDS QUADRUPLE ARROWANTICLOCKWISE G" +
"APPED CIRCLE ARROWCLOCKWISE GAPPED CIRCLE ARROWRIGHT ARROW WITH CIRCLED " +
"PLUSLONG LEFTWARDS ARROWLONG RIGHTWARDS ARROWLONG LEFT RIGHT ARROWLONG L" +
"EFTWARDS DOUBLE ARROWLONG RIGHTWARDS DOUBLE ARROWLONG LEFT RIGHT DOUBLE " +
"ARROWLONG LEFTWARDS ARROW FROM BARLONG RIGHTWARDS ARROW FROM BARLONG LEF" +
"TWARDS DOUBLE ARROW FROM BARLONG RIGHTWARDS DOUBLE ARROW FROM BARLONG RI" +
"GHTWARDS SQUIGGLE ARROWBRAILLE PATTERN BLANKBRAILLE PATTERN DOTS-1BRAILL" +
"E PATTERN DOTS-2BRAILLE PATTERN DOTS-12BRAILLE PATTERN DOTS-3BRAILLE PAT" +
"TERN DOTS-13BRAILLE PATTERN DOTS-23BRAILLE PATTERN DOTS-123BRAILLE PATTE" +
"RN DOTS-4BRAILLE PATTERN DOTS-14BRAILLE PATTERN DOTS-24BRAILLE PATTERN D" +
"OTS-124BRAILLE PATTERN DOTS-34BRAILLE PATTERN DOTS-134BRAILLE PATTERN DO" +
"TS-234BRAILLE PATTERN DOTS-1234BRAILLE PATTERN DOTS-5BRAILLE PATTERN DOT" +
"S-15BRAILLE PATTERN DOTS-25BRAILLE PATTERN DOTS-125BRAILLE PATTERN DOTS-" +
"35BRAILLE PATTERN DOTS-135BRAILLE PATTERN DOTS-235BRAILLE PATTERN DOTS-1" +
"235BRAILLE PATTERN DOTS-45BRAILLE PATTERN DOTS-145BRAILLE PATTERN DOTS-2" +
"45BRAILLE PATTERN DOTS-1245BRAILLE PATTERN DOTS-345BRAILLE PATTERN DOTS-" +
"1345BRAILLE PATTERN DOTS-2345BRAILLE PATTERN DOTS-12345BRAILLE PATTERN D" +
"OTS-6BRAILLE PATTERN DOTS-16BRAILLE PATTERN DOTS-26BRAILLE PATTERN DOTS-" +
"126BRAILLE PATTERN DOTS-36BRAILLE PATTERN DOTS-136BRAILLE PATTERN DOTS-2" +
"36BRAILLE PATTERN DOTS-1236BRAILLE PATTERN DOTS-46BRAILLE PATTERN DOTS-1" +
"46BRAILLE PATTERN DOTS-246BRAILLE PATTERN DOTS-1246BRAILLE PATTERN DOTS-" +
"346BRAILLE PATTERN DOTS-1346BRAILLE PATTERN DOTS-2346BRAILLE PATTERN DOT" +
"S-12346BRAILLE PATTERN DOTS-56BRAILLE PATTERN DOTS-156BRAILLE PATTERN DO" +
"TS-256BRAILLE PATTERN DOTS-1256BRAILLE PATTERN DOTS-356BRAILLE PATTERN D" +
"OTS-1356BRAILLE PATTERN DOTS-2356BRAILLE PATTERN DOTS-12356BRAILLE PATTE" +
"RN DOTS-456BRAILLE PATTERN DOTS-1456BRAILLE PATTERN DOTS-2456BRAILLE PAT" +
"TERN DOTS-12456BRAILLE PATTERN DOTS-3456BRAILLE PATTERN DOTS-13456BRAILL" +
"E PATTERN DOTS-23456BRAILLE PATTERN DOTS-123456BRAILLE PATTERN DOTS-7BRA" +
"ILLE PATTERN DOTS-17BRAILLE PATTERN DOTS-27BRAILLE PATTERN DOTS-127BRAIL" +
"LE PATTERN DOTS-37BRAILLE PATTERN DOTS-137BRAILLE PATTERN DOTS-237BRAILL" +
"E PATTERN DOTS-1237BRAILLE PATTERN DOTS-47BRAILLE PATTERN DOTS-147BRAILL" +
"E PATTERN DOTS-247BRAILLE PATTERN DOTS-1247BRAILLE PATTERN DOTS-347BRAIL" +
"LE PATTERN DOTS-1347BRAILLE PATTERN DOTS-2347BRAILLE PATTERN DOTS-12347B" +
"RAILLE PATTERN DOTS-57BRAILLE PATTERN DOTS-157BRAILLE PATTERN DOTS-257BR" +
"AILLE PATTERN DOTS-1257BRAILLE PATTERN DOTS-357BRAILLE PATTERN DOTS-1357" +
"BRAILLE PATTERN DOTS-2357BRAILLE PATTERN DOTS-12357BRAILLE PATTERN DOTS-" +
"457BRAILLE PATTERN DOTS-1457BRAILLE PATTERN DOTS-2457BRAILLE PATTERN DOT" +
"S-12457BRAILLE PATTERN DOTS-3457BRAILLE PATTERN DOTS-13457BRAILLE PATTER" +
"N DOTS-23457BRAILLE PATTERN DOTS-123457BRAILLE PATTERN DOTS-67BRAILLE PA" +
"TTERN DOTS-167BRAILLE PATTERN DOTS-267BRAILLE PATTERN DOTS-1267BRAILLE P" +
"ATTERN DOTS-367BRAILLE PATTERN DOTS-1367BRAILLE PATTERN DOTS-2367BRAILLE" +
" PATTERN DOTS-12367BRAILLE PATTERN DOTS-467BRAILLE PATTERN DOTS-1467BRAI" +
"LLE PATTERN DOTS-2467BRAILLE PATTERN DOTS-12467BRAILLE PATTERN DOTS-3467" +
"BRAILLE PATTERN DOTS-13467BRAILLE PATTERN DOTS-23467BRAILLE PATTERN DOTS" +
"-123467BRAILLE PATTERN DOTS-567BRAILLE PATTERN DOTS-1567BRAILLE PATTERN " +
"DOTS-2567BRAILLE PATTERN DOTS-12567BRAILLE PATTERN DOTS-3567BRAILLE PATT" +
"ERN DOTS-13567BRAILLE PATTERN DOTS-23567BRAILLE PATTERN DOTS-123567BRAIL" +
"LE PATTERN DOTS-4567BRAILLE PATTERN DOTS-14567BRAILLE PATTERN DOTS-24567" +
"BRAILLE PATTERN DOTS-124567BRAILLE PATTERN DOTS-34567BRAILLE PATTERN DOT" +
"S-134567BRAILLE PATTERN DOTS-234567BRAILLE PATTERN DOTS-1234567BRAILLE P" +
"ATTERN DOTS-8BRAILLE PATTERN DOTS-18BRAILLE PATTERN DOTS-28BRAILLE PATTE" +
"RN DOTS-128BRAILLE PATTERN DOTS-38BRAILLE PATTERN DOTS-138BRAILLE PATTER" +
"N DOTS-238BRAILLE PATTERN DOTS-1238BRAILLE PATTERN DOTS-48BRAILLE PATTER" +
"N DOTS-148BRAILLE PATTERN DOTS-248BRAILLE PATTERN DOTS-1248BRAILLE PATTE" +
"RN DOTS-348BRAILLE PATTERN DOTS-1348BRAILLE PATTERN DOTS-2348BRAILLE PAT" +
"TERN DOTS-12348BRAILLE PATTERN DOTS-58BRAILLE PATTERN DOTS-158BRAILLE PA" +
"TTERN DOTS-258BRAILLE PATTERN DOTS-1258BRAILLE PATTERN DOTS-358BRAILLE P" +
"ATTERN DOTS-1358BRAILLE PATTERN DOTS-2358BRAILLE PATTERN DOTS-12358BRAIL" +
"LE PATTERN DOTS-458BRAILLE PATTERN DOTS-1458BRAILLE PATTERN DOTS-2458BRA") + ("" +
"ILLE PATTERN DOTS-12458BRAILLE PATTERN DOTS-3458BRAILLE PATTERN DOTS-134" +
"58BRAILLE PATTERN DOTS-23458BRAILLE PATTERN DOTS-123458BRAILLE PATTERN D" +
"OTS-68BRAILLE PATTERN DOTS-168BRAILLE PATTERN DOTS-268BRAILLE PATTERN DO" +
"TS-1268BRAILLE PATTERN DOTS-368BRAILLE PATTERN DOTS-1368BRAILLE PATTERN " +
"DOTS-2368BRAILLE PATTERN DOTS-12368BRAILLE PATTERN DOTS-468BRAILLE PATTE" +
"RN DOTS-1468BRAILLE PATTERN DOTS-2468BRAILLE PATTERN DOTS-12468BRAILLE P" +
"ATTERN DOTS-3468BRAILLE PATTERN DOTS-13468BRAILLE PATTERN DOTS-23468BRAI" +
"LLE PATTERN DOTS-123468BRAILLE PATTERN DOTS-568BRAILLE PATTERN DOTS-1568" +
"BRAILLE PATTERN DOTS-2568BRAILLE PATTERN DOTS-12568BRAILLE PATTERN DOTS-" +
"3568BRAILLE PATTERN DOTS-13568BRAILLE PATTERN DOTS-23568BRAILLE PATTERN " +
"DOTS-123568BRAILLE PATTERN DOTS-4568BRAILLE PATTERN DOTS-14568BRAILLE PA" +
"TTERN DOTS-24568BRAILLE PATTERN DOTS-124568BRAILLE PATTERN DOTS-34568BRA" +
"ILLE PATTERN DOTS-134568BRAILLE PATTERN DOTS-234568BRAILLE PATTERN DOTS-" +
"1234568BRAILLE PATTERN DOTS-78BRAILLE PATTERN DOTS-178BRAILLE PATTERN DO" +
"TS-278BRAILLE PATTERN DOTS-1278BRAILLE PATTERN DOTS-378BRAILLE PATTERN D" +
"OTS-1378BRAILLE PATTERN DOTS-2378BRAILLE PATTERN DOTS-12378BRAILLE PATTE" +
"RN DOTS-478BRAILLE PATTERN DOTS-1478BRAILLE PATTERN DOTS-2478BRAILLE PAT" +
"TERN DOTS-12478BRAILLE PATTERN DOTS-3478BRAILLE PATTERN DOTS-13478BRAILL" +
"E PATTERN DOTS-23478BRAILLE PATTERN DOTS-123478BRAILLE PATTERN DOTS-578B" +
"RAILLE PATTERN DOTS-1578BRAILLE PATTERN DOTS-2578BRAILLE PATTERN DOTS-12" +
"578BRAILLE PATTERN DOTS-3578BRAILLE PATTERN DOTS-13578BRAILLE PATTERN DO" +
"TS-23578BRAILLE PATTERN DOTS-123578BRAILLE PATTERN DOTS-4578BRAILLE PATT" +
"ERN DOTS-14578BRAILLE PATTERN DOTS-24578BRAILLE PATTERN DOTS-124578BRAIL" +
"LE PATTERN DOTS-34578BRAILLE PATTERN DOTS-134578BRAILLE PATTERN DOTS-234" +
"578BRAILLE PATTERN DOTS-1234578BRAILLE PATTERN DOTS-678BRAILLE PATTERN D" +
"OTS-1678BRAILLE PATTERN DOTS-2678BRAILLE PATTERN DOTS-12678BRAILLE PATTE" +
"RN DOTS-3678BRAILLE PATTERN DOTS-13678BRAILLE PATTERN DOTS-23678BRAILLE " +
"PATTERN DOTS-123678BRAILLE PATTERN DOTS-4678BRAILLE PATTERN DOTS-14678BR" +
"AILLE PATTERN DOTS-24678BRAILLE PATTERN DOTS-124678BRAILLE PATTERN DOTS-" +
"34678BRAILLE PATTERN DOTS-134678BRAILLE PATTERN DOTS-234678BRAILLE PATTE" +
"RN DOTS-1234678BRAILLE PATTERN DOTS-5678BRAILLE PATTERN DOTS-15678BRAILL" +
"E PATTERN DOTS-25678BRAILLE PATTERN DOTS-125678BRAILLE PATTERN DOTS-3567" +
"8BRAILLE PATTERN DOTS-135678BRAILLE PATTERN DOTS-235678BRAILLE PATTERN D" +
"OTS-1235678BRAILLE PATTERN DOTS-45678BRAILLE PATTERN DOTS-145678BRAILLE " +
"PATTERN DOTS-245678BRAILLE PATTERN DOTS-1245678BRAILLE PATTERN DOTS-3456" +
"78BRAILLE PATTERN DOTS-1345678BRAILLE PATTERN DOTS-2345678BRAILLE PATTER" +
"N DOTS-12345678RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKERIGHTWARD" +
"S TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKELEFTWARDS DOUBLE ARROW WIT" +
"H VERTICAL STROKERIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKELEFT RIGHT " +
"DOUBLE ARROW WITH VERTICAL STROKERIGHTWARDS TWO-HEADED ARROW FROM BARLEF" +
"TWARDS DOUBLE ARROW FROM BARRIGHTWARDS DOUBLE ARROW FROM BARDOWNWARDS AR" +
"ROW WITH HORIZONTAL STROKEUPWARDS ARROW WITH HORIZONTAL STROKEUPWARDS TR" +
"IPLE ARROWDOWNWARDS TRIPLE ARROWLEFTWARDS DOUBLE DASH ARROWRIGHTWARDS DO" +
"UBLE DASH ARROWLEFTWARDS TRIPLE DASH ARROWRIGHTWARDS TRIPLE DASH ARROWRI" +
"GHTWARDS TWO-HEADED TRIPLE DASH ARROWRIGHTWARDS ARROW WITH DOTTED STEMUP" +
"WARDS ARROW TO BARDOWNWARDS ARROW TO BARRIGHTWARDS ARROW WITH TAIL WITH " +
"VERTICAL STROKERIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKERIG" +
"HTWARDS TWO-HEADED ARROW WITH TAILRIGHTWARDS TWO-HEADED ARROW WITH TAIL " +
"WITH VERTICAL STROKERIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VE" +
"RTICAL STROKELEFTWARDS ARROW-TAILRIGHTWARDS ARROW-TAILLEFTWARDS DOUBLE A" +
"RROW-TAILRIGHTWARDS DOUBLE ARROW-TAILLEFTWARDS ARROW TO BLACK DIAMONDRIG" +
"HTWARDS ARROW TO BLACK DIAMONDLEFTWARDS ARROW FROM BAR TO BLACK DIAMONDR" +
"IGHTWARDS ARROW FROM BAR TO BLACK DIAMONDNORTH WEST AND SOUTH EAST ARROW" +
"NORTH EAST AND SOUTH WEST ARROWNORTH WEST ARROW WITH HOOKNORTH EAST ARRO" +
"W WITH HOOKSOUTH EAST ARROW WITH HOOKSOUTH WEST ARROW WITH HOOKNORTH WES" +
"T ARROW AND NORTH EAST ARROWNORTH EAST ARROW AND SOUTH EAST ARROWSOUTH E" +
"AST ARROW AND SOUTH WEST ARROWSOUTH WEST ARROW AND NORTH WEST ARROWRISIN" +
"G DIAGONAL CROSSING FALLING DIAGONALFALLING DIAGONAL CROSSING RISING DIA" +
"GONALSOUTH EAST ARROW CROSSING NORTH EAST ARROWNORTH EAST ARROW CROSSING" +
" SOUTH EAST ARROWFALLING DIAGONAL CROSSING NORTH EAST ARROWRISING DIAGON" +
"AL CROSSING SOUTH EAST ARROWNORTH EAST ARROW CROSSING NORTH WEST ARROWNO" +
"RTH WEST ARROW CROSSING NORTH EAST ARROWWAVE ARROW POINTING DIRECTLY RIG" +
"HTARROW POINTING RIGHTWARDS THEN CURVING UPWARDSARROW POINTING RIGHTWARD" +
"S THEN CURVING DOWNWARDSARROW POINTING DOWNWARDS THEN CURVING LEFTWARDSA") + ("" +
"RROW POINTING DOWNWARDS THEN CURVING RIGHTWARDSRIGHT-SIDE ARC CLOCKWISE " +
"ARROWLEFT-SIDE ARC ANTICLOCKWISE ARROWTOP ARC ANTICLOCKWISE ARROWBOTTOM " +
"ARC ANTICLOCKWISE ARROWTOP ARC CLOCKWISE ARROW WITH MINUSTOP ARC ANTICLO" +
"CKWISE ARROW WITH PLUSLOWER RIGHT SEMICIRCULAR CLOCKWISE ARROWLOWER LEFT" +
" SEMICIRCULAR ANTICLOCKWISE ARROWANTICLOCKWISE CLOSED CIRCLE ARROWCLOCKW" +
"ISE CLOSED CIRCLE ARROWRIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROWLEFTW" +
"ARDS ARROW ABOVE SHORT RIGHTWARDS ARROWSHORT RIGHTWARDS ARROW ABOVE LEFT" +
"WARDS ARROWRIGHTWARDS ARROW WITH PLUS BELOWLEFTWARDS ARROW WITH PLUS BEL" +
"OWRIGHTWARDS ARROW THROUGH XLEFT RIGHT ARROW THROUGH SMALL CIRCLEUPWARDS" +
" TWO-HEADED ARROW FROM SMALL CIRCLELEFT BARB UP RIGHT BARB DOWN HARPOONL" +
"EFT BARB DOWN RIGHT BARB UP HARPOONUP BARB RIGHT DOWN BARB LEFT HARPOONU" +
"P BARB LEFT DOWN BARB RIGHT HARPOONLEFT BARB UP RIGHT BARB UP HARPOONUP " +
"BARB RIGHT DOWN BARB RIGHT HARPOONLEFT BARB DOWN RIGHT BARB DOWN HARPOON" +
"UP BARB LEFT DOWN BARB LEFT HARPOONLEFTWARDS HARPOON WITH BARB UP TO BAR" +
"RIGHTWARDS HARPOON WITH BARB UP TO BARUPWARDS HARPOON WITH BARB RIGHT TO" +
" BARDOWNWARDS HARPOON WITH BARB RIGHT TO BARLEFTWARDS 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 WITH BARB UP FROM BARUPWARDS HA" +
"RPOON WITH BARB RIGHT FROM BARDOWNWARDS HARPOON WITH BARB RIGHT FROM BAR" +
"LEFTWARDS HARPOON WITH BARB DOWN FROM BARRIGHTWARDS HARPOON WITH BARB DO" +
"WN FROM BARUPWARDS HARPOON WITH BARB LEFT FROM BARDOWNWARDS HARPOON WITH" +
" BARB LEFT FROM BARLEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOO" +
"N WITH BARB DOWNUPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WI" +
"TH BARB RIGHTRIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WI" +
"TH BARB DOWNDOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WI" +
"TH BARB RIGHTLEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WIT" +
"H BARB UPLEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH " +
"BARB DOWNRIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BA" +
"RB UPRIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB" +
" DOWNLEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASHLEFTWARDS HARPOON WIT" +
"H BARB DOWN BELOW LONG DASHRIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DA" +
"SHRIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG 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 ARROWTILDE OPERATOR ABOVE RIGH" +
"TWARDS ARROWLEFTWARDS ARROW ABOVE TILDE OPERATORRIGHTWARDS ARROW ABOVE T" +
"ILDE OPERATORRIGHTWARDS ARROW ABOVE ALMOST EQUAL TOLESS-THAN ABOVE LEFTW" +
"ARDS ARROWLEFTWARDS ARROW THROUGH LESS-THANGREATER-THAN ABOVE RIGHTWARDS" +
" ARROWSUBSET ABOVE RIGHTWARDS ARROWLEFTWARDS ARROW THROUGH SUBSETSUPERSE" +
"T ABOVE LEFTWARDS ARROWLEFT FISH TAILRIGHT FISH TAILUP FISH TAILDOWN FIS" +
"H TAILTRIPLE VERTICAL BAR DELIMITERZ NOTATION SPOTZ NOTATION TYPE COLONL" +
"EFT WHITE CURLY BRACKETRIGHT WHITE CURLY BRACKETLEFT WHITE PARENTHESISRI" +
"GHT WHITE PARENTHESISZ NOTATION LEFT IMAGE BRACKETZ NOTATION RIGHT IMAGE" +
" BRACKETZ NOTATION LEFT BINDING BRACKETZ NOTATION RIGHT BINDING BRACKETL" +
"EFT SQUARE BRACKET WITH UNDERBARRIGHT SQUARE BRACKET WITH UNDERBARLEFT S" +
"QUARE BRACKET WITH TICK IN TOP CORNERRIGHT SQUARE BRACKET WITH TICK IN B" +
"OTTOM CORNERLEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNERRIGHT SQUARE B" +
"RACKET WITH TICK IN TOP CORNERLEFT ANGLE BRACKET WITH DOTRIGHT ANGLE BRA" +
"CKET WITH DOTLEFT ARC LESS-THAN BRACKETRIGHT ARC GREATER-THAN BRACKETDOU" +
"BLE LEFT ARC GREATER-THAN BRACKETDOUBLE RIGHT ARC LESS-THAN BRACKETLEFT " +
"BLACK TORTOISE SHELL BRACKETRIGHT BLACK TORTOISE SHELL BRACKETDOTTED FEN" +
"CEVERTICAL ZIGZAG LINEMEASURED ANGLE OPENING LEFTRIGHT ANGLE VARIANT WIT" +
"H SQUAREMEASURED RIGHT ANGLE WITH DOTANGLE WITH S INSIDEACUTE ANGLESPHER" +
"ICAL ANGLE OPENING LEFTSPHERICAL ANGLE OPENING UPTURNED ANGLEREVERSED AN" +
"GLEANGLE WITH UNDERBARREVERSED ANGLE WITH UNDERBAROBLIQUE ANGLE OPENING " +
"UPOBLIQUE ANGLE OPENING DOWNMEASURED ANGLE WITH OPEN ARM ENDING IN ARROW" +
" POINTING UP AND RIGHTMEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINT" +
"ING UP AND LEFTMEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOW" +
"N AND RIGHTMEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AN" +
"D LEFTMEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP" +
"MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UPMEASURE" +
"D ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWNMEASURED AN" +
"GLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWNREVERSED EMPTY S") + ("" +
"ETEMPTY SET WITH OVERBAREMPTY SET WITH SMALL CIRCLE ABOVEEMPTY SET WITH " +
"RIGHT ARROW ABOVEEMPTY SET WITH LEFT ARROW ABOVECIRCLE WITH HORIZONTAL B" +
"ARCIRCLED VERTICAL BARCIRCLED PARALLELCIRCLED REVERSE SOLIDUSCIRCLED PER" +
"PENDICULARCIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTI" +
"CAL BARCIRCLE WITH SUPERIMPOSED XCIRCLED ANTICLOCKWISE-ROTATED DIVISION " +
"SIGNUP ARROW THROUGH CIRCLECIRCLED WHITE BULLETCIRCLED BULLETCIRCLED LES" +
"S-THANCIRCLED GREATER-THANCIRCLE WITH SMALL CIRCLE TO THE RIGHTCIRCLE WI" +
"TH TWO HORIZONTAL STROKES TO THE RIGHTSQUARED RISING DIAGONAL SLASHSQUAR" +
"ED FALLING DIAGONAL SLASHSQUARED ASTERISKSQUARED SMALL CIRCLESQUARED SQU" +
"ARETWO JOINED SQUARESTRIANGLE WITH DOT ABOVETRIANGLE WITH UNDERBARS IN T" +
"RIANGLETRIANGLE WITH SERIFS AT BOTTOMRIGHT TRIANGLE ABOVE LEFT TRIANGLEL" +
"EFT TRIANGLE BESIDE VERTICAL BARVERTICAL BAR BESIDE RIGHT TRIANGLEBOWTIE" +
" WITH LEFT HALF BLACKBOWTIE WITH RIGHT HALF BLACKBLACK BOWTIETIMES WITH " +
"LEFT HALF BLACKTIMES WITH RIGHT HALF BLACKWHITE HOURGLASSBLACK HOURGLASS" +
"LEFT WIGGLY FENCERIGHT WIGGLY FENCELEFT DOUBLE WIGGLY FENCERIGHT DOUBLE " +
"WIGGLY FENCEINCOMPLETE INFINITYTIE OVER INFINITYINFINITY NEGATED WITH VE" +
"RTICAL BARDOUBLE-ENDED MULTIMAPSQUARE WITH CONTOURED OUTLINEINCREASES AS" +
"SHUFFLE PRODUCTEQUALS SIGN AND SLANTED PARALLELEQUALS SIGN AND SLANTED P" +
"ARALLEL WITH TILDE ABOVEIDENTICAL TO AND SLANTED PARALLELGLEICH STARKTHE" +
"RMODYNAMICDOWN-POINTING TRIANGLE WITH LEFT HALF BLACKDOWN-POINTING TRIAN" +
"GLE WITH RIGHT HALF BLACKBLACK DIAMOND WITH DOWN ARROWBLACK LOZENGEWHITE" +
" CIRCLE WITH DOWN ARROWBLACK CIRCLE WITH DOWN ARROWERROR-BARRED WHITE SQ" +
"UAREERROR-BARRED BLACK SQUAREERROR-BARRED WHITE DIAMONDERROR-BARRED BLAC" +
"K DIAMONDERROR-BARRED WHITE CIRCLEERROR-BARRED BLACK CIRCLERULE-DELAYEDR" +
"EVERSE SOLIDUS OPERATORSOLIDUS WITH OVERBARREVERSE SOLIDUS WITH HORIZONT" +
"AL STROKEBIG SOLIDUSBIG REVERSE SOLIDUSDOUBLE PLUSTRIPLE PLUSLEFT-POINTI" +
"NG CURVED ANGLE BRACKETRIGHT-POINTING CURVED ANGLE BRACKETTINYMINYN-ARY " +
"CIRCLED DOT OPERATORN-ARY CIRCLED PLUS OPERATORN-ARY CIRCLED TIMES OPERA" +
"TORN-ARY UNION OPERATOR WITH DOTN-ARY UNION OPERATOR WITH PLUSN-ARY SQUA" +
"RE INTERSECTION OPERATORN-ARY SQUARE UNION OPERATORTWO LOGICAL AND OPERA" +
"TORTWO LOGICAL OR OPERATORN-ARY TIMES OPERATORMODULO TWO SUMSUMMATION WI" +
"TH INTEGRALQUADRUPLE INTEGRAL OPERATORFINITE PART INTEGRALINTEGRAL WITH " +
"DOUBLE STROKEINTEGRAL AVERAGE WITH SLASHCIRCULATION FUNCTIONANTICLOCKWIS" +
"E INTEGRATIONLINE INTEGRATION WITH RECTANGULAR PATH AROUND POLELINE INTE" +
"GRATION WITH SEMICIRCULAR PATH AROUND POLELINE INTEGRATION NOT INCLUDING" +
" THE POLEINTEGRAL AROUND A POINT OPERATORQUATERNION INTEGRAL OPERATORINT" +
"EGRAL WITH LEFTWARDS ARROW WITH HOOKINTEGRAL WITH TIMES SIGNINTEGRAL WIT" +
"H INTERSECTIONINTEGRAL WITH UNIONINTEGRAL WITH OVERBARINTEGRAL WITH UNDE" +
"RBARJOINLARGE LEFT TRIANGLE OPERATORZ NOTATION SCHEMA COMPOSITIONZ NOTAT" +
"ION SCHEMA PIPINGZ NOTATION SCHEMA PROJECTIONPLUS SIGN WITH SMALL CIRCLE" +
" ABOVEPLUS SIGN WITH CIRCUMFLEX ACCENT ABOVEPLUS SIGN WITH TILDE ABOVEPL" +
"US SIGN WITH DOT BELOWPLUS SIGN WITH TILDE BELOWPLUS SIGN WITH SUBSCRIPT" +
" TWOPLUS SIGN WITH BLACK TRIANGLEMINUS SIGN WITH COMMA ABOVEMINUS SIGN W" +
"ITH DOT BELOWMINUS SIGN WITH FALLING DOTSMINUS SIGN WITH RISING DOTSPLUS" +
" SIGN IN LEFT HALF CIRCLEPLUS SIGN IN RIGHT HALF CIRCLEVECTOR OR CROSS P" +
"RODUCTMULTIPLICATION SIGN WITH DOT ABOVEMULTIPLICATION SIGN WITH UNDERBA" +
"RSEMIDIRECT PRODUCT WITH BOTTOM CLOSEDSMASH PRODUCTMULTIPLICATION SIGN I" +
"N LEFT HALF CIRCLEMULTIPLICATION SIGN IN RIGHT HALF CIRCLECIRCLED MULTIP" +
"LICATION SIGN WITH CIRCUMFLEX ACCENTMULTIPLICATION SIGN IN DOUBLE CIRCLE" +
"CIRCLED DIVISION SIGNPLUS SIGN IN TRIANGLEMINUS SIGN IN TRIANGLEMULTIPLI" +
"CATION SIGN IN TRIANGLEINTERIOR PRODUCTRIGHTHAND INTERIOR PRODUCTZ NOTAT" +
"ION RELATIONAL COMPOSITIONAMALGAMATION OR COPRODUCTINTERSECTION WITH DOT" +
"UNION WITH MINUS SIGNUNION WITH OVERBARINTERSECTION WITH OVERBARINTERSEC" +
"TION WITH LOGICAL ANDUNION WITH LOGICAL ORUNION ABOVE INTERSECTIONINTERS" +
"ECTION ABOVE UNIONUNION ABOVE BAR ABOVE INTERSECTIONINTERSECTION ABOVE B" +
"AR ABOVE UNIONUNION BESIDE AND JOINED WITH UNIONINTERSECTION BESIDE AND " +
"JOINED WITH INTERSECTIONCLOSED UNION WITH SERIFSCLOSED INTERSECTION WITH" +
" SERIFSDOUBLE SQUARE INTERSECTIONDOUBLE SQUARE UNIONCLOSED UNION WITH SE" +
"RIFS AND SMASH PRODUCTLOGICAL AND WITH DOT ABOVELOGICAL OR WITH DOT ABOV" +
"EDOUBLE LOGICAL ANDDOUBLE LOGICAL ORTWO INTERSECTING LOGICAL ANDTWO INTE" +
"RSECTING LOGICAL ORSLOPING LARGE ORSLOPING LARGE ANDLOGICAL OR OVERLAPPI" +
"NG LOGICAL ANDLOGICAL AND WITH MIDDLE STEMLOGICAL OR WITH MIDDLE STEMLOG" +
"ICAL AND WITH HORIZONTAL DASHLOGICAL OR WITH HORIZONTAL DASHLOGICAL AND " +
"WITH DOUBLE OVERBARLOGICAL AND WITH UNDERBARLOGICAL AND WITH DOUBLE UNDE") + ("" +
"RBARSMALL VEE WITH UNDERBARLOGICAL OR WITH DOUBLE OVERBARLOGICAL OR WITH" +
" DOUBLE UNDERBARZ NOTATION DOMAIN ANTIRESTRICTIONZ NOTATION RANGE ANTIRE" +
"STRICTIONEQUALS SIGN WITH DOT BELOWIDENTICAL WITH DOT ABOVETRIPLE HORIZO" +
"NTAL BAR WITH DOUBLE VERTICAL STROKETRIPLE HORIZONTAL BAR WITH TRIPLE VE" +
"RTICAL STROKETILDE OPERATOR WITH DOT ABOVETILDE OPERATOR WITH RISING DOT" +
"SSIMILAR MINUS SIMILARCONGRUENT WITH DOT ABOVEEQUALS WITH ASTERISKALMOST" +
" EQUAL TO WITH CIRCUMFLEX ACCENTAPPROXIMATELY EQUAL OR EQUAL TOEQUALS SI" +
"GN ABOVE PLUS SIGNPLUS SIGN ABOVE EQUALS SIGNEQUALS SIGN ABOVE TILDE OPE" +
"RATORDOUBLE COLON EQUALTWO CONSECUTIVE EQUALS SIGNSTHREE CONSECUTIVE EQU" +
"ALS SIGNSEQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOWEQUIVALENT WI" +
"TH FOUR DOTS ABOVELESS-THAN WITH CIRCLE INSIDEGREATER-THAN WITH CIRCLE I" +
"NSIDELESS-THAN WITH QUESTION MARK ABOVEGREATER-THAN WITH QUESTION MARK A" +
"BOVELESS-THAN OR SLANTED EQUAL TOGREATER-THAN OR SLANTED EQUAL TOLESS-TH" +
"AN OR SLANTED EQUAL TO WITH DOT INSIDEGREATER-THAN OR SLANTED EQUAL TO W" +
"ITH DOT INSIDELESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVEGREATER-THAN O" +
"R SLANTED EQUAL TO WITH DOT ABOVELESS-THAN OR SLANTED EQUAL TO WITH DOT " +
"ABOVE RIGHTGREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFTLESS-THAN" +
" OR APPROXIMATEGREATER-THAN OR APPROXIMATELESS-THAN AND SINGLE-LINE NOT " +
"EQUAL TOGREATER-THAN AND SINGLE-LINE NOT EQUAL TOLESS-THAN AND NOT APPRO" +
"XIMATEGREATER-THAN AND NOT APPROXIMATELESS-THAN ABOVE DOUBLE-LINE EQUAL " +
"ABOVE GREATER-THANGREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THANLE" +
"SS-THAN ABOVE SIMILAR OR EQUALGREATER-THAN ABOVE SIMILAR OR EQUALLESS-TH" +
"AN ABOVE SIMILAR ABOVE GREATER-THANGREATER-THAN ABOVE SIMILAR ABOVE LESS" +
"-THANLESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUALGREATER-THAN AB" +
"OVE LESS-THAN ABOVE DOUBLE-LINE EQUALLESS-THAN ABOVE SLANTED EQUAL ABOVE" +
" GREATER-THAN ABOVE SLANTED EQUALGREATER-THAN ABOVE SLANTED EQUAL ABOVE " +
"LESS-THAN ABOVE SLANTED EQUALSLANTED EQUAL TO OR LESS-THANSLANTED EQUAL " +
"TO OR GREATER-THANSLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDESLANTED E" +
"QUAL TO OR GREATER-THAN WITH DOT INSIDEDOUBLE-LINE EQUAL TO OR LESS-THAN" +
"DOUBLE-LINE EQUAL TO OR GREATER-THANDOUBLE-LINE SLANTED EQUAL TO OR LESS" +
"-THANDOUBLE-LINE SLANTED EQUAL TO OR GREATER-THANSIMILAR OR LESS-THANSIM" +
"ILAR OR GREATER-THANSIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGNSIMILAR ABO" +
"VE GREATER-THAN ABOVE EQUALS SIGNDOUBLE NESTED LESS-THANDOUBLE NESTED GR" +
"EATER-THANDOUBLE NESTED LESS-THAN WITH UNDERBARGREATER-THAN OVERLAPPING " +
"LESS-THANGREATER-THAN BESIDE LESS-THANLESS-THAN CLOSED BY CURVEGREATER-T" +
"HAN CLOSED BY CURVELESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUALGREATER-" +
"THAN CLOSED BY CURVE ABOVE SLANTED EQUALSMALLER THANLARGER THANSMALLER T" +
"HAN OR EQUAL TOLARGER THAN OR EQUAL TOEQUALS SIGN WITH BUMPY ABOVEPRECED" +
"ES ABOVE SINGLE-LINE EQUALS SIGNSUCCEEDS ABOVE SINGLE-LINE EQUALS SIGNPR" +
"ECEDES ABOVE SINGLE-LINE NOT EQUAL TOSUCCEEDS ABOVE SINGLE-LINE NOT EQUA" +
"L TOPRECEDES ABOVE EQUALS SIGNSUCCEEDS ABOVE EQUALS SIGNPRECEDES ABOVE N" +
"OT EQUAL TOSUCCEEDS ABOVE NOT EQUAL TOPRECEDES ABOVE ALMOST EQUAL TOSUCC" +
"EEDS ABOVE ALMOST EQUAL TOPRECEDES ABOVE NOT ALMOST EQUAL TOSUCCEEDS ABO" +
"VE NOT ALMOST EQUAL TODOUBLE PRECEDESDOUBLE SUCCEEDSSUBSET WITH DOTSUPER" +
"SET WITH DOTSUBSET WITH PLUS SIGN BELOWSUPERSET WITH PLUS SIGN BELOWSUBS" +
"ET WITH MULTIPLICATION SIGN BELOWSUPERSET WITH MULTIPLICATION SIGN BELOW" +
"SUBSET OF OR EQUAL TO WITH DOT ABOVESUPERSET OF OR EQUAL TO WITH DOT ABO" +
"VESUBSET OF ABOVE EQUALS SIGNSUPERSET OF ABOVE EQUALS SIGNSUBSET OF ABOV" +
"E TILDE OPERATORSUPERSET OF ABOVE TILDE OPERATORSUBSET OF ABOVE ALMOST E" +
"QUAL TOSUPERSET OF ABOVE ALMOST EQUAL TOSUBSET OF ABOVE NOT EQUAL TOSUPE" +
"RSET OF ABOVE NOT EQUAL TOSQUARE LEFT OPEN BOX OPERATORSQUARE RIGHT OPEN" +
" BOX OPERATORCLOSED SUBSETCLOSED SUPERSETCLOSED SUBSET OR EQUAL TOCLOSED" +
" SUPERSET OR EQUAL TOSUBSET ABOVE SUPERSETSUPERSET ABOVE SUBSETSUBSET AB" +
"OVE SUBSETSUPERSET ABOVE SUPERSETSUPERSET BESIDE SUBSETSUPERSET BESIDE A" +
"ND JOINED BY DASH WITH SUBSETELEMENT OF OPENING DOWNWARDSPITCHFORK WITH " +
"TEE TOPTRANSVERSAL INTERSECTIONFORKINGNONFORKINGSHORT LEFT TACKSHORT DOW" +
"N TACKSHORT UP TACKPERPENDICULAR WITH SVERTICAL BAR TRIPLE RIGHT TURNSTI" +
"LEDOUBLE VERTICAL BAR LEFT TURNSTILEVERTICAL BAR DOUBLE LEFT TURNSTILEDO" +
"UBLE VERTICAL BAR DOUBLE LEFT TURNSTILELONG DASH FROM LEFT MEMBER OF DOU" +
"BLE VERTICALSHORT DOWN TACK WITH OVERBARSHORT UP TACK WITH UNDERBARSHORT" +
" UP TACK ABOVE SHORT DOWN TACKDOUBLE DOWN TACKDOUBLE UP TACKDOUBLE STROK" +
"E NOT SIGNREVERSED DOUBLE STROKE NOT SIGNDOES NOT DIVIDE WITH REVERSED N" +
"EGATION SLASHVERTICAL LINE WITH CIRCLE ABOVEVERTICAL LINE WITH CIRCLE BE" +
"LOWDOWN TACK WITH CIRCLE BELOWPARALLEL WITH HORIZONTAL STROKEPARALLEL WI") + ("" +
"TH TILDE OPERATORTRIPLE VERTICAL BAR BINARY RELATIONTRIPLE VERTICAL BAR " +
"WITH HORIZONTAL STROKETRIPLE COLON OPERATORTRIPLE NESTED LESS-THANTRIPLE" +
" NESTED GREATER-THANDOUBLE-LINE SLANTED LESS-THAN OR EQUAL TODOUBLE-LINE" +
" SLANTED GREATER-THAN OR EQUAL TOTRIPLE SOLIDUS BINARY RELATIONLARGE TRI" +
"PLE VERTICAL BAR OPERATORDOUBLE SOLIDUS OPERATORWHITE VERTICAL BARN-ARY " +
"WHITE VERTICAL BARNORTH EAST WHITE ARROWNORTH WEST WHITE ARROWSOUTH EAST" +
" WHITE ARROWSOUTH WEST WHITE ARROWLEFT RIGHT WHITE ARROWLEFTWARDS BLACK " +
"ARROWUPWARDS BLACK ARROWDOWNWARDS BLACK ARROWNORTH EAST BLACK ARROWNORTH" +
" WEST BLACK ARROWSOUTH EAST BLACK ARROWSOUTH WEST BLACK ARROWLEFT RIGHT " +
"BLACK ARROWUP DOWN BLACK ARROWRIGHTWARDS ARROW WITH TIP DOWNWARDSRIGHTWA" +
"RDS ARROW WITH TIP UPWARDSLEFTWARDS ARROW WITH TIP DOWNWARDSLEFTWARDS AR" +
"ROW WITH TIP UPWARDSSQUARE WITH TOP HALF BLACKSQUARE WITH BOTTOM HALF BL" +
"ACKSQUARE WITH UPPER RIGHT DIAGONAL HALF BLACKSQUARE WITH LOWER LEFT DIA" +
"GONAL HALF BLACKDIAMOND WITH LEFT HALF BLACKDIAMOND WITH RIGHT HALF BLAC" +
"KDIAMOND WITH TOP HALF BLACKDIAMOND WITH BOTTOM HALF BLACKDOTTED SQUAREB" +
"LACK LARGE SQUAREWHITE LARGE SQUAREBLACK VERY SMALL SQUAREWHITE VERY SMA" +
"LL SQUAREBLACK PENTAGONWHITE PENTAGONWHITE HEXAGONBLACK HEXAGONHORIZONTA" +
"L BLACK HEXAGONBLACK LARGE CIRCLEBLACK MEDIUM DIAMONDWHITE MEDIUM DIAMON" +
"DBLACK MEDIUM LOZENGEWHITE MEDIUM LOZENGEBLACK SMALL DIAMONDBLACK SMALL " +
"LOZENGEWHITE SMALL LOZENGEBLACK HORIZONTAL ELLIPSEWHITE HORIZONTAL ELLIP" +
"SEBLACK VERTICAL ELLIPSEWHITE VERTICAL ELLIPSELEFT ARROW WITH SMALL CIRC" +
"LETHREE LEFTWARDS ARROWSLEFT ARROW WITH CIRCLED PLUSLONG LEFTWARDS SQUIG" +
"GLE ARROWLEFTWARDS TWO-HEADED ARROW WITH VERTICAL STROKELEFTWARDS TWO-HE" +
"ADED ARROW WITH DOUBLE VERTICAL STROKELEFTWARDS TWO-HEADED ARROW FROM BA" +
"RLEFTWARDS TWO-HEADED TRIPLE DASH ARROWLEFTWARDS ARROW WITH DOTTED STEML" +
"EFTWARDS ARROW WITH TAIL WITH VERTICAL STROKELEFTWARDS ARROW WITH TAIL W" +
"ITH DOUBLE VERTICAL STROKELEFTWARDS TWO-HEADED ARROW WITH TAILLEFTWARDS " +
"TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKELEFTWARDS TWO-HEADED ARRO" +
"W WITH TAIL WITH DOUBLE VERTICAL STROKELEFTWARDS ARROW THROUGH XWAVE ARR" +
"OW POINTING DIRECTLY LEFTEQUALS SIGN ABOVE LEFTWARDS ARROWREVERSE TILDE " +
"OPERATOR ABOVE LEFTWARDS ARROWLEFTWARDS ARROW ABOVE REVERSE ALMOST EQUAL" +
" TORIGHTWARDS ARROW THROUGH GREATER-THANRIGHTWARDS ARROW THROUGH SUPERSE" +
"TLEFTWARDS QUADRUPLE ARROWRIGHTWARDS QUADRUPLE ARROWREVERSE TILDE OPERAT" +
"OR ABOVE RIGHTWARDS ARROWRIGHTWARDS ARROW ABOVE REVERSE ALMOST EQUAL TOT" +
"ILDE OPERATOR ABOVE LEFTWARDS ARROWLEFTWARDS ARROW ABOVE ALMOST EQUAL TO" +
"LEFTWARDS ARROW ABOVE REVERSE TILDE OPERATORRIGHTWARDS ARROW ABOVE REVER" +
"SE TILDE OPERATORDOWNWARDS TRIANGLE-HEADED ZIGZAG ARROWSHORT SLANTED NOR" +
"TH ARROWSHORT BACKSLANTED SOUTH ARROWWHITE MEDIUM STARBLACK SMALL STARWH" +
"ITE SMALL STARBLACK RIGHT-POINTING PENTAGONWHITE RIGHT-POINTING PENTAGON" +
"HEAVY LARGE CIRCLEHEAVY OVAL WITH OVAL INSIDEHEAVY CIRCLE WITH CIRCLE IN" +
"SIDEHEAVY CIRCLEHEAVY CIRCLED SALTIRESLANTED NORTH ARROW WITH HOOKED HEA" +
"DBACKSLANTED SOUTH ARROW WITH HOOKED TAILSLANTED NORTH ARROW WITH HORIZO" +
"NTAL TAILBACKSLANTED SOUTH ARROW WITH HORIZONTAL TAILBENT ARROW POINTING" +
" DOWNWARDS THEN NORTH EASTSHORT BENT ARROW POINTING DOWNWARDS THEN NORTH" +
" EASTLEFTWARDS TRIANGLE-HEADED ARROWUPWARDS TRIANGLE-HEADED ARROWRIGHTWA" +
"RDS TRIANGLE-HEADED ARROWDOWNWARDS TRIANGLE-HEADED ARROWLEFT RIGHT TRIAN" +
"GLE-HEADED ARROWUP DOWN TRIANGLE-HEADED ARROWNORTH WEST TRIANGLE-HEADED " +
"ARROWNORTH EAST TRIANGLE-HEADED ARROWSOUTH EAST TRIANGLE-HEADED ARROWSOU" +
"TH WEST TRIANGLE-HEADED ARROWLEFTWARDS TRIANGLE-HEADED DASHED ARROWUPWAR" +
"DS TRIANGLE-HEADED DASHED ARROWRIGHTWARDS TRIANGLE-HEADED DASHED ARROWDO" +
"WNWARDS TRIANGLE-HEADED DASHED ARROWCLOCKWISE TRIANGLE-HEADED OPEN CIRCL" +
"E ARROWANTICLOCKWISE TRIANGLE-HEADED OPEN CIRCLE ARROWLEFTWARDS TRIANGLE" +
"-HEADED ARROW TO BARUPWARDS TRIANGLE-HEADED ARROW TO BARRIGHTWARDS TRIAN" +
"GLE-HEADED ARROW TO BARDOWNWARDS TRIANGLE-HEADED ARROW TO BARNORTH WEST " +
"TRIANGLE-HEADED ARROW TO BARNORTH EAST TRIANGLE-HEADED ARROW TO BARSOUTH" +
" EAST TRIANGLE-HEADED ARROW TO BARSOUTH WEST TRIANGLE-HEADED ARROW TO BA" +
"RLEFTWARDS TRIANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKEUPWARDS TR" +
"IANGLE-HEADED ARROW WITH DOUBLE HORIZONTAL STROKERIGHTWARDS TRIANGLE-HEA" +
"DED ARROW WITH DOUBLE HORIZONTAL STROKEDOWNWARDS TRIANGLE-HEADED ARROW W" +
"ITH DOUBLE HORIZONTAL STROKEHORIZONTAL TAB KEYVERTICAL TAB KEYLEFTWARDS " +
"TRIANGLE-HEADED ARROW OVER RIGHTWARDS TRIANGLE-HEADED ARROWUPWARDS TRIAN" +
"GLE-HEADED ARROW LEFTWARDS OF DOWNWARDS TRIANGLE-HEADED ARROWRIGHTWARDS " +
"TRIANGLE-HEADED ARROW OVER LEFTWARDS TRIANGLE-HEADED ARROWDOWNWARDS TRIA" +
"NGLE-HEADED ARROW LEFTWARDS OF UPWARDS TRIANGLE-HEADED ARROWLEFTWARDS TR") + ("" +
"IANGLE-HEADED PAIRED ARROWSUPWARDS TRIANGLE-HEADED PAIRED ARROWSRIGHTWAR" +
"DS TRIANGLE-HEADED PAIRED ARROWSDOWNWARDS TRIANGLE-HEADED PAIRED ARROWSL" +
"EFTWARDS BLACK CIRCLED WHITE ARROWUPWARDS BLACK CIRCLED WHITE ARROWRIGHT" +
"WARDS BLACK CIRCLED WHITE ARROWDOWNWARDS BLACK CIRCLED WHITE ARROWANTICL" +
"OCKWISE TRIANGLE-HEADED RIGHT U-SHAPED ARROWANTICLOCKWISE TRIANGLE-HEADE" +
"D BOTTOM U-SHAPED ARROWANTICLOCKWISE TRIANGLE-HEADED LEFT U-SHAPED ARROW" +
"ANTICLOCKWISE TRIANGLE-HEADED TOP U-SHAPED ARROWRETURN LEFTRETURN RIGHTN" +
"EWLINE LEFTNEWLINE RIGHTFOUR CORNER ARROWS CIRCLING ANTICLOCKWISERIGHTWA" +
"RDS BLACK ARROWEQUALS SIGN WITH INFINITY ABOVESYMBOL FOR TYPE A ELECTRON" +
"ICSTHREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEADTHREE-D RIGHT-LIGH" +
"TED UPWARDS EQUILATERAL ARROWHEADTHREE-D TOP-LIGHTED RIGHTWARDS EQUILATE" +
"RAL ARROWHEADTHREE-D LEFT-LIGHTED DOWNWARDS EQUILATERAL ARROWHEADBLACK L" +
"EFTWARDS EQUILATERAL ARROWHEADBLACK UPWARDS EQUILATERAL ARROWHEADBLACK R" +
"IGHTWARDS EQUILATERAL ARROWHEADBLACK DOWNWARDS EQUILATERAL ARROWHEADDOWN" +
"WARDS TRIANGLE-HEADED ARROW WITH LONG TIP LEFTWARDSDOWNWARDS TRIANGLE-HE" +
"ADED ARROW WITH LONG TIP RIGHTWARDSUPWARDS TRIANGLE-HEADED ARROW WITH LO" +
"NG TIP LEFTWARDSUPWARDS TRIANGLE-HEADED ARROW WITH LONG TIP RIGHTWARDSLE" +
"FTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP UPWARDSRIGHTWARDS TRIANGLE-H" +
"EADED ARROW WITH LONG TIP UPWARDSLEFTWARDS TRIANGLE-HEADED ARROW WITH LO" +
"NG TIP DOWNWARDSRIGHTWARDS TRIANGLE-HEADED ARROW WITH LONG TIP DOWNWARDS" +
"BLACK CURVED DOWNWARDS AND LEFTWARDS ARROWBLACK CURVED DOWNWARDS AND RIG" +
"HTWARDS ARROWBLACK CURVED UPWARDS AND LEFTWARDS ARROWBLACK CURVED UPWARD" +
"S AND RIGHTWARDS ARROWBLACK CURVED LEFTWARDS AND UPWARDS ARROWBLACK CURV" +
"ED RIGHTWARDS AND UPWARDS ARROWBLACK CURVED LEFTWARDS AND DOWNWARDS ARRO" +
"WBLACK CURVED RIGHTWARDS AND DOWNWARDS ARROWRIBBON ARROW DOWN LEFTRIBBON" +
" ARROW DOWN RIGHTRIBBON ARROW UP LEFTRIBBON ARROW UP RIGHTRIBBON ARROW L" +
"EFT UPRIBBON ARROW RIGHT UPRIBBON ARROW LEFT DOWNRIBBON ARROW RIGHT DOWN" +
"UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BARUP ARROWHEAD IN A RECTAN" +
"GLE BOXOVERLAPPING WHITE SQUARESOVERLAPPING WHITE AND BLACK SQUARESOVERL" +
"APPING BLACK SQUARESBALLOT BOX WITH LIGHT XCIRCLED XCIRCLED BOLD XBLACK " +
"SQUARE CENTREDBLACK DIAMOND CENTREDTURNED BLACK PENTAGONHORIZONTAL BLACK" +
" OCTAGONBLACK OCTAGONBLACK MEDIUM UP-POINTING TRIANGLE CENTREDBLACK MEDI" +
"UM DOWN-POINTING TRIANGLE CENTREDBLACK MEDIUM LEFT-POINTING TRIANGLE CEN" +
"TREDBLACK MEDIUM RIGHT-POINTING TRIANGLE CENTREDNEPTUNE FORM TWOTOP HALF" +
" BLACK CIRCLEBOTTOM HALF BLACK CIRCLELIGHT FOUR POINTED BLACK CUSPROTATE" +
"D LIGHT FOUR POINTED BLACK CUSPWHITE FOUR POINTED CUSPROTATED WHITE FOUR" +
" POINTED CUSPSQUARE POSITION INDICATORUNCERTAINTY SIGNGROUP MARKPLUTO FO" +
"RM TWOPLUTO FORM THREEPLUTO FORM FOURPLUTO FORM FIVETRANSPLUTOPROSERPINA" +
"ASTRAEAHYGIEAPHOLUSNESSUSWHITE MOON SELENABLACK DIAMOND ON CROSSTRUE LIG" +
"HT MOON ARTACUPIDOHADESZEUSKRONOSAPOLLONADMETOSVULCANUSPOSEIDONLEFT HALF" +
" BLACK STARRIGHT HALF BLACK STARSTAR WITH LEFT HALF BLACKSTAR WITH RIGHT" +
" HALF BLACKLEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADSUPWARDS TW" +
"O-HEADED ARROW WITH TRIANGLE ARROWHEADSRIGHTWARDS TWO-HEADED ARROW WITH " +
"TRIANGLE ARROWHEADSDOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADSER" +
"IS FORM ONEERIS FORM TWOSEDNARUSSIAN ASTROLOGICAL SYMBOL VIGINTILERUSSIA" +
"N ASTROLOGICAL SYMBOL NOVILERUSSIAN ASTROLOGICAL SYMBOL QUINTILERUSSIAN " +
"ASTROLOGICAL SYMBOL BINOVILERUSSIAN ASTROLOGICAL SYMBOL SENTAGONRUSSIAN " +
"ASTROLOGICAL SYMBOL TREDECILEEQUALS SIGN WITH INFINITY BELOWUNITED SYMBO" +
"LSEPARATED SYMBOLDOUBLED SYMBOLPASSED SYMBOLREVERSED RIGHT ANGLEHELLSCHR" +
"EIBER PAUSE SYMBOLGLAGOLITIC CAPITAL LETTER AZUGLAGOLITIC CAPITAL LETTER" +
" BUKYGLAGOLITIC CAPITAL LETTER VEDEGLAGOLITIC CAPITAL LETTER GLAGOLIGLAG" +
"OLITIC CAPITAL LETTER DOBROGLAGOLITIC CAPITAL LETTER YESTUGLAGOLITIC CAP" +
"ITAL LETTER ZHIVETEGLAGOLITIC CAPITAL LETTER DZELOGLAGOLITIC CAPITAL LET" +
"TER ZEMLJAGLAGOLITIC CAPITAL LETTER IZHEGLAGOLITIC CAPITAL LETTER INITIA" +
"L IZHEGLAGOLITIC CAPITAL LETTER IGLAGOLITIC CAPITAL LETTER DJERVIGLAGOLI" +
"TIC CAPITAL LETTER KAKOGLAGOLITIC CAPITAL LETTER LJUDIJEGLAGOLITIC CAPIT" +
"AL LETTER MYSLITEGLAGOLITIC CAPITAL LETTER NASHIGLAGOLITIC CAPITAL LETTE" +
"R ONUGLAGOLITIC CAPITAL LETTER POKOJIGLAGOLITIC CAPITAL LETTER RITSIGLAG" +
"OLITIC CAPITAL LETTER SLOVOGLAGOLITIC CAPITAL LETTER TVRIDOGLAGOLITIC CA" +
"PITAL LETTER UKUGLAGOLITIC CAPITAL LETTER FRITUGLAGOLITIC CAPITAL LETTER" +
" HERUGLAGOLITIC CAPITAL LETTER OTUGLAGOLITIC CAPITAL LETTER PEGLAGOLITIC" +
" CAPITAL LETTER SHTAGLAGOLITIC CAPITAL LETTER TSIGLAGOLITIC CAPITAL LETT" +
"ER CHRIVIGLAGOLITIC CAPITAL LETTER SHAGLAGOLITIC CAPITAL LETTER YERUGLAG" +
"OLITIC CAPITAL LETTER YERIGLAGOLITIC CAPITAL LETTER YATIGLAGOLITIC CAPIT") + ("" +
"AL LETTER SPIDERY HAGLAGOLITIC CAPITAL LETTER YUGLAGOLITIC CAPITAL LETTE" +
"R SMALL YUSGLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAILGLAGOLITIC CAPIT" +
"AL LETTER YOGLAGOLITIC CAPITAL LETTER IOTATED SMALL YUSGLAGOLITIC CAPITA" +
"L LETTER BIG YUSGLAGOLITIC CAPITAL LETTER IOTATED BIG YUSGLAGOLITIC CAPI" +
"TAL LETTER FITAGLAGOLITIC CAPITAL LETTER IZHITSAGLAGOLITIC CAPITAL LETTE" +
"R SHTAPICGLAGOLITIC CAPITAL LETTER TROKUTASTI AGLAGOLITIC CAPITAL LETTER" +
" LATINATE MYSLITEGLAGOLITIC CAPITAL LETTER CAUDATE CHRIVIGLAGOLITIC SMAL" +
"L LETTER AZUGLAGOLITIC SMALL LETTER BUKYGLAGOLITIC SMALL LETTER VEDEGLAG" +
"OLITIC SMALL LETTER GLAGOLIGLAGOLITIC SMALL LETTER DOBROGLAGOLITIC SMALL" +
" LETTER YESTUGLAGOLITIC SMALL LETTER ZHIVETEGLAGOLITIC SMALL LETTER DZEL" +
"OGLAGOLITIC SMALL LETTER ZEMLJAGLAGOLITIC SMALL LETTER IZHEGLAGOLITIC SM" +
"ALL LETTER INITIAL IZHEGLAGOLITIC SMALL LETTER IGLAGOLITIC SMALL LETTER " +
"DJERVIGLAGOLITIC SMALL LETTER KAKOGLAGOLITIC SMALL LETTER LJUDIJEGLAGOLI" +
"TIC SMALL LETTER MYSLITEGLAGOLITIC SMALL LETTER NASHIGLAGOLITIC SMALL LE" +
"TTER ONUGLAGOLITIC SMALL LETTER POKOJIGLAGOLITIC SMALL LETTER RITSIGLAGO" +
"LITIC SMALL LETTER SLOVOGLAGOLITIC SMALL LETTER TVRIDOGLAGOLITIC SMALL L" +
"ETTER UKUGLAGOLITIC SMALL LETTER FRITUGLAGOLITIC SMALL LETTER HERUGLAGOL" +
"ITIC SMALL LETTER OTUGLAGOLITIC SMALL LETTER PEGLAGOLITIC SMALL LETTER S" +
"HTAGLAGOLITIC SMALL LETTER TSIGLAGOLITIC SMALL LETTER CHRIVIGLAGOLITIC S" +
"MALL LETTER SHAGLAGOLITIC SMALL LETTER YERUGLAGOLITIC SMALL LETTER YERIG" +
"LAGOLITIC SMALL LETTER YATIGLAGOLITIC SMALL LETTER SPIDERY HAGLAGOLITIC " +
"SMALL LETTER YUGLAGOLITIC SMALL LETTER SMALL YUSGLAGOLITIC SMALL LETTER " +
"SMALL YUS WITH TAILGLAGOLITIC SMALL LETTER YOGLAGOLITIC SMALL LETTER IOT" +
"ATED SMALL YUSGLAGOLITIC SMALL LETTER BIG YUSGLAGOLITIC SMALL LETTER IOT" +
"ATED BIG YUSGLAGOLITIC SMALL LETTER FITAGLAGOLITIC SMALL LETTER IZHITSAG" +
"LAGOLITIC SMALL LETTER SHTAPICGLAGOLITIC SMALL LETTER TROKUTASTI AGLAGOL" +
"ITIC SMALL LETTER LATINATE MYSLITEGLAGOLITIC SMALL LETTER CAUDATE CHRIVI" +
"LATIN CAPITAL LETTER L WITH DOUBLE BARLATIN SMALL LETTER L WITH DOUBLE B" +
"ARLATIN CAPITAL LETTER L WITH MIDDLE TILDELATIN CAPITAL LETTER P WITH ST" +
"ROKELATIN CAPITAL LETTER R WITH TAILLATIN SMALL LETTER A WITH STROKELATI" +
"N SMALL LETTER T WITH DIAGONAL STROKELATIN CAPITAL LETTER H WITH DESCEND" +
"ERLATIN SMALL LETTER H WITH DESCENDERLATIN CAPITAL LETTER K WITH DESCEND" +
"ERLATIN SMALL LETTER K WITH DESCENDERLATIN CAPITAL LETTER Z WITH DESCEND" +
"ERLATIN SMALL LETTER Z WITH DESCENDERLATIN CAPITAL LETTER ALPHALATIN CAP" +
"ITAL LETTER M WITH HOOKLATIN CAPITAL LETTER TURNED ALATIN CAPITAL LETTER" +
" TURNED ALPHALATIN SMALL LETTER V WITH RIGHT HOOKLATIN CAPITAL LETTER W " +
"WITH HOOKLATIN SMALL LETTER W WITH HOOKLATIN SMALL LETTER V WITH CURLLAT" +
"IN CAPITAL LETTER HALF HLATIN SMALL LETTER HALF HLATIN SMALL LETTER TAIL" +
"LESS PHILATIN SMALL LETTER E WITH NOTCHLATIN SMALL LETTER TURNED R WITH " +
"TAILLATIN SMALL LETTER O WITH LOW RING INSIDELATIN LETTER SMALL CAPITAL " +
"TURNED ELATIN SUBSCRIPT SMALL LETTER JMODIFIER LETTER CAPITAL VLATIN CAP" +
"ITAL LETTER S WITH SWASH TAILLATIN CAPITAL LETTER Z WITH SWASH TAILCOPTI" +
"C CAPITAL LETTER ALFACOPTIC SMALL LETTER ALFACOPTIC CAPITAL LETTER VIDAC" +
"OPTIC SMALL LETTER VIDACOPTIC CAPITAL LETTER GAMMACOPTIC SMALL LETTER GA" +
"MMACOPTIC CAPITAL LETTER DALDACOPTIC SMALL LETTER DALDACOPTIC CAPITAL LE" +
"TTER EIECOPTIC SMALL LETTER EIECOPTIC CAPITAL LETTER SOUCOPTIC SMALL LET" +
"TER SOUCOPTIC CAPITAL LETTER ZATACOPTIC SMALL LETTER ZATACOPTIC CAPITAL " +
"LETTER HATECOPTIC SMALL LETTER HATECOPTIC CAPITAL LETTER THETHECOPTIC SM" +
"ALL LETTER THETHECOPTIC CAPITAL LETTER IAUDACOPTIC SMALL LETTER IAUDACOP" +
"TIC CAPITAL LETTER KAPACOPTIC SMALL LETTER KAPACOPTIC CAPITAL LETTER LAU" +
"LACOPTIC SMALL LETTER LAULACOPTIC CAPITAL LETTER MICOPTIC SMALL LETTER M" +
"ICOPTIC CAPITAL LETTER NICOPTIC SMALL LETTER NICOPTIC CAPITAL LETTER KSI" +
"COPTIC SMALL LETTER KSICOPTIC CAPITAL LETTER OCOPTIC SMALL LETTER OCOPTI" +
"C CAPITAL LETTER PICOPTIC SMALL LETTER PICOPTIC CAPITAL LETTER ROCOPTIC " +
"SMALL LETTER ROCOPTIC CAPITAL LETTER SIMACOPTIC SMALL LETTER SIMACOPTIC " +
"CAPITAL LETTER TAUCOPTIC SMALL LETTER TAUCOPTIC CAPITAL LETTER UACOPTIC " +
"SMALL LETTER UACOPTIC CAPITAL LETTER FICOPTIC SMALL LETTER FICOPTIC CAPI" +
"TAL LETTER KHICOPTIC SMALL LETTER KHICOPTIC CAPITAL LETTER PSICOPTIC SMA" +
"LL LETTER PSICOPTIC CAPITAL LETTER OOUCOPTIC SMALL LETTER OOUCOPTIC CAPI" +
"TAL LETTER DIALECT-P ALEFCOPTIC SMALL LETTER DIALECT-P ALEFCOPTIC CAPITA" +
"L LETTER OLD COPTIC AINCOPTIC SMALL LETTER OLD COPTIC AINCOPTIC CAPITAL " +
"LETTER CRYPTOGRAMMIC EIECOPTIC SMALL LETTER CRYPTOGRAMMIC EIECOPTIC CAPI" +
"TAL LETTER DIALECT-P KAPACOPTIC SMALL LETTER DIALECT-P KAPACOPTIC CAPITA" +
"L LETTER DIALECT-P NICOPTIC SMALL LETTER DIALECT-P NICOPTIC CAPITAL LETT") + ("" +
"ER CRYPTOGRAMMIC NICOPTIC SMALL LETTER CRYPTOGRAMMIC NICOPTIC CAPITAL LE" +
"TTER OLD COPTIC OOUCOPTIC SMALL LETTER OLD COPTIC OOUCOPTIC CAPITAL LETT" +
"ER SAMPICOPTIC SMALL LETTER SAMPICOPTIC CAPITAL LETTER CROSSED SHEICOPTI" +
"C SMALL LETTER CROSSED SHEICOPTIC CAPITAL LETTER OLD COPTIC SHEICOPTIC S" +
"MALL LETTER OLD COPTIC SHEICOPTIC CAPITAL LETTER OLD COPTIC ESHCOPTIC SM" +
"ALL LETTER OLD COPTIC ESHCOPTIC CAPITAL LETTER AKHMIMIC KHEICOPTIC SMALL" +
" LETTER AKHMIMIC KHEICOPTIC CAPITAL LETTER DIALECT-P HORICOPTIC SMALL LE" +
"TTER DIALECT-P HORICOPTIC CAPITAL LETTER OLD COPTIC HORICOPTIC SMALL LET" +
"TER OLD COPTIC HORICOPTIC CAPITAL LETTER OLD COPTIC HACOPTIC SMALL LETTE" +
"R OLD COPTIC HACOPTIC CAPITAL LETTER L-SHAPED HACOPTIC SMALL LETTER L-SH" +
"APED HACOPTIC CAPITAL LETTER OLD COPTIC HEICOPTIC SMALL LETTER OLD COPTI" +
"C HEICOPTIC CAPITAL LETTER OLD COPTIC HATCOPTIC SMALL LETTER OLD COPTIC " +
"HATCOPTIC CAPITAL LETTER OLD COPTIC GANGIACOPTIC SMALL LETTER OLD COPTIC" +
" GANGIACOPTIC CAPITAL LETTER OLD COPTIC DJACOPTIC SMALL LETTER OLD COPTI" +
"C DJACOPTIC CAPITAL LETTER OLD COPTIC SHIMACOPTIC SMALL LETTER OLD COPTI" +
"C SHIMACOPTIC CAPITAL LETTER OLD NUBIAN SHIMACOPTIC SMALL LETTER OLD NUB" +
"IAN SHIMACOPTIC CAPITAL LETTER OLD NUBIAN NGICOPTIC SMALL LETTER OLD NUB" +
"IAN NGICOPTIC CAPITAL LETTER OLD NUBIAN NYICOPTIC SMALL LETTER OLD NUBIA" +
"N NYICOPTIC CAPITAL LETTER OLD NUBIAN WAUCOPTIC SMALL LETTER OLD NUBIAN " +
"WAUCOPTIC SYMBOL KAICOPTIC SYMBOL MI ROCOPTIC SYMBOL PI ROCOPTIC SYMBOL " +
"STAUROSCOPTIC SYMBOL TAU ROCOPTIC SYMBOL KHI ROCOPTIC SYMBOL SHIMA SIMAC" +
"OPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEICOPTIC SMALL LETTER CRYPTOGRAMMIC" +
" SHEICOPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIACOPTIC SMALL LETTER CRYPT" +
"OGRAMMIC GANGIACOPTIC COMBINING NI ABOVECOPTIC COMBINING SPIRITUS ASPERC" +
"OPTIC COMBINING SPIRITUS LENISCOPTIC CAPITAL LETTER BOHAIRIC KHEICOPTIC " +
"SMALL LETTER BOHAIRIC KHEICOPTIC OLD NUBIAN FULL STOPCOPTIC OLD NUBIAN D" +
"IRECT QUESTION MARKCOPTIC OLD NUBIAN INDIRECT QUESTION MARKCOPTIC OLD NU" +
"BIAN VERSE DIVIDERCOPTIC FRACTION ONE HALFCOPTIC FULL STOPCOPTIC MORPHOL" +
"OGICAL DIVIDERGEORGIAN SMALL LETTER ANGEORGIAN SMALL LETTER BANGEORGIAN " +
"SMALL LETTER GANGEORGIAN SMALL LETTER DONGEORGIAN SMALL LETTER ENGEORGIA" +
"N SMALL LETTER VINGEORGIAN SMALL LETTER ZENGEORGIAN SMALL LETTER TANGEOR" +
"GIAN SMALL LETTER INGEORGIAN SMALL LETTER KANGEORGIAN SMALL LETTER LASGE" +
"ORGIAN SMALL LETTER MANGEORGIAN SMALL LETTER NARGEORGIAN SMALL LETTER ON" +
"GEORGIAN SMALL LETTER PARGEORGIAN SMALL LETTER ZHARGEORGIAN SMALL LETTER" +
" RAEGEORGIAN SMALL LETTER SANGEORGIAN SMALL LETTER TARGEORGIAN SMALL LET" +
"TER UNGEORGIAN SMALL LETTER PHARGEORGIAN SMALL LETTER KHARGEORGIAN SMALL" +
" LETTER GHANGEORGIAN SMALL LETTER QARGEORGIAN SMALL LETTER SHINGEORGIAN " +
"SMALL LETTER CHINGEORGIAN SMALL LETTER CANGEORGIAN SMALL LETTER JILGEORG" +
"IAN SMALL LETTER CILGEORGIAN SMALL LETTER CHARGEORGIAN SMALL LETTER XANG" +
"EORGIAN SMALL LETTER JHANGEORGIAN SMALL LETTER HAEGEORGIAN SMALL LETTER " +
"HEGEORGIAN SMALL LETTER HIEGEORGIAN SMALL LETTER WEGEORGIAN SMALL LETTER" +
" HARGEORGIAN SMALL LETTER HOEGEORGIAN SMALL LETTER YNGEORGIAN SMALL LETT" +
"ER AENTIFINAGH LETTER YATIFINAGH LETTER YABTIFINAGH LETTER YABHTIFINAGH " +
"LETTER YAGTIFINAGH LETTER YAGHHTIFINAGH LETTER BERBER ACADEMY YAJTIFINAG" +
"H LETTER YAJTIFINAGH LETTER YADTIFINAGH LETTER YADHTIFINAGH LETTER YADDT" +
"IFINAGH LETTER YADDHTIFINAGH LETTER YEYTIFINAGH LETTER YAFTIFINAGH LETTE" +
"R YAKTIFINAGH LETTER TUAREG YAKTIFINAGH LETTER YAKHHTIFINAGH LETTER YAHT" +
"IFINAGH LETTER BERBER ACADEMY YAHTIFINAGH LETTER TUAREG YAHTIFINAGH LETT" +
"ER YAHHTIFINAGH LETTER YAATIFINAGH LETTER YAKHTIFINAGH LETTER TUAREG YAK" +
"HTIFINAGH LETTER YAQTIFINAGH LETTER TUAREG YAQTIFINAGH LETTER YITIFINAGH" +
" LETTER YAZHTIFINAGH LETTER AHAGGAR YAZHTIFINAGH LETTER TUAREG YAZHTIFIN" +
"AGH LETTER YALTIFINAGH LETTER YAMTIFINAGH LETTER YANTIFINAGH LETTER TUAR" +
"EG YAGNTIFINAGH LETTER TUAREG YANGTIFINAGH LETTER YAPTIFINAGH LETTER YUT" +
"IFINAGH LETTER YARTIFINAGH LETTER YARRTIFINAGH LETTER YAGHTIFINAGH LETTE" +
"R TUAREG YAGHTIFINAGH LETTER AYER YAGHTIFINAGH LETTER YASTIFINAGH LETTER" +
" YASSTIFINAGH LETTER YASHTIFINAGH LETTER YATTIFINAGH LETTER YATHTIFINAGH" +
" LETTER YACHTIFINAGH LETTER YATTTIFINAGH LETTER YAVTIFINAGH LETTER YAWTI" +
"FINAGH LETTER YAYTIFINAGH LETTER YAZTIFINAGH LETTER TAWELLEMET YAZTIFINA" +
"GH LETTER YAZZTIFINAGH LETTER YETIFINAGH LETTER YOTIFINAGH MODIFIER LETT" +
"ER LABIALIZATION MARKTIFINAGH SEPARATOR MARKTIFINAGH CONSONANT JOINERETH" +
"IOPIC SYLLABLE LOAETHIOPIC SYLLABLE MOAETHIOPIC SYLLABLE ROAETHIOPIC SYL" +
"LABLE SOAETHIOPIC SYLLABLE SHOAETHIOPIC SYLLABLE BOAETHIOPIC SYLLABLE TO" +
"AETHIOPIC SYLLABLE COAETHIOPIC SYLLABLE NOAETHIOPIC SYLLABLE NYOAETHIOPI" +
"C SYLLABLE GLOTTAL OAETHIOPIC SYLLABLE ZOAETHIOPIC SYLLABLE DOAETHIOPIC ") + ("" +
"SYLLABLE DDOAETHIOPIC SYLLABLE JOAETHIOPIC SYLLABLE THOAETHIOPIC SYLLABL" +
"E CHOAETHIOPIC SYLLABLE PHOAETHIOPIC SYLLABLE POAETHIOPIC SYLLABLE GGWAE" +
"THIOPIC SYLLABLE GGWIETHIOPIC SYLLABLE GGWEEETHIOPIC SYLLABLE GGWEETHIOP" +
"IC SYLLABLE SSAETHIOPIC SYLLABLE SSUETHIOPIC SYLLABLE SSIETHIOPIC SYLLAB" +
"LE SSAAETHIOPIC SYLLABLE SSEEETHIOPIC SYLLABLE SSEETHIOPIC SYLLABLE SSOE" +
"THIOPIC SYLLABLE CCAETHIOPIC SYLLABLE CCUETHIOPIC SYLLABLE CCIETHIOPIC S" +
"YLLABLE CCAAETHIOPIC SYLLABLE CCEEETHIOPIC SYLLABLE CCEETHIOPIC SYLLABLE" +
" CCOETHIOPIC SYLLABLE ZZAETHIOPIC SYLLABLE ZZUETHIOPIC SYLLABLE ZZIETHIO" +
"PIC SYLLABLE ZZAAETHIOPIC SYLLABLE ZZEEETHIOPIC SYLLABLE ZZEETHIOPIC SYL" +
"LABLE ZZOETHIOPIC SYLLABLE CCHAETHIOPIC SYLLABLE CCHUETHIOPIC SYLLABLE C" +
"CHIETHIOPIC SYLLABLE CCHAAETHIOPIC SYLLABLE CCHEEETHIOPIC SYLLABLE CCHEE" +
"THIOPIC SYLLABLE CCHOETHIOPIC SYLLABLE QYAETHIOPIC SYLLABLE QYUETHIOPIC " +
"SYLLABLE QYIETHIOPIC SYLLABLE QYAAETHIOPIC SYLLABLE QYEEETHIOPIC SYLLABL" +
"E QYEETHIOPIC SYLLABLE QYOETHIOPIC SYLLABLE KYAETHIOPIC SYLLABLE KYUETHI" +
"OPIC SYLLABLE KYIETHIOPIC SYLLABLE KYAAETHIOPIC SYLLABLE KYEEETHIOPIC SY" +
"LLABLE KYEETHIOPIC SYLLABLE KYOETHIOPIC SYLLABLE XYAETHIOPIC SYLLABLE XY" +
"UETHIOPIC SYLLABLE XYIETHIOPIC SYLLABLE XYAAETHIOPIC SYLLABLE XYEEETHIOP" +
"IC SYLLABLE XYEETHIOPIC SYLLABLE XYOETHIOPIC SYLLABLE GYAETHIOPIC SYLLAB" +
"LE GYUETHIOPIC SYLLABLE GYIETHIOPIC SYLLABLE GYAAETHIOPIC SYLLABLE GYEEE" +
"THIOPIC SYLLABLE GYEETHIOPIC SYLLABLE GYOCOMBINING CYRILLIC LETTER BECOM" +
"BINING CYRILLIC LETTER VECOMBINING CYRILLIC LETTER GHECOMBINING CYRILLIC" +
" LETTER DECOMBINING CYRILLIC LETTER ZHECOMBINING CYRILLIC LETTER ZECOMBI" +
"NING CYRILLIC LETTER KACOMBINING CYRILLIC LETTER ELCOMBINING CYRILLIC LE" +
"TTER EMCOMBINING CYRILLIC LETTER ENCOMBINING CYRILLIC LETTER OCOMBINING " +
"CYRILLIC LETTER PECOMBINING CYRILLIC LETTER ERCOMBINING CYRILLIC LETTER " +
"ESCOMBINING CYRILLIC LETTER TECOMBINING CYRILLIC LETTER HACOMBINING CYRI" +
"LLIC LETTER TSECOMBINING CYRILLIC LETTER CHECOMBINING CYRILLIC LETTER SH" +
"ACOMBINING CYRILLIC LETTER SHCHACOMBINING CYRILLIC LETTER FITACOMBINING " +
"CYRILLIC LETTER ES-TECOMBINING CYRILLIC LETTER ACOMBINING CYRILLIC LETTE" +
"R IECOMBINING CYRILLIC LETTER DJERVCOMBINING CYRILLIC LETTER MONOGRAPH U" +
"KCOMBINING CYRILLIC LETTER YATCOMBINING CYRILLIC LETTER YUCOMBINING CYRI" +
"LLIC LETTER IOTIFIED ACOMBINING CYRILLIC LETTER LITTLE YUSCOMBINING CYRI" +
"LLIC LETTER BIG YUSCOMBINING CYRILLIC LETTER IOTIFIED BIG YUSRIGHT ANGLE" +
" SUBSTITUTION MARKERRIGHT ANGLE DOTTED SUBSTITUTION MARKERLEFT SUBSTITUT" +
"ION BRACKETRIGHT SUBSTITUTION BRACKETLEFT DOTTED SUBSTITUTION BRACKETRIG" +
"HT DOTTED SUBSTITUTION BRACKETRAISED INTERPOLATION MARKERRAISED DOTTED I" +
"NTERPOLATION MARKERDOTTED TRANSPOSITION MARKERLEFT TRANSPOSITION BRACKET" +
"RIGHT TRANSPOSITION BRACKETRAISED SQUARELEFT RAISED OMISSION BRACKETRIGH" +
"T RAISED OMISSION BRACKETEDITORIAL CORONISPARAGRAPHOSFORKED PARAGRAPHOSR" +
"EVERSED FORKED PARAGRAPHOSHYPODIASTOLEDOTTED OBELOSDOWNWARDS ANCORAUPWAR" +
"DS ANCORADOTTED RIGHT-POINTING ANGLEDOUBLE OBLIQUE HYPHENINVERTED INTERR" +
"OBANGPALM BRANCHHYPHEN WITH DIAERESISTILDE WITH RING ABOVELEFT LOW PARAP" +
"HRASE BRACKETRIGHT LOW PARAPHRASE BRACKETTILDE WITH DOT ABOVETILDE WITH " +
"DOT BELOWLEFT VERTICAL BAR WITH QUILLRIGHT VERTICAL BAR WITH QUILLTOP LE" +
"FT HALF BRACKETTOP RIGHT HALF BRACKETBOTTOM LEFT HALF BRACKETBOTTOM RIGH" +
"T HALF BRACKETLEFT SIDEWAYS U BRACKETRIGHT SIDEWAYS U BRACKETLEFT DOUBLE" +
" PARENTHESISRIGHT DOUBLE PARENTHESISTWO DOTS OVER ONE DOT PUNCTUATIONONE" +
" DOT OVER TWO DOTS PUNCTUATIONSQUARED FOUR DOT PUNCTUATIONFIVE DOT MARKR" +
"EVERSED QUESTION MARKVERTICAL TILDERING POINTWORD SEPARATOR MIDDLE DOTTU" +
"RNED COMMARAISED DOTRAISED COMMATURNED SEMICOLONDAGGER WITH LEFT GUARDDA" +
"GGER WITH RIGHT GUARDTURNED DAGGERTOP HALF SECTION SIGNTWO-EM DASHTHREE-" +
"EM DASHSTENOGRAPHIC FULL STOPVERTICAL SIX DOTSWIGGLY VERTICAL LINECAPITU" +
"LUMDOUBLE HYPHENREVERSED COMMADOUBLE LOW-REVERSED-9 QUOTATION MARKDASH W" +
"ITH LEFT UPTURNDOUBLE SUSPENSION MARKINVERTED LOW KAVYKAINVERTED LOW KAV" +
"YKA WITH KAVYKA ABOVELOW KAVYKALOW KAVYKA WITH DOTDOUBLE STACKED COMMADO" +
"TTED SOLIDUSTRIPLE DAGGERMEDIEVAL COMMAPARAGRAPHUS MARKPUNCTUS ELEVATUS " +
"MARKCORNISH VERSE DIVIDERCROSS PATTY WITH RIGHT CROSSBARCROSS PATTY WITH" +
" LEFT CROSSBARTIRONIAN SIGN CAPITAL ETMEDIEVAL EXCLAMATION MARKMEDIEVAL " +
"QUESTION MARKLEFT SQUARE BRACKET WITH STROKERIGHT SQUARE BRACKET WITH ST" +
"ROKELEFT SQUARE BRACKET WITH DOUBLE STROKERIGHT SQUARE BRACKET WITH DOUB" +
"LE STROKETOP HALF LEFT PARENTHESISTOP HALF RIGHT PARENTHESISBOTTOM HALF " +
"LEFT PARENTHESISBOTTOM HALF RIGHT PARENTHESISOBLIQUE HYPHENCJK RADICAL R" +
"EPEATCJK RADICAL CLIFFCJK RADICAL SECOND ONECJK RADICAL SECOND TWOCJK RA" +
"DICAL SECOND THREECJK RADICAL PERSONCJK RADICAL BOXCJK RADICAL TABLECJK ") + ("" +
"RADICAL KNIFE ONECJK RADICAL KNIFE TWOCJK RADICAL DIVINATIONCJK RADICAL " +
"SEALCJK RADICAL SMALL ONECJK RADICAL SMALL TWOCJK RADICAL LAME ONECJK RA" +
"DICAL LAME TWOCJK RADICAL LAME THREECJK RADICAL LAME FOURCJK RADICAL SNA" +
"KECJK RADICAL THREADCJK RADICAL SNOUT ONECJK RADICAL SNOUT TWOCJK RADICA" +
"L HEART ONECJK RADICAL HEART TWOCJK RADICAL HANDCJK RADICAL RAPCJK RADIC" +
"AL CHOKECJK RADICAL SUNCJK RADICAL MOONCJK RADICAL DEATHCJK RADICAL MOTH" +
"ERCJK RADICAL CIVILIANCJK RADICAL WATER ONECJK RADICAL WATER TWOCJK RADI" +
"CAL FIRECJK RADICAL PAW ONECJK RADICAL PAW TWOCJK RADICAL SIMPLIFIED HAL" +
"F TREE TRUNKCJK RADICAL COWCJK RADICAL DOGCJK RADICAL JADECJK RADICAL BO" +
"LT OF CLOTHCJK RADICAL EYECJK RADICAL SPIRIT ONECJK RADICAL SPIRIT TWOCJ" +
"K RADICAL BAMBOOCJK RADICAL SILKCJK RADICAL C-SIMPLIFIED SILKCJK RADICAL" +
" NET ONECJK RADICAL NET TWOCJK RADICAL NET THREECJK RADICAL NET FOURCJK " +
"RADICAL MESHCJK RADICAL SHEEPCJK RADICAL RAMCJK RADICAL EWECJK RADICAL O" +
"LDCJK RADICAL BRUSH ONECJK RADICAL BRUSH TWOCJK RADICAL MEATCJK RADICAL " +
"MORTARCJK RADICAL GRASS ONECJK RADICAL GRASS TWOCJK RADICAL GRASS THREEC" +
"JK RADICAL TIGERCJK RADICAL CLOTHESCJK RADICAL WEST ONECJK RADICAL WEST " +
"TWOCJK RADICAL C-SIMPLIFIED SEECJK RADICAL SIMPLIFIED HORNCJK RADICAL HO" +
"RNCJK RADICAL C-SIMPLIFIED SPEECHCJK RADICAL C-SIMPLIFIED SHELLCJK RADIC" +
"AL FOOTCJK RADICAL C-SIMPLIFIED CARTCJK RADICAL SIMPLIFIED WALKCJK RADIC" +
"AL WALK ONECJK RADICAL WALK TWOCJK RADICAL CITYCJK RADICAL C-SIMPLIFIED " +
"GOLDCJK RADICAL LONG ONECJK RADICAL LONG TWOCJK RADICAL C-SIMPLIFIED LON" +
"GCJK RADICAL C-SIMPLIFIED GATECJK RADICAL MOUND ONECJK RADICAL MOUND TWO" +
"CJK RADICAL RAINCJK RADICAL BLUECJK RADICAL C-SIMPLIFIED TANNED LEATHERC" +
"JK RADICAL C-SIMPLIFIED LEAFCJK RADICAL C-SIMPLIFIED WINDCJK RADICAL C-S" +
"IMPLIFIED FLYCJK RADICAL EAT ONECJK RADICAL EAT TWOCJK RADICAL EAT THREE" +
"CJK RADICAL C-SIMPLIFIED EATCJK RADICAL HEADCJK RADICAL C-SIMPLIFIED HOR" +
"SECJK RADICAL BONECJK RADICAL GHOSTCJK RADICAL C-SIMPLIFIED FISHCJK RADI" +
"CAL C-SIMPLIFIED BIRDCJK RADICAL C-SIMPLIFIED SALTCJK RADICAL SIMPLIFIED" +
" WHEATCJK RADICAL SIMPLIFIED YELLOWCJK RADICAL C-SIMPLIFIED FROGCJK RADI" +
"CAL J-SIMPLIFIED EVENCJK RADICAL C-SIMPLIFIED EVENCJK RADICAL J-SIMPLIFI" +
"ED TOOTHCJK RADICAL C-SIMPLIFIED TOOTHCJK RADICAL J-SIMPLIFIED DRAGONCJK" +
" RADICAL C-SIMPLIFIED DRAGONCJK RADICAL TURTLECJK RADICAL J-SIMPLIFIED T" +
"URTLECJK RADICAL C-SIMPLIFIED TURTLEKANGXI RADICAL ONEKANGXI RADICAL LIN" +
"EKANGXI RADICAL DOTKANGXI RADICAL SLASHKANGXI RADICAL SECONDKANGXI RADIC" +
"AL HOOKKANGXI RADICAL TWOKANGXI RADICAL LIDKANGXI RADICAL MANKANGXI RADI" +
"CAL LEGSKANGXI RADICAL ENTERKANGXI RADICAL EIGHTKANGXI RADICAL DOWN BOXK" +
"ANGXI RADICAL COVERKANGXI RADICAL ICEKANGXI RADICAL TABLEKANGXI RADICAL " +
"OPEN BOXKANGXI RADICAL KNIFEKANGXI RADICAL POWERKANGXI RADICAL WRAPKANGX" +
"I RADICAL SPOONKANGXI RADICAL RIGHT OPEN BOXKANGXI RADICAL HIDING ENCLOS" +
"UREKANGXI RADICAL TENKANGXI RADICAL DIVINATIONKANGXI RADICAL SEALKANGXI " +
"RADICAL CLIFFKANGXI RADICAL PRIVATEKANGXI RADICAL AGAINKANGXI RADICAL MO" +
"UTHKANGXI RADICAL ENCLOSUREKANGXI RADICAL EARTHKANGXI RADICAL SCHOLARKAN" +
"GXI RADICAL GOKANGXI RADICAL GO SLOWLYKANGXI RADICAL EVENINGKANGXI RADIC" +
"AL BIGKANGXI RADICAL WOMANKANGXI RADICAL CHILDKANGXI RADICAL ROOFKANGXI " +
"RADICAL INCHKANGXI RADICAL SMALLKANGXI RADICAL LAMEKANGXI RADICAL CORPSE" +
"KANGXI RADICAL SPROUTKANGXI RADICAL MOUNTAINKANGXI RADICAL RIVERKANGXI R" +
"ADICAL WORKKANGXI RADICAL ONESELFKANGXI RADICAL TURBANKANGXI RADICAL DRY" +
"KANGXI RADICAL SHORT THREADKANGXI RADICAL DOTTED CLIFFKANGXI RADICAL LON" +
"G STRIDEKANGXI RADICAL TWO HANDSKANGXI RADICAL SHOOTKANGXI RADICAL BOWKA" +
"NGXI RADICAL SNOUTKANGXI RADICAL BRISTLEKANGXI RADICAL STEPKANGXI RADICA" +
"L HEARTKANGXI RADICAL HALBERDKANGXI RADICAL DOORKANGXI RADICAL HANDKANGX" +
"I RADICAL BRANCHKANGXI RADICAL RAPKANGXI RADICAL SCRIPTKANGXI RADICAL DI" +
"PPERKANGXI RADICAL AXEKANGXI RADICAL SQUAREKANGXI RADICAL NOTKANGXI RADI" +
"CAL SUNKANGXI RADICAL SAYKANGXI RADICAL MOONKANGXI RADICAL TREEKANGXI RA" +
"DICAL LACKKANGXI RADICAL STOPKANGXI RADICAL DEATHKANGXI RADICAL WEAPONKA" +
"NGXI RADICAL DO NOTKANGXI RADICAL COMPAREKANGXI RADICAL FURKANGXI RADICA" +
"L CLANKANGXI RADICAL STEAMKANGXI RADICAL WATERKANGXI RADICAL FIREKANGXI " +
"RADICAL CLAWKANGXI RADICAL FATHERKANGXI RADICAL DOUBLE XKANGXI RADICAL H" +
"ALF TREE TRUNKKANGXI RADICAL SLICEKANGXI RADICAL FANGKANGXI RADICAL COWK" +
"ANGXI RADICAL DOGKANGXI RADICAL PROFOUNDKANGXI RADICAL JADEKANGXI RADICA" +
"L MELONKANGXI RADICAL TILEKANGXI RADICAL SWEETKANGXI RADICAL LIFEKANGXI " +
"RADICAL USEKANGXI RADICAL FIELDKANGXI RADICAL BOLT OF CLOTHKANGXI RADICA" +
"L SICKNESSKANGXI RADICAL DOTTED TENTKANGXI RADICAL WHITEKANGXI RADICAL S" +
"KINKANGXI RADICAL DISHKANGXI RADICAL EYEKANGXI RADICAL SPEARKANGXI RADIC") + ("" +
"AL ARROWKANGXI RADICAL STONEKANGXI RADICAL SPIRITKANGXI RADICAL TRACKKAN" +
"GXI RADICAL GRAINKANGXI RADICAL CAVEKANGXI RADICAL STANDKANGXI RADICAL B" +
"AMBOOKANGXI RADICAL RICEKANGXI RADICAL SILKKANGXI RADICAL JARKANGXI RADI" +
"CAL NETKANGXI RADICAL SHEEPKANGXI RADICAL FEATHERKANGXI RADICAL OLDKANGX" +
"I RADICAL ANDKANGXI RADICAL PLOWKANGXI RADICAL EARKANGXI RADICAL BRUSHKA" +
"NGXI RADICAL MEATKANGXI RADICAL MINISTERKANGXI RADICAL SELFKANGXI RADICA" +
"L ARRIVEKANGXI RADICAL MORTARKANGXI RADICAL TONGUEKANGXI RADICAL OPPOSEK" +
"ANGXI RADICAL BOATKANGXI RADICAL STOPPINGKANGXI RADICAL COLORKANGXI RADI" +
"CAL GRASSKANGXI RADICAL TIGERKANGXI RADICAL INSECTKANGXI RADICAL BLOODKA" +
"NGXI RADICAL WALK ENCLOSUREKANGXI RADICAL CLOTHESKANGXI RADICAL WESTKANG" +
"XI RADICAL SEEKANGXI RADICAL HORNKANGXI RADICAL SPEECHKANGXI RADICAL VAL" +
"LEYKANGXI RADICAL BEANKANGXI RADICAL PIGKANGXI RADICAL BADGERKANGXI RADI" +
"CAL SHELLKANGXI RADICAL REDKANGXI RADICAL RUNKANGXI RADICAL FOOTKANGXI R" +
"ADICAL BODYKANGXI RADICAL CARTKANGXI RADICAL BITTERKANGXI RADICAL MORNIN" +
"GKANGXI RADICAL WALKKANGXI RADICAL CITYKANGXI RADICAL WINEKANGXI RADICAL" +
" DISTINGUISHKANGXI RADICAL VILLAGEKANGXI RADICAL GOLDKANGXI RADICAL LONG" +
"KANGXI RADICAL GATEKANGXI RADICAL MOUNDKANGXI RADICAL SLAVEKANGXI RADICA" +
"L SHORT TAILED BIRDKANGXI RADICAL RAINKANGXI RADICAL BLUEKANGXI RADICAL " +
"WRONGKANGXI RADICAL FACEKANGXI RADICAL LEATHERKANGXI RADICAL TANNED LEAT" +
"HERKANGXI RADICAL LEEKKANGXI RADICAL SOUNDKANGXI RADICAL LEAFKANGXI RADI" +
"CAL WINDKANGXI RADICAL FLYKANGXI RADICAL EATKANGXI RADICAL HEADKANGXI RA" +
"DICAL FRAGRANTKANGXI RADICAL HORSEKANGXI RADICAL BONEKANGXI RADICAL TALL" +
"KANGXI RADICAL HAIRKANGXI RADICAL FIGHTKANGXI RADICAL SACRIFICIAL WINEKA" +
"NGXI RADICAL CAULDRONKANGXI RADICAL GHOSTKANGXI RADICAL FISHKANGXI RADIC" +
"AL BIRDKANGXI RADICAL SALTKANGXI RADICAL DEERKANGXI RADICAL WHEATKANGXI " +
"RADICAL HEMPKANGXI RADICAL YELLOWKANGXI RADICAL MILLETKANGXI RADICAL BLA" +
"CKKANGXI RADICAL EMBROIDERYKANGXI RADICAL FROGKANGXI RADICAL TRIPODKANGX" +
"I RADICAL DRUMKANGXI RADICAL RATKANGXI RADICAL NOSEKANGXI RADICAL EVENKA" +
"NGXI RADICAL TOOTHKANGXI RADICAL DRAGONKANGXI RADICAL TURTLEKANGXI RADIC" +
"AL FLUTEIDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHTIDEOGRAPHIC DESCR" +
"IPTION CHARACTER ABOVE TO BELOWIDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO" +
" MIDDLE AND RIGHTIDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND B" +
"ELOWIDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUNDIDEOGRAPHIC DESCRIPTI" +
"ON CHARACTER SURROUND FROM ABOVEIDEOGRAPHIC DESCRIPTION CHARACTER SURROU" +
"ND FROM BELOWIDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFTIDEOGRA" +
"PHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFTIDEOGRAPHIC DESCRIPTI" +
"ON CHARACTER SURROUND FROM UPPER RIGHTIDEOGRAPHIC DESCRIPTION CHARACTER " +
"SURROUND FROM LOWER LEFTIDEOGRAPHIC DESCRIPTION CHARACTER OVERLAIDIDEOGR" +
"APHIC DESCRIPTION CHARACTER SURROUND FROM RIGHTIDEOGRAPHIC DESCRIPTION C" +
"HARACTER SURROUND FROM LOWER RIGHTIDEOGRAPHIC DESCRIPTION CHARACTER HORI" +
"ZONTAL REFLECTIONIDEOGRAPHIC DESCRIPTION CHARACTER ROTATIONIDEOGRAPHIC S" +
"PACEIDEOGRAPHIC COMMAIDEOGRAPHIC FULL STOPDITTO MARKJAPANESE INDUSTRIAL " +
"STANDARD SYMBOLIDEOGRAPHIC ITERATION MARKIDEOGRAPHIC CLOSING MARKIDEOGRA" +
"PHIC NUMBER ZEROLEFT ANGLE BRACKETRIGHT ANGLE BRACKETLEFT DOUBLE ANGLE B" +
"RACKETRIGHT DOUBLE ANGLE BRACKETLEFT CORNER BRACKETRIGHT CORNER BRACKETL" +
"EFT WHITE CORNER BRACKETRIGHT WHITE CORNER BRACKETLEFT BLACK LENTICULAR " +
"BRACKETRIGHT BLACK LENTICULAR BRACKETPOSTAL MARKGETA MARKLEFT TORTOISE S" +
"HELL BRACKETRIGHT TORTOISE SHELL BRACKETLEFT WHITE LENTICULAR BRACKETRIG" +
"HT WHITE LENTICULAR BRACKETLEFT WHITE TORTOISE SHELL BRACKETRIGHT WHITE " +
"TORTOISE SHELL BRACKETLEFT WHITE SQUARE BRACKETRIGHT WHITE SQUARE BRACKE" +
"TWAVE DASHREVERSED DOUBLE PRIME QUOTATION MARKDOUBLE PRIME QUOTATION MAR" +
"KLOW DOUBLE PRIME QUOTATION MARKPOSTAL MARK FACEHANGZHOU NUMERAL ONEHANG" +
"ZHOU NUMERAL TWOHANGZHOU NUMERAL THREEHANGZHOU NUMERAL FOURHANGZHOU NUME" +
"RAL FIVEHANGZHOU NUMERAL SIXHANGZHOU NUMERAL SEVENHANGZHOU NUMERAL EIGHT" +
"HANGZHOU NUMERAL NINEIDEOGRAPHIC LEVEL TONE MARKIDEOGRAPHIC RISING TONE " +
"MARKIDEOGRAPHIC DEPARTING TONE MARKIDEOGRAPHIC ENTERING TONE MARKHANGUL " +
"SINGLE DOT TONE MARKHANGUL DOUBLE DOT TONE MARKWAVY DASHVERTICAL KANA RE" +
"PEAT MARKVERTICAL KANA REPEAT WITH VOICED SOUND MARKVERTICAL KANA REPEAT" +
" MARK UPPER HALFVERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALFVE" +
"RTICAL KANA REPEAT MARK LOWER HALFCIRCLED POSTAL MARKIDEOGRAPHIC TELEGRA" +
"PH LINE FEED SEPARATOR SYMBOLHANGZHOU NUMERAL TENHANGZHOU NUMERAL TWENTY" +
"HANGZHOU NUMERAL THIRTYVERTICAL IDEOGRAPHIC ITERATION MARKMASU MARKPART " +
"ALTERNATION MARKIDEOGRAPHIC VARIATION INDICATORIDEOGRAPHIC HALF FILL SPA" +
"CEHIRAGANA LETTER SMALL AHIRAGANA LETTER AHIRAGANA LETTER SMALL IHIRAGAN") + ("" +
"A LETTER IHIRAGANA LETTER SMALL UHIRAGANA LETTER UHIRAGANA LETTER SMALL " +
"EHIRAGANA LETTER EHIRAGANA LETTER SMALL OHIRAGANA LETTER OHIRAGANA LETTE" +
"R KAHIRAGANA LETTER GAHIRAGANA LETTER KIHIRAGANA LETTER GIHIRAGANA LETTE" +
"R KUHIRAGANA LETTER GUHIRAGANA LETTER KEHIRAGANA LETTER GEHIRAGANA LETTE" +
"R KOHIRAGANA LETTER GOHIRAGANA LETTER SAHIRAGANA LETTER ZAHIRAGANA LETTE" +
"R SIHIRAGANA LETTER ZIHIRAGANA LETTER SUHIRAGANA LETTER ZUHIRAGANA LETTE" +
"R SEHIRAGANA LETTER ZEHIRAGANA LETTER SOHIRAGANA LETTER ZOHIRAGANA LETTE" +
"R TAHIRAGANA LETTER DAHIRAGANA LETTER TIHIRAGANA LETTER DIHIRAGANA LETTE" +
"R SMALL TUHIRAGANA LETTER TUHIRAGANA LETTER DUHIRAGANA LETTER TEHIRAGANA" +
" LETTER DEHIRAGANA LETTER TOHIRAGANA LETTER DOHIRAGANA LETTER NAHIRAGANA" +
" LETTER NIHIRAGANA LETTER NUHIRAGANA LETTER NEHIRAGANA LETTER NOHIRAGANA" +
" LETTER HAHIRAGANA LETTER BAHIRAGANA LETTER PAHIRAGANA LETTER HIHIRAGANA" +
" LETTER BIHIRAGANA LETTER PIHIRAGANA LETTER HUHIRAGANA LETTER BUHIRAGANA" +
" LETTER PUHIRAGANA LETTER HEHIRAGANA LETTER BEHIRAGANA LETTER PEHIRAGANA" +
" LETTER HOHIRAGANA LETTER BOHIRAGANA LETTER POHIRAGANA LETTER MAHIRAGANA" +
" LETTER MIHIRAGANA LETTER MUHIRAGANA LETTER MEHIRAGANA LETTER MOHIRAGANA" +
" LETTER SMALL YAHIRAGANA LETTER YAHIRAGANA LETTER SMALL YUHIRAGANA LETTE" +
"R YUHIRAGANA LETTER SMALL YOHIRAGANA LETTER YOHIRAGANA LETTER RAHIRAGANA" +
" LETTER RIHIRAGANA LETTER RUHIRAGANA LETTER REHIRAGANA LETTER ROHIRAGANA" +
" LETTER SMALL WAHIRAGANA LETTER WAHIRAGANA LETTER WIHIRAGANA LETTER WEHI" +
"RAGANA LETTER WOHIRAGANA LETTER NHIRAGANA LETTER VUHIRAGANA LETTER SMALL" +
" KAHIRAGANA LETTER SMALL KECOMBINING KATAKANA-HIRAGANA VOICED SOUND MARK" +
"COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARKKATAKANA-HIRAGANA VOIC" +
"ED SOUND MARKKATAKANA-HIRAGANA SEMI-VOICED SOUND MARKHIRAGANA ITERATION " +
"MARKHIRAGANA VOICED ITERATION MARKHIRAGANA DIGRAPH YORIKATAKANA-HIRAGANA" +
" DOUBLE HYPHENKATAKANA LETTER SMALL AKATAKANA LETTER AKATAKANA LETTER SM" +
"ALL IKATAKANA LETTER IKATAKANA LETTER SMALL UKATAKANA LETTER UKATAKANA L" +
"ETTER SMALL EKATAKANA LETTER EKATAKANA LETTER SMALL OKATAKANA LETTER OKA" +
"TAKANA LETTER KAKATAKANA LETTER GAKATAKANA LETTER KIKATAKANA LETTER GIKA" +
"TAKANA LETTER KUKATAKANA LETTER GUKATAKANA LETTER KEKATAKANA LETTER GEKA" +
"TAKANA LETTER KOKATAKANA LETTER GOKATAKANA LETTER SAKATAKANA LETTER ZAKA" +
"TAKANA LETTER SIKATAKANA LETTER ZIKATAKANA LETTER SUKATAKANA LETTER ZUKA" +
"TAKANA LETTER SEKATAKANA LETTER ZEKATAKANA LETTER SOKATAKANA LETTER ZOKA" +
"TAKANA LETTER TAKATAKANA LETTER DAKATAKANA LETTER TIKATAKANA LETTER DIKA" +
"TAKANA LETTER SMALL TUKATAKANA LETTER TUKATAKANA LETTER DUKATAKANA LETTE" +
"R TEKATAKANA LETTER DEKATAKANA LETTER TOKATAKANA LETTER DOKATAKANA LETTE" +
"R NAKATAKANA LETTER NIKATAKANA LETTER NUKATAKANA LETTER NEKATAKANA LETTE" +
"R NOKATAKANA LETTER HAKATAKANA LETTER BAKATAKANA LETTER PAKATAKANA LETTE" +
"R HIKATAKANA LETTER BIKATAKANA LETTER PIKATAKANA LETTER HUKATAKANA LETTE" +
"R BUKATAKANA LETTER PUKATAKANA LETTER HEKATAKANA LETTER BEKATAKANA LETTE" +
"R PEKATAKANA LETTER HOKATAKANA LETTER BOKATAKANA LETTER POKATAKANA LETTE" +
"R MAKATAKANA LETTER MIKATAKANA LETTER MUKATAKANA LETTER MEKATAKANA LETTE" +
"R MOKATAKANA LETTER SMALL YAKATAKANA LETTER YAKATAKANA LETTER SMALL YUKA" +
"TAKANA LETTER YUKATAKANA LETTER SMALL YOKATAKANA LETTER YOKATAKANA LETTE" +
"R RAKATAKANA LETTER RIKATAKANA LETTER RUKATAKANA LETTER REKATAKANA LETTE" +
"R ROKATAKANA LETTER SMALL WAKATAKANA LETTER WAKATAKANA LETTER WIKATAKANA" +
" LETTER WEKATAKANA LETTER WOKATAKANA LETTER NKATAKANA LETTER VUKATAKANA " +
"LETTER SMALL KAKATAKANA LETTER SMALL KEKATAKANA LETTER VAKATAKANA LETTER" +
" VIKATAKANA LETTER VEKATAKANA LETTER VOKATAKANA MIDDLE DOTKATAKANA-HIRAG" +
"ANA PROLONGED SOUND MARKKATAKANA ITERATION MARKKATAKANA VOICED ITERATION" +
" MARKKATAKANA DIGRAPH KOTOBOPOMOFO LETTER BBOPOMOFO LETTER PBOPOMOFO LET" +
"TER MBOPOMOFO LETTER FBOPOMOFO LETTER DBOPOMOFO LETTER TBOPOMOFO LETTER " +
"NBOPOMOFO LETTER LBOPOMOFO LETTER GBOPOMOFO LETTER KBOPOMOFO LETTER HBOP" +
"OMOFO LETTER JBOPOMOFO LETTER QBOPOMOFO LETTER XBOPOMOFO LETTER ZHBOPOMO" +
"FO LETTER CHBOPOMOFO LETTER SHBOPOMOFO LETTER RBOPOMOFO LETTER ZBOPOMOFO" +
" LETTER CBOPOMOFO LETTER SBOPOMOFO LETTER ABOPOMOFO LETTER OBOPOMOFO LET" +
"TER EBOPOMOFO LETTER EHBOPOMOFO LETTER AIBOPOMOFO LETTER EIBOPOMOFO LETT" +
"ER AUBOPOMOFO LETTER OUBOPOMOFO LETTER ANBOPOMOFO LETTER ENBOPOMOFO LETT" +
"ER ANGBOPOMOFO LETTER ENGBOPOMOFO LETTER ERBOPOMOFO LETTER IBOPOMOFO LET" +
"TER UBOPOMOFO LETTER IUBOPOMOFO LETTER VBOPOMOFO LETTER NGBOPOMOFO LETTE" +
"R GNBOPOMOFO LETTER IHBOPOMOFO LETTER O WITH DOT ABOVEBOPOMOFO LETTER NN" +
"HANGUL LETTER KIYEOKHANGUL LETTER SSANGKIYEOKHANGUL LETTER KIYEOK-SIOSHA" +
"NGUL LETTER NIEUNHANGUL LETTER NIEUN-CIEUCHANGUL LETTER NIEUN-HIEUHHANGU" +
"L LETTER TIKEUTHANGUL LETTER SSANGTIKEUTHANGUL LETTER RIEULHANGUL LETTER") + ("" +
" RIEUL-KIYEOKHANGUL LETTER RIEUL-MIEUMHANGUL LETTER RIEUL-PIEUPHANGUL LE" +
"TTER RIEUL-SIOSHANGUL LETTER RIEUL-THIEUTHHANGUL LETTER RIEUL-PHIEUPHHAN" +
"GUL LETTER RIEUL-HIEUHHANGUL LETTER MIEUMHANGUL LETTER PIEUPHANGUL LETTE" +
"R SSANGPIEUPHANGUL LETTER PIEUP-SIOSHANGUL LETTER SIOSHANGUL LETTER SSAN" +
"GSIOSHANGUL LETTER IEUNGHANGUL LETTER CIEUCHANGUL LETTER SSANGCIEUCHANGU" +
"L LETTER CHIEUCHHANGUL LETTER KHIEUKHHANGUL LETTER THIEUTHHANGUL LETTER " +
"PHIEUPHHANGUL LETTER HIEUHHANGUL LETTER AHANGUL LETTER AEHANGUL LETTER Y" +
"AHANGUL LETTER YAEHANGUL LETTER EOHANGUL LETTER EHANGUL LETTER YEOHANGUL" +
" LETTER YEHANGUL LETTER OHANGUL LETTER WAHANGUL LETTER WAEHANGUL LETTER " +
"OEHANGUL LETTER YOHANGUL LETTER UHANGUL LETTER WEOHANGUL LETTER WEHANGUL" +
" LETTER WIHANGUL LETTER YUHANGUL LETTER EUHANGUL LETTER YIHANGUL LETTER " +
"IHANGUL FILLERHANGUL LETTER SSANGNIEUNHANGUL LETTER NIEUN-TIKEUTHANGUL L" +
"ETTER NIEUN-SIOSHANGUL LETTER NIEUN-PANSIOSHANGUL LETTER RIEUL-KIYEOK-SI" +
"OSHANGUL LETTER RIEUL-TIKEUTHANGUL LETTER RIEUL-PIEUP-SIOSHANGUL LETTER " +
"RIEUL-PANSIOSHANGUL LETTER RIEUL-YEORINHIEUHHANGUL LETTER MIEUM-PIEUPHAN" +
"GUL LETTER MIEUM-SIOSHANGUL LETTER MIEUM-PANSIOSHANGUL LETTER KAPYEOUNMI" +
"EUMHANGUL LETTER PIEUP-KIYEOKHANGUL LETTER PIEUP-TIKEUTHANGUL LETTER PIE" +
"UP-SIOS-KIYEOKHANGUL LETTER PIEUP-SIOS-TIKEUTHANGUL LETTER PIEUP-CIEUCHA" +
"NGUL LETTER PIEUP-THIEUTHHANGUL LETTER KAPYEOUNPIEUPHANGUL LETTER KAPYEO" +
"UNSSANGPIEUPHANGUL LETTER SIOS-KIYEOKHANGUL LETTER SIOS-NIEUNHANGUL LETT" +
"ER SIOS-TIKEUTHANGUL LETTER SIOS-PIEUPHANGUL LETTER SIOS-CIEUCHANGUL LET" +
"TER PANSIOSHANGUL LETTER SSANGIEUNGHANGUL LETTER YESIEUNGHANGUL LETTER Y" +
"ESIEUNG-SIOSHANGUL LETTER YESIEUNG-PANSIOSHANGUL LETTER KAPYEOUNPHIEUPHH" +
"ANGUL LETTER SSANGHIEUHHANGUL LETTER YEORINHIEUHHANGUL LETTER YO-YAHANGU" +
"L LETTER YO-YAEHANGUL LETTER YO-IHANGUL LETTER YU-YEOHANGUL LETTER YU-YE" +
"HANGUL LETTER YU-IHANGUL LETTER ARAEAHANGUL LETTER ARAEAEIDEOGRAPHIC ANN" +
"OTATION LINKING MARKIDEOGRAPHIC ANNOTATION REVERSE MARKIDEOGRAPHIC ANNOT" +
"ATION ONE MARKIDEOGRAPHIC ANNOTATION TWO MARKIDEOGRAPHIC ANNOTATION THRE" +
"E MARKIDEOGRAPHIC ANNOTATION FOUR MARKIDEOGRAPHIC ANNOTATION TOP MARKIDE" +
"OGRAPHIC ANNOTATION MIDDLE MARKIDEOGRAPHIC ANNOTATION BOTTOM MARKIDEOGRA" +
"PHIC ANNOTATION FIRST MARKIDEOGRAPHIC ANNOTATION SECOND MARKIDEOGRAPHIC " +
"ANNOTATION THIRD MARKIDEOGRAPHIC ANNOTATION FOURTH MARKIDEOGRAPHIC ANNOT" +
"ATION HEAVEN MARKIDEOGRAPHIC ANNOTATION EARTH MARKIDEOGRAPHIC ANNOTATION" +
" MAN MARKBOPOMOFO LETTER BUBOPOMOFO LETTER ZIBOPOMOFO LETTER JIBOPOMOFO " +
"LETTER GUBOPOMOFO LETTER EEBOPOMOFO LETTER ENNBOPOMOFO LETTER OOBOPOMOFO" +
" LETTER ONNBOPOMOFO LETTER IRBOPOMOFO LETTER ANNBOPOMOFO LETTER INNBOPOM" +
"OFO LETTER UNNBOPOMOFO LETTER IMBOPOMOFO LETTER NGGBOPOMOFO LETTER AINNB" +
"OPOMOFO LETTER AUNNBOPOMOFO LETTER AMBOPOMOFO LETTER OMBOPOMOFO LETTER O" +
"NGBOPOMOFO LETTER INNNBOPOMOFO FINAL LETTER PBOPOMOFO FINAL LETTER TBOPO" +
"MOFO FINAL LETTER KBOPOMOFO FINAL LETTER HBOPOMOFO LETTER GHBOPOMOFO LET" +
"TER LHBOPOMOFO LETTER ZYBOPOMOFO FINAL LETTER GBOPOMOFO LETTER GWBOPOMOF" +
"O LETTER KWBOPOMOFO LETTER OEBOPOMOFO LETTER AHCJK STROKE TCJK STROKE WG" +
"CJK STROKE XGCJK STROKE BXGCJK STROKE SWCJK STROKE HZZCJK STROKE HZGCJK " +
"STROKE HPCJK STROKE HZWGCJK STROKE SZWGCJK STROKE HZTCJK STROKE HZZPCJK " +
"STROKE HPWGCJK STROKE HZWCJK STROKE HZZZCJK STROKE NCJK STROKE HCJK STRO" +
"KE SCJK STROKE PCJK STROKE SPCJK STROKE DCJK STROKE HZCJK STROKE HGCJK S" +
"TROKE SZCJK STROKE SWZCJK STROKE STCJK STROKE SGCJK STROKE PDCJK STROKE " +
"PZCJK STROKE TNCJK STROKE SZZCJK STROKE SWGCJK STROKE HXWGCJK STROKE HZZ" +
"ZGCJK STROKE PGCJK STROKE QCJK STROKE HXGCJK STROKE SZPIDEOGRAPHIC DESCR" +
"IPTION CHARACTER SUBTRACTIONKATAKANA LETTER SMALL KUKATAKANA LETTER SMAL" +
"L SIKATAKANA LETTER SMALL SUKATAKANA LETTER SMALL TOKATAKANA LETTER SMAL" +
"L NUKATAKANA LETTER SMALL HAKATAKANA LETTER SMALL HIKATAKANA LETTER SMAL" +
"L HUKATAKANA LETTER SMALL HEKATAKANA LETTER SMALL HOKATAKANA LETTER SMAL" +
"L MUKATAKANA LETTER SMALL RAKATAKANA LETTER SMALL RIKATAKANA LETTER SMAL" +
"L RUKATAKANA LETTER SMALL REKATAKANA LETTER SMALL ROPARENTHESIZED HANGUL" +
" KIYEOKPARENTHESIZED HANGUL NIEUNPARENTHESIZED HANGUL TIKEUTPARENTHESIZE" +
"D HANGUL RIEULPARENTHESIZED HANGUL MIEUMPARENTHESIZED HANGUL PIEUPPARENT" +
"HESIZED HANGUL SIOSPARENTHESIZED HANGUL IEUNGPARENTHESIZED HANGUL CIEUCP" +
"ARENTHESIZED HANGUL CHIEUCHPARENTHESIZED HANGUL KHIEUKHPARENTHESIZED HAN" +
"GUL THIEUTHPARENTHESIZED HANGUL PHIEUPHPARENTHESIZED HANGUL HIEUHPARENTH" +
"ESIZED HANGUL KIYEOK APARENTHESIZED HANGUL NIEUN APARENTHESIZED HANGUL T" +
"IKEUT APARENTHESIZED HANGUL RIEUL APARENTHESIZED HANGUL MIEUM APARENTHES" +
"IZED HANGUL PIEUP APARENTHESIZED HANGUL SIOS APARENTHESIZED HANGUL IEUNG" +
" APARENTHESIZED HANGUL CIEUC APARENTHESIZED HANGUL CHIEUCH APARENTHESIZE") + ("" +
"D HANGUL KHIEUKH APARENTHESIZED HANGUL THIEUTH APARENTHESIZED HANGUL PHI" +
"EUPH APARENTHESIZED HANGUL HIEUH APARENTHESIZED HANGUL CIEUC UPARENTHESI" +
"ZED KOREAN CHARACTER OJEONPARENTHESIZED KOREAN CHARACTER O HUPARENTHESIZ" +
"ED IDEOGRAPH ONEPARENTHESIZED IDEOGRAPH TWOPARENTHESIZED IDEOGRAPH THREE" +
"PARENTHESIZED IDEOGRAPH FOURPARENTHESIZED IDEOGRAPH FIVEPARENTHESIZED ID" +
"EOGRAPH SIXPARENTHESIZED IDEOGRAPH SEVENPARENTHESIZED IDEOGRAPH EIGHTPAR" +
"ENTHESIZED IDEOGRAPH NINEPARENTHESIZED IDEOGRAPH TENPARENTHESIZED IDEOGR" +
"APH MOONPARENTHESIZED IDEOGRAPH FIREPARENTHESIZED IDEOGRAPH WATERPARENTH" +
"ESIZED IDEOGRAPH WOODPARENTHESIZED IDEOGRAPH METALPARENTHESIZED IDEOGRAP" +
"H EARTHPARENTHESIZED IDEOGRAPH SUNPARENTHESIZED IDEOGRAPH STOCKPARENTHES" +
"IZED IDEOGRAPH HAVEPARENTHESIZED IDEOGRAPH SOCIETYPARENTHESIZED IDEOGRAP" +
"H NAMEPARENTHESIZED IDEOGRAPH SPECIALPARENTHESIZED IDEOGRAPH FINANCIALPA" +
"RENTHESIZED IDEOGRAPH CONGRATULATIONPARENTHESIZED IDEOGRAPH LABORPARENTH" +
"ESIZED IDEOGRAPH REPRESENTPARENTHESIZED IDEOGRAPH CALLPARENTHESIZED IDEO" +
"GRAPH STUDYPARENTHESIZED IDEOGRAPH SUPERVISEPARENTHESIZED IDEOGRAPH ENTE" +
"RPRISEPARENTHESIZED IDEOGRAPH RESOURCEPARENTHESIZED IDEOGRAPH ALLIANCEPA" +
"RENTHESIZED IDEOGRAPH FESTIVALPARENTHESIZED IDEOGRAPH RESTPARENTHESIZED " +
"IDEOGRAPH SELFPARENTHESIZED IDEOGRAPH REACHCIRCLED IDEOGRAPH QUESTIONCIR" +
"CLED IDEOGRAPH KINDERGARTENCIRCLED IDEOGRAPH SCHOOLCIRCLED IDEOGRAPH KOT" +
"OCIRCLED NUMBER TEN ON BLACK SQUARECIRCLED NUMBER TWENTY ON BLACK SQUARE" +
"CIRCLED NUMBER THIRTY ON BLACK SQUARECIRCLED NUMBER FORTY ON BLACK SQUAR" +
"ECIRCLED NUMBER FIFTY ON BLACK SQUARECIRCLED NUMBER SIXTY ON BLACK SQUAR" +
"ECIRCLED NUMBER SEVENTY ON BLACK SQUARECIRCLED NUMBER EIGHTY ON BLACK SQ" +
"UAREPARTNERSHIP SIGNCIRCLED NUMBER TWENTY ONECIRCLED NUMBER TWENTY TWOCI" +
"RCLED NUMBER TWENTY THREECIRCLED NUMBER TWENTY FOURCIRCLED NUMBER TWENTY" +
" FIVECIRCLED NUMBER TWENTY SIXCIRCLED NUMBER TWENTY SEVENCIRCLED NUMBER " +
"TWENTY EIGHTCIRCLED NUMBER TWENTY NINECIRCLED NUMBER THIRTYCIRCLED NUMBE" +
"R THIRTY ONECIRCLED NUMBER THIRTY TWOCIRCLED NUMBER THIRTY THREECIRCLED " +
"NUMBER THIRTY FOURCIRCLED NUMBER THIRTY FIVECIRCLED HANGUL KIYEOKCIRCLED" +
" HANGUL NIEUNCIRCLED HANGUL TIKEUTCIRCLED HANGUL RIEULCIRCLED HANGUL MIE" +
"UMCIRCLED HANGUL PIEUPCIRCLED HANGUL SIOSCIRCLED HANGUL IEUNGCIRCLED HAN" +
"GUL CIEUCCIRCLED HANGUL CHIEUCHCIRCLED HANGUL KHIEUKHCIRCLED HANGUL THIE" +
"UTHCIRCLED HANGUL PHIEUPHCIRCLED HANGUL HIEUHCIRCLED HANGUL KIYEOK ACIRC" +
"LED HANGUL NIEUN ACIRCLED HANGUL TIKEUT ACIRCLED HANGUL RIEUL ACIRCLED H" +
"ANGUL MIEUM ACIRCLED HANGUL PIEUP ACIRCLED HANGUL SIOS ACIRCLED HANGUL I" +
"EUNG ACIRCLED HANGUL CIEUC ACIRCLED HANGUL CHIEUCH ACIRCLED HANGUL KHIEU" +
"KH ACIRCLED HANGUL THIEUTH ACIRCLED HANGUL PHIEUPH ACIRCLED HANGUL HIEUH" +
" ACIRCLED KOREAN CHARACTER CHAMKOCIRCLED KOREAN CHARACTER JUEUICIRCLED H" +
"ANGUL IEUNG UKOREAN STANDARD SYMBOLCIRCLED IDEOGRAPH ONECIRCLED IDEOGRAP" +
"H TWOCIRCLED IDEOGRAPH THREECIRCLED IDEOGRAPH FOURCIRCLED IDEOGRAPH FIVE" +
"CIRCLED IDEOGRAPH SIXCIRCLED IDEOGRAPH SEVENCIRCLED IDEOGRAPH EIGHTCIRCL" +
"ED IDEOGRAPH NINECIRCLED IDEOGRAPH TENCIRCLED IDEOGRAPH MOONCIRCLED IDEO" +
"GRAPH FIRECIRCLED IDEOGRAPH WATERCIRCLED IDEOGRAPH WOODCIRCLED IDEOGRAPH" +
" METALCIRCLED IDEOGRAPH EARTHCIRCLED IDEOGRAPH SUNCIRCLED IDEOGRAPH STOC" +
"KCIRCLED IDEOGRAPH HAVECIRCLED IDEOGRAPH SOCIETYCIRCLED IDEOGRAPH NAMECI" +
"RCLED IDEOGRAPH SPECIALCIRCLED IDEOGRAPH FINANCIALCIRCLED IDEOGRAPH CONG" +
"RATULATIONCIRCLED IDEOGRAPH LABORCIRCLED IDEOGRAPH SECRETCIRCLED IDEOGRA" +
"PH MALECIRCLED IDEOGRAPH FEMALECIRCLED IDEOGRAPH SUITABLECIRCLED IDEOGRA" +
"PH EXCELLENTCIRCLED IDEOGRAPH PRINTCIRCLED IDEOGRAPH ATTENTIONCIRCLED ID" +
"EOGRAPH ITEMCIRCLED IDEOGRAPH RESTCIRCLED IDEOGRAPH COPYCIRCLED IDEOGRAP" +
"H CORRECTCIRCLED IDEOGRAPH HIGHCIRCLED IDEOGRAPH CENTRECIRCLED IDEOGRAPH" +
" LOWCIRCLED IDEOGRAPH LEFTCIRCLED IDEOGRAPH RIGHTCIRCLED IDEOGRAPH MEDIC" +
"INECIRCLED IDEOGRAPH RELIGIONCIRCLED IDEOGRAPH STUDYCIRCLED IDEOGRAPH SU" +
"PERVISECIRCLED IDEOGRAPH ENTERPRISECIRCLED IDEOGRAPH RESOURCECIRCLED IDE" +
"OGRAPH ALLIANCECIRCLED IDEOGRAPH NIGHTCIRCLED NUMBER THIRTY SIXCIRCLED N" +
"UMBER THIRTY SEVENCIRCLED NUMBER THIRTY EIGHTCIRCLED NUMBER THIRTY NINEC" +
"IRCLED NUMBER FORTYCIRCLED NUMBER FORTY ONECIRCLED NUMBER FORTY TWOCIRCL" +
"ED NUMBER FORTY THREECIRCLED NUMBER FORTY FOURCIRCLED NUMBER FORTY FIVEC" +
"IRCLED NUMBER FORTY SIXCIRCLED NUMBER FORTY SEVENCIRCLED NUMBER FORTY EI" +
"GHTCIRCLED NUMBER FORTY NINECIRCLED NUMBER FIFTYIDEOGRAPHIC TELEGRAPH SY" +
"MBOL FOR JANUARYIDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARYIDEOGRAPHIC TEL" +
"EGRAPH SYMBOL FOR MARCHIDEOGRAPHIC TELEGRAPH SYMBOL FOR APRILIDEOGRAPHIC" +
" TELEGRAPH SYMBOL FOR MAYIDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNEIDEOGRAPHI" +
"C TELEGRAPH SYMBOL FOR JULYIDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUSTIDEOGR") + ("" +
"APHIC TELEGRAPH SYMBOL FOR SEPTEMBERIDEOGRAPHIC TELEGRAPH SYMBOL FOR OCT" +
"OBERIDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBERIDEOGRAPHIC TELEGRAPH SYMBO" +
"L FOR DECEMBERSQUARE HGSQUARE ERGSQUARE EVLIMITED LIABILITY SIGNCIRCLED " +
"KATAKANA ACIRCLED KATAKANA ICIRCLED KATAKANA UCIRCLED KATAKANA ECIRCLED " +
"KATAKANA OCIRCLED KATAKANA KACIRCLED KATAKANA KICIRCLED KATAKANA KUCIRCL" +
"ED KATAKANA KECIRCLED KATAKANA KOCIRCLED KATAKANA SACIRCLED KATAKANA SIC" +
"IRCLED KATAKANA SUCIRCLED KATAKANA SECIRCLED KATAKANA SOCIRCLED KATAKANA" +
" TACIRCLED KATAKANA TICIRCLED KATAKANA TUCIRCLED KATAKANA TECIRCLED KATA" +
"KANA TOCIRCLED KATAKANA NACIRCLED KATAKANA NICIRCLED KATAKANA NUCIRCLED " +
"KATAKANA NECIRCLED KATAKANA NOCIRCLED KATAKANA HACIRCLED KATAKANA HICIRC" +
"LED KATAKANA HUCIRCLED KATAKANA HECIRCLED KATAKANA HOCIRCLED KATAKANA MA" +
"CIRCLED KATAKANA MICIRCLED KATAKANA MUCIRCLED KATAKANA MECIRCLED KATAKAN" +
"A MOCIRCLED KATAKANA YACIRCLED KATAKANA YUCIRCLED KATAKANA YOCIRCLED KAT" +
"AKANA RACIRCLED KATAKANA RICIRCLED KATAKANA RUCIRCLED KATAKANA RECIRCLED" +
" KATAKANA ROCIRCLED KATAKANA WACIRCLED KATAKANA WICIRCLED KATAKANA WECIR" +
"CLED KATAKANA WOSQUARE ERA NAME REIWASQUARE APAATOSQUARE ARUHUASQUARE AN" +
"PEASQUARE AARUSQUARE ININGUSQUARE INTISQUARE UONSQUARE ESUKUUDOSQUARE EE" +
"KAASQUARE ONSUSQUARE OOMUSQUARE KAIRISQUARE KARATTOSQUARE KARORIISQUARE " +
"GARONSQUARE GANMASQUARE GIGASQUARE GINIISQUARE KYURIISQUARE GIRUDAASQUAR" +
"E KIROSQUARE KIROGURAMUSQUARE KIROMEETORUSQUARE KIROWATTOSQUARE GURAMUSQ" +
"UARE GURAMUTONSQUARE KURUZEIROSQUARE KUROONESQUARE KEESUSQUARE KORUNASQU" +
"ARE KOOPOSQUARE SAIKURUSQUARE SANTIIMUSQUARE SIRINGUSQUARE SENTISQUARE S" +
"ENTOSQUARE DAASUSQUARE DESISQUARE DORUSQUARE TONSQUARE NANOSQUARE NOTTOS" +
"QUARE HAITUSQUARE PAASENTOSQUARE PAATUSQUARE BAARERUSQUARE PIASUTORUSQUA" +
"RE PIKURUSQUARE PIKOSQUARE BIRUSQUARE HUARADDOSQUARE HUIITOSQUARE BUSSYE" +
"RUSQUARE HURANSQUARE HEKUTAARUSQUARE PESOSQUARE PENIHISQUARE HERUTUSQUAR" +
"E PENSUSQUARE PEEZISQUARE BEETASQUARE POINTOSQUARE BORUTOSQUARE HONSQUAR" +
"E PONDOSQUARE HOORUSQUARE HOONSQUARE MAIKUROSQUARE MAIRUSQUARE MAHHASQUA" +
"RE MARUKUSQUARE MANSYONSQUARE MIKURONSQUARE MIRISQUARE MIRIBAARUSQUARE M" +
"EGASQUARE MEGATONSQUARE MEETORUSQUARE YAADOSQUARE YAARUSQUARE YUANSQUARE" +
" RITTORUSQUARE RIRASQUARE RUPIISQUARE RUUBURUSQUARE REMUSQUARE RENTOGENS" +
"QUARE WATTOIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZEROIDEOGRAPHIC TELEGRA" +
"PH SYMBOL FOR HOUR ONEIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWOIDEOGRAPH" +
"IC TELEGRAPH SYMBOL FOR HOUR THREEIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR " +
"FOURIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVEIDEOGRAPHIC TELEGRAPH SYMB" +
"OL FOR HOUR SIXIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENIDEOGRAPHIC TE" +
"LEGRAPH SYMBOL FOR HOUR EIGHTIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINEI" +
"DEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TENIDEOGRAPHIC TELEGRAPH SYMBOL FOR" +
" HOUR ELEVENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVEIDEOGRAPHIC TELE" +
"GRAPH SYMBOL FOR HOUR THIRTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR" +
"TEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEENIDEOGRAPHIC TELEGRAPH S" +
"YMBOL FOR HOUR SIXTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEENIDE" +
"OGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEENIDEOGRAPHIC TELEGRAPH SYMBOL " +
"FOR HOUR NINETEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTYIDEOGRAPHIC" +
" TELEGRAPH SYMBOL FOR HOUR TWENTY-ONEIDEOGRAPHIC TELEGRAPH SYMBOL FOR HO" +
"UR TWENTY-TWOIDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREEIDEOGRAPH" +
"IC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOURSQUARE HPASQUARE DASQUARE AUSQUA" +
"RE BARSQUARE OVSQUARE PCSQUARE DMSQUARE DM SQUAREDSQUARE DM CUBEDSQUARE " +
"IUSQUARE ERA NAME HEISEISQUARE ERA NAME SYOUWASQUARE ERA NAME TAISYOUSQU" +
"ARE ERA NAME MEIZISQUARE CORPORATIONSQUARE PA AMPSSQUARE NASQUARE MU ASQ" +
"UARE MASQUARE KASQUARE KBSQUARE MBSQUARE GBSQUARE CALSQUARE KCALSQUARE P" +
"FSQUARE NFSQUARE MU FSQUARE MU GSQUARE MGSQUARE KGSQUARE HZSQUARE KHZSQU" +
"ARE MHZSQUARE GHZSQUARE THZSQUARE MU LSQUARE MLSQUARE DLSQUARE KLSQUARE " +
"FMSQUARE NMSQUARE MU MSQUARE MMSQUARE CMSQUARE KMSQUARE MM SQUAREDSQUARE" +
" CM SQUAREDSQUARE M SQUAREDSQUARE KM SQUAREDSQUARE MM CUBEDSQUARE CM CUB" +
"EDSQUARE M CUBEDSQUARE KM CUBEDSQUARE M OVER SSQUARE M OVER S SQUAREDSQU" +
"ARE PASQUARE KPASQUARE MPASQUARE GPASQUARE RADSQUARE RAD OVER SSQUARE RA" +
"D OVER S SQUAREDSQUARE PSSQUARE NSSQUARE MU SSQUARE MSSQUARE PVSQUARE NV" +
"SQUARE MU VSQUARE MVSQUARE KVSQUARE MV MEGASQUARE PWSQUARE NWSQUARE MU W" +
"SQUARE MWSQUARE KWSQUARE MW MEGASQUARE K OHMSQUARE M OHMSQUARE AMSQUARE " +
"BQSQUARE CCSQUARE CDSQUARE C OVER KGSQUARE COSQUARE DBSQUARE GYSQUARE HA" +
"SQUARE HPSQUARE INSQUARE KKSQUARE KM CAPITALSQUARE KTSQUARE LMSQUARE LNS" +
"QUARE LOGSQUARE LXSQUARE MB SMALLSQUARE MILSQUARE MOLSQUARE PHSQUARE PMS" +
"QUARE PPMSQUARE PRSQUARE SRSQUARE SVSQUARE WBSQUARE V OVER MSQUARE A OVE") + ("" +
"R MIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONEIDEOGRAPHIC TELEGRAPH SYMBOL " +
"FOR DAY TWOIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREEIDEOGRAPHIC TELEGRA" +
"PH SYMBOL FOR DAY FOURIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVEIDEOGRAPH" +
"IC TELEGRAPH SYMBOL FOR DAY SIXIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVE" +
"NIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTIDEOGRAPHIC TELEGRAPH SYMBOL " +
"FOR DAY NINEIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TENIDEOGRAPHIC TELEGRAP" +
"H SYMBOL FOR DAY ELEVENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVEIDEOGR" +
"APHIC TELEGRAPH SYMBOL FOR DAY THIRTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR " +
"DAY FOURTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEENIDEOGRAPHIC TELE" +
"GRAPH SYMBOL FOR DAY SIXTEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTE" +
"ENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEENIDEOGRAPHIC TELEGRAPH SYM" +
"BOL FOR DAY NINETEENIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTYIDEOGRAPH" +
"IC TELEGRAPH SYMBOL FOR DAY TWENTY-ONEIDEOGRAPHIC TELEGRAPH SYMBOL FOR D" +
"AY TWENTY-TWOIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREEIDEOGRAPHI" +
"C TELEGRAPH SYMBOL FOR DAY TWENTY-FOURIDEOGRAPHIC TELEGRAPH SYMBOL FOR D" +
"AY TWENTY-FIVEIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIXIDEOGRAPHIC" +
" TELEGRAPH SYMBOL FOR DAY TWENTY-SEVENIDEOGRAPHIC TELEGRAPH SYMBOL FOR D" +
"AY TWENTY-EIGHTIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINEIDEOGRAPH" +
"IC TELEGRAPH SYMBOL FOR DAY THIRTYIDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY T" +
"HIRTY-ONESQUARE GALHEXAGRAM FOR THE CREATIVE HEAVENHEXAGRAM FOR THE RECE" +
"PTIVE EARTHHEXAGRAM FOR DIFFICULTY AT THE BEGINNINGHEXAGRAM FOR YOUTHFUL" +
" FOLLYHEXAGRAM FOR WAITINGHEXAGRAM FOR CONFLICTHEXAGRAM FOR THE ARMYHEXA" +
"GRAM FOR HOLDING TOGETHERHEXAGRAM FOR SMALL TAMINGHEXAGRAM FOR TREADINGH" +
"EXAGRAM FOR PEACEHEXAGRAM FOR STANDSTILLHEXAGRAM FOR FELLOWSHIPHEXAGRAM " +
"FOR GREAT POSSESSIONHEXAGRAM FOR MODESTYHEXAGRAM FOR ENTHUSIASMHEXAGRAM " +
"FOR FOLLOWINGHEXAGRAM FOR WORK ON THE DECAYEDHEXAGRAM FOR APPROACHHEXAGR" +
"AM FOR CONTEMPLATIONHEXAGRAM FOR BITING THROUGHHEXAGRAM FOR GRACEHEXAGRA" +
"M FOR SPLITTING APARTHEXAGRAM FOR RETURNHEXAGRAM FOR INNOCENCEHEXAGRAM F" +
"OR GREAT TAMINGHEXAGRAM FOR MOUTH CORNERSHEXAGRAM FOR GREAT PREPONDERANC" +
"EHEXAGRAM FOR THE ABYSMAL WATERHEXAGRAM FOR THE CLINGING FIREHEXAGRAM FO" +
"R INFLUENCEHEXAGRAM FOR DURATIONHEXAGRAM FOR RETREATHEXAGRAM FOR GREAT P" +
"OWERHEXAGRAM FOR PROGRESSHEXAGRAM FOR DARKENING OF THE LIGHTHEXAGRAM FOR" +
" THE FAMILYHEXAGRAM FOR OPPOSITIONHEXAGRAM FOR OBSTRUCTIONHEXAGRAM FOR D" +
"ELIVERANCEHEXAGRAM FOR DECREASEHEXAGRAM FOR INCREASEHEXAGRAM FOR BREAKTH" +
"ROUGHHEXAGRAM FOR COMING TO MEETHEXAGRAM FOR GATHERING TOGETHERHEXAGRAM " +
"FOR PUSHING UPWARDHEXAGRAM FOR OPPRESSIONHEXAGRAM FOR THE WELLHEXAGRAM F" +
"OR REVOLUTIONHEXAGRAM FOR THE CAULDRONHEXAGRAM FOR THE AROUSING THUNDERH" +
"EXAGRAM FOR THE KEEPING STILL MOUNTAINHEXAGRAM FOR DEVELOPMENTHEXAGRAM F" +
"OR THE MARRYING MAIDENHEXAGRAM FOR ABUNDANCEHEXAGRAM FOR THE WANDERERHEX" +
"AGRAM FOR THE GENTLE WINDHEXAGRAM FOR THE JOYOUS LAKEHEXAGRAM FOR DISPER" +
"SIONHEXAGRAM FOR LIMITATIONHEXAGRAM FOR INNER TRUTHHEXAGRAM FOR SMALL PR" +
"EPONDERANCEHEXAGRAM FOR AFTER COMPLETIONHEXAGRAM FOR BEFORE COMPLETIONYI" +
" SYLLABLE ITYI SYLLABLE IXYI SYLLABLE IYI SYLLABLE IPYI SYLLABLE IETYI S" +
"YLLABLE IEXYI SYLLABLE IEYI SYLLABLE IEPYI SYLLABLE ATYI SYLLABLE AXYI S" +
"YLLABLE AYI SYLLABLE APYI SYLLABLE UOXYI SYLLABLE UOYI SYLLABLE UOPYI SY" +
"LLABLE OTYI SYLLABLE OXYI SYLLABLE OYI SYLLABLE OPYI SYLLABLE EXYI SYLLA" +
"BLE EYI SYLLABLE WUYI SYLLABLE BITYI SYLLABLE BIXYI SYLLABLE BIYI SYLLAB" +
"LE BIPYI SYLLABLE BIETYI SYLLABLE BIEXYI SYLLABLE BIEYI SYLLABLE BIEPYI " +
"SYLLABLE BATYI SYLLABLE BAXYI SYLLABLE BAYI SYLLABLE BAPYI SYLLABLE BUOX" +
"YI SYLLABLE BUOYI SYLLABLE BUOPYI SYLLABLE BOTYI SYLLABLE BOXYI SYLLABLE" +
" BOYI SYLLABLE BOPYI SYLLABLE BEXYI SYLLABLE BEYI SYLLABLE BEPYI SYLLABL" +
"E BUTYI SYLLABLE BUXYI SYLLABLE BUYI SYLLABLE BUPYI SYLLABLE BURXYI SYLL" +
"ABLE BURYI SYLLABLE BYTYI SYLLABLE BYXYI SYLLABLE BYYI SYLLABLE BYPYI SY" +
"LLABLE BYRXYI SYLLABLE BYRYI SYLLABLE PITYI SYLLABLE PIXYI SYLLABLE PIYI" +
" SYLLABLE PIPYI SYLLABLE PIEXYI SYLLABLE PIEYI SYLLABLE PIEPYI SYLLABLE " +
"PATYI SYLLABLE PAXYI SYLLABLE PAYI SYLLABLE PAPYI SYLLABLE PUOXYI SYLLAB" +
"LE PUOYI SYLLABLE PUOPYI SYLLABLE POTYI SYLLABLE POXYI SYLLABLE POYI SYL" +
"LABLE POPYI SYLLABLE PUTYI SYLLABLE PUXYI SYLLABLE PUYI SYLLABLE PUPYI S" +
"YLLABLE PURXYI SYLLABLE PURYI SYLLABLE PYTYI SYLLABLE PYXYI SYLLABLE PYY" +
"I SYLLABLE PYPYI SYLLABLE PYRXYI SYLLABLE PYRYI SYLLABLE BBITYI SYLLABLE" +
" BBIXYI SYLLABLE BBIYI SYLLABLE BBIPYI SYLLABLE BBIETYI SYLLABLE BBIEXYI" +
" SYLLABLE BBIEYI SYLLABLE BBIEPYI SYLLABLE BBATYI SYLLABLE BBAXYI SYLLAB" +
"LE BBAYI SYLLABLE BBAPYI SYLLABLE BBUOXYI SYLLABLE BBUOYI SYLLABLE BBUOP" +
"YI SYLLABLE BBOTYI SYLLABLE BBOXYI SYLLABLE BBOYI SYLLABLE BBOPYI SYLLAB") + ("" +
"LE BBEXYI SYLLABLE BBEYI SYLLABLE BBEPYI SYLLABLE BBUTYI SYLLABLE BBUXYI" +
" SYLLABLE BBUYI SYLLABLE BBUPYI SYLLABLE BBURXYI SYLLABLE BBURYI SYLLABL" +
"E BBYTYI SYLLABLE BBYXYI SYLLABLE BBYYI SYLLABLE BBYPYI SYLLABLE NBITYI " +
"SYLLABLE NBIXYI SYLLABLE NBIYI SYLLABLE NBIPYI SYLLABLE NBIEXYI SYLLABLE" +
" NBIEYI SYLLABLE NBIEPYI SYLLABLE NBATYI SYLLABLE NBAXYI SYLLABLE NBAYI " +
"SYLLABLE NBAPYI SYLLABLE NBOTYI SYLLABLE NBOXYI SYLLABLE NBOYI SYLLABLE " +
"NBOPYI SYLLABLE NBUTYI SYLLABLE NBUXYI SYLLABLE NBUYI SYLLABLE NBUPYI SY" +
"LLABLE NBURXYI SYLLABLE NBURYI SYLLABLE NBYTYI SYLLABLE NBYXYI SYLLABLE " +
"NBYYI SYLLABLE NBYPYI SYLLABLE NBYRXYI SYLLABLE NBYRYI SYLLABLE HMITYI S" +
"YLLABLE HMIXYI SYLLABLE HMIYI SYLLABLE HMIPYI SYLLABLE HMIEXYI SYLLABLE " +
"HMIEYI SYLLABLE HMIEPYI SYLLABLE HMATYI SYLLABLE HMAXYI SYLLABLE HMAYI S" +
"YLLABLE HMAPYI SYLLABLE HMUOXYI SYLLABLE HMUOYI SYLLABLE HMUOPYI SYLLABL" +
"E HMOTYI SYLLABLE HMOXYI SYLLABLE HMOYI SYLLABLE HMOPYI SYLLABLE HMUTYI " +
"SYLLABLE HMUXYI SYLLABLE HMUYI SYLLABLE HMUPYI SYLLABLE HMURXYI SYLLABLE" +
" HMURYI SYLLABLE HMYXYI SYLLABLE HMYYI SYLLABLE HMYPYI SYLLABLE HMYRXYI " +
"SYLLABLE HMYRYI SYLLABLE MITYI SYLLABLE MIXYI SYLLABLE MIYI SYLLABLE MIP" +
"YI SYLLABLE MIEXYI SYLLABLE MIEYI SYLLABLE MIEPYI SYLLABLE MATYI SYLLABL" +
"E MAXYI SYLLABLE MAYI SYLLABLE MAPYI SYLLABLE MUOTYI SYLLABLE MUOXYI SYL" +
"LABLE MUOYI SYLLABLE MUOPYI SYLLABLE MOTYI SYLLABLE MOXYI SYLLABLE MOYI " +
"SYLLABLE MOPYI SYLLABLE MEXYI SYLLABLE MEYI SYLLABLE MUTYI SYLLABLE MUXY" +
"I SYLLABLE MUYI SYLLABLE MUPYI SYLLABLE MURXYI SYLLABLE MURYI SYLLABLE M" +
"YTYI SYLLABLE MYXYI SYLLABLE MYYI SYLLABLE MYPYI SYLLABLE FITYI SYLLABLE" +
" FIXYI SYLLABLE FIYI SYLLABLE FIPYI SYLLABLE FATYI SYLLABLE FAXYI SYLLAB" +
"LE FAYI SYLLABLE FAPYI SYLLABLE FOXYI SYLLABLE FOYI SYLLABLE FOPYI SYLLA" +
"BLE FUTYI SYLLABLE FUXYI SYLLABLE FUYI SYLLABLE FUPYI SYLLABLE FURXYI SY" +
"LLABLE FURYI SYLLABLE FYTYI SYLLABLE FYXYI SYLLABLE FYYI SYLLABLE FYPYI " +
"SYLLABLE VITYI SYLLABLE VIXYI SYLLABLE VIYI SYLLABLE VIPYI SYLLABLE VIET" +
"YI SYLLABLE VIEXYI SYLLABLE VIEYI SYLLABLE VIEPYI SYLLABLE VATYI SYLLABL" +
"E VAXYI SYLLABLE VAYI SYLLABLE VAPYI SYLLABLE VOTYI SYLLABLE VOXYI SYLLA" +
"BLE VOYI SYLLABLE VOPYI SYLLABLE VEXYI SYLLABLE VEPYI SYLLABLE VUTYI SYL" +
"LABLE VUXYI SYLLABLE VUYI SYLLABLE VUPYI SYLLABLE VURXYI SYLLABLE VURYI " +
"SYLLABLE VYTYI SYLLABLE VYXYI SYLLABLE VYYI SYLLABLE VYPYI SYLLABLE VYRX" +
"YI SYLLABLE VYRYI SYLLABLE DITYI SYLLABLE DIXYI SYLLABLE DIYI SYLLABLE D" +
"IPYI SYLLABLE DIEXYI SYLLABLE DIEYI SYLLABLE DIEPYI SYLLABLE DATYI SYLLA" +
"BLE DAXYI SYLLABLE DAYI SYLLABLE DAPYI SYLLABLE DUOXYI SYLLABLE DUOYI SY" +
"LLABLE DOTYI SYLLABLE DOXYI SYLLABLE DOYI SYLLABLE DOPYI SYLLABLE DEXYI " +
"SYLLABLE DEYI SYLLABLE DEPYI SYLLABLE DUTYI SYLLABLE DUXYI SYLLABLE DUYI" +
" SYLLABLE DUPYI SYLLABLE DURXYI SYLLABLE DURYI SYLLABLE TITYI SYLLABLE T" +
"IXYI SYLLABLE TIYI SYLLABLE TIPYI SYLLABLE TIEXYI SYLLABLE TIEYI SYLLABL" +
"E TIEPYI SYLLABLE TATYI SYLLABLE TAXYI SYLLABLE TAYI SYLLABLE TAPYI SYLL" +
"ABLE TUOTYI SYLLABLE TUOXYI SYLLABLE TUOYI SYLLABLE TUOPYI SYLLABLE TOTY" +
"I SYLLABLE TOXYI SYLLABLE TOYI SYLLABLE TOPYI SYLLABLE TEXYI SYLLABLE TE" +
"YI SYLLABLE TEPYI SYLLABLE TUTYI SYLLABLE TUXYI SYLLABLE TUYI SYLLABLE T" +
"UPYI SYLLABLE TURXYI SYLLABLE TURYI SYLLABLE DDITYI SYLLABLE DDIXYI SYLL" +
"ABLE DDIYI SYLLABLE DDIPYI SYLLABLE DDIEXYI SYLLABLE DDIEYI SYLLABLE DDI" +
"EPYI SYLLABLE DDATYI SYLLABLE DDAXYI SYLLABLE DDAYI SYLLABLE DDAPYI SYLL" +
"ABLE DDUOXYI SYLLABLE DDUOYI SYLLABLE DDUOPYI SYLLABLE DDOTYI SYLLABLE D" +
"DOXYI SYLLABLE DDOYI SYLLABLE DDOPYI SYLLABLE DDEXYI SYLLABLE DDEYI SYLL" +
"ABLE DDEPYI SYLLABLE DDUTYI SYLLABLE DDUXYI SYLLABLE DDUYI SYLLABLE DDUP" +
"YI SYLLABLE DDURXYI SYLLABLE DDURYI SYLLABLE NDITYI SYLLABLE NDIXYI SYLL" +
"ABLE NDIYI SYLLABLE NDIPYI SYLLABLE NDIEXYI SYLLABLE NDIEYI SYLLABLE NDA" +
"TYI SYLLABLE NDAXYI SYLLABLE NDAYI SYLLABLE NDAPYI SYLLABLE NDOTYI SYLLA" +
"BLE NDOXYI SYLLABLE NDOYI SYLLABLE NDOPYI SYLLABLE NDEXYI SYLLABLE NDEYI" +
" SYLLABLE NDEPYI SYLLABLE NDUTYI SYLLABLE NDUXYI SYLLABLE NDUYI SYLLABLE" +
" NDUPYI SYLLABLE NDURXYI SYLLABLE NDURYI SYLLABLE HNITYI SYLLABLE HNIXYI" +
" SYLLABLE HNIYI SYLLABLE HNIPYI SYLLABLE HNIETYI SYLLABLE HNIEXYI SYLLAB" +
"LE HNIEYI SYLLABLE HNIEPYI SYLLABLE HNATYI SYLLABLE HNAXYI SYLLABLE HNAY" +
"I SYLLABLE HNAPYI SYLLABLE HNUOXYI SYLLABLE HNUOYI SYLLABLE HNOTYI SYLLA" +
"BLE HNOXYI SYLLABLE HNOPYI SYLLABLE HNEXYI SYLLABLE HNEYI SYLLABLE HNEPY" +
"I SYLLABLE HNUTYI SYLLABLE NITYI SYLLABLE NIXYI SYLLABLE NIYI SYLLABLE N" +
"IPYI SYLLABLE NIEXYI SYLLABLE NIEYI SYLLABLE NIEPYI SYLLABLE NAXYI SYLLA" +
"BLE NAYI SYLLABLE NAPYI SYLLABLE NUOXYI SYLLABLE NUOYI SYLLABLE NUOPYI S" +
"YLLABLE NOTYI SYLLABLE NOXYI SYLLABLE NOYI SYLLABLE NOPYI SYLLABLE NEXYI" +
" SYLLABLE NEYI SYLLABLE NEPYI SYLLABLE NUTYI SYLLABLE NUXYI SYLLABLE NUY") + ("" +
"I SYLLABLE NUPYI SYLLABLE NURXYI SYLLABLE NURYI SYLLABLE HLITYI SYLLABLE" +
" HLIXYI SYLLABLE HLIYI SYLLABLE HLIPYI SYLLABLE HLIEXYI SYLLABLE HLIEYI " +
"SYLLABLE HLIEPYI SYLLABLE HLATYI SYLLABLE HLAXYI SYLLABLE HLAYI SYLLABLE" +
" HLAPYI SYLLABLE HLUOXYI SYLLABLE HLUOYI SYLLABLE HLUOPYI SYLLABLE HLOXY" +
"I SYLLABLE HLOYI SYLLABLE HLOPYI SYLLABLE HLEXYI SYLLABLE HLEYI SYLLABLE" +
" HLEPYI SYLLABLE HLUTYI SYLLABLE HLUXYI SYLLABLE HLUYI SYLLABLE HLUPYI S" +
"YLLABLE HLURXYI SYLLABLE HLURYI SYLLABLE HLYTYI SYLLABLE HLYXYI SYLLABLE" +
" HLYYI SYLLABLE HLYPYI SYLLABLE HLYRXYI SYLLABLE HLYRYI SYLLABLE LITYI S" +
"YLLABLE LIXYI SYLLABLE LIYI SYLLABLE LIPYI SYLLABLE LIETYI SYLLABLE LIEX" +
"YI SYLLABLE LIEYI SYLLABLE LIEPYI SYLLABLE LATYI SYLLABLE LAXYI SYLLABLE" +
" LAYI SYLLABLE LAPYI SYLLABLE LUOTYI SYLLABLE LUOXYI SYLLABLE LUOYI SYLL" +
"ABLE LUOPYI SYLLABLE LOTYI SYLLABLE LOXYI SYLLABLE LOYI SYLLABLE LOPYI S" +
"YLLABLE LEXYI SYLLABLE LEYI SYLLABLE LEPYI SYLLABLE LUTYI SYLLABLE LUXYI" +
" SYLLABLE LUYI SYLLABLE LUPYI SYLLABLE LURXYI SYLLABLE LURYI SYLLABLE LY" +
"TYI SYLLABLE LYXYI SYLLABLE LYYI SYLLABLE LYPYI SYLLABLE LYRXYI SYLLABLE" +
" LYRYI SYLLABLE GITYI SYLLABLE GIXYI SYLLABLE GIYI SYLLABLE GIPYI SYLLAB" +
"LE GIETYI SYLLABLE GIEXYI SYLLABLE GIEYI SYLLABLE GIEPYI SYLLABLE GATYI " +
"SYLLABLE GAXYI SYLLABLE GAYI SYLLABLE GAPYI SYLLABLE GUOTYI SYLLABLE GUO" +
"XYI SYLLABLE GUOYI SYLLABLE GUOPYI SYLLABLE GOTYI SYLLABLE GOXYI SYLLABL" +
"E GOYI SYLLABLE GOPYI SYLLABLE GETYI SYLLABLE GEXYI SYLLABLE GEYI SYLLAB" +
"LE GEPYI SYLLABLE GUTYI SYLLABLE GUXYI SYLLABLE GUYI SYLLABLE GUPYI SYLL" +
"ABLE GURXYI SYLLABLE GURYI SYLLABLE KITYI SYLLABLE KIXYI SYLLABLE KIYI S" +
"YLLABLE KIPYI SYLLABLE KIEXYI SYLLABLE KIEYI SYLLABLE KIEPYI SYLLABLE KA" +
"TYI SYLLABLE KAXYI SYLLABLE KAYI SYLLABLE KAPYI SYLLABLE KUOXYI SYLLABLE" +
" KUOYI SYLLABLE KUOPYI SYLLABLE KOTYI SYLLABLE KOXYI SYLLABLE KOYI SYLLA" +
"BLE KOPYI SYLLABLE KETYI SYLLABLE KEXYI SYLLABLE KEYI SYLLABLE KEPYI SYL" +
"LABLE KUTYI SYLLABLE KUXYI SYLLABLE KUYI SYLLABLE KUPYI SYLLABLE KURXYI " +
"SYLLABLE KURYI SYLLABLE GGITYI SYLLABLE GGIXYI SYLLABLE GGIYI SYLLABLE G" +
"GIEXYI SYLLABLE GGIEYI SYLLABLE GGIEPYI SYLLABLE GGATYI SYLLABLE GGAXYI " +
"SYLLABLE GGAYI SYLLABLE GGAPYI SYLLABLE GGUOTYI SYLLABLE GGUOXYI SYLLABL" +
"E GGUOYI SYLLABLE GGUOPYI SYLLABLE GGOTYI SYLLABLE GGOXYI SYLLABLE GGOYI" +
" SYLLABLE GGOPYI SYLLABLE GGETYI SYLLABLE GGEXYI SYLLABLE GGEYI SYLLABLE" +
" GGEPYI SYLLABLE GGUTYI SYLLABLE GGUXYI SYLLABLE GGUYI SYLLABLE GGUPYI S" +
"YLLABLE GGURXYI SYLLABLE GGURYI SYLLABLE MGIEXYI SYLLABLE MGIEYI SYLLABL" +
"E MGATYI SYLLABLE MGAXYI SYLLABLE MGAYI SYLLABLE MGAPYI SYLLABLE MGUOXYI" +
" SYLLABLE MGUOYI SYLLABLE MGUOPYI SYLLABLE MGOTYI SYLLABLE MGOXYI SYLLAB" +
"LE MGOYI SYLLABLE MGOPYI SYLLABLE MGEXYI SYLLABLE MGEYI SYLLABLE MGEPYI " +
"SYLLABLE MGUTYI SYLLABLE MGUXYI SYLLABLE MGUYI SYLLABLE MGUPYI SYLLABLE " +
"MGURXYI SYLLABLE MGURYI SYLLABLE HXITYI SYLLABLE HXIXYI SYLLABLE HXIYI S" +
"YLLABLE HXIPYI SYLLABLE HXIETYI SYLLABLE HXIEXYI SYLLABLE HXIEYI SYLLABL" +
"E HXIEPYI SYLLABLE HXATYI SYLLABLE HXAXYI SYLLABLE HXAYI SYLLABLE HXAPYI" +
" SYLLABLE HXUOTYI SYLLABLE HXUOXYI SYLLABLE HXUOYI SYLLABLE HXUOPYI SYLL" +
"ABLE HXOTYI SYLLABLE HXOXYI SYLLABLE HXOYI SYLLABLE HXOPYI SYLLABLE HXEX" +
"YI SYLLABLE HXEYI SYLLABLE HXEPYI SYLLABLE NGIEXYI SYLLABLE NGIEYI SYLLA" +
"BLE NGIEPYI SYLLABLE NGATYI SYLLABLE NGAXYI SYLLABLE NGAYI SYLLABLE NGAP" +
"YI SYLLABLE NGUOTYI SYLLABLE NGUOXYI SYLLABLE NGUOYI SYLLABLE NGOTYI SYL" +
"LABLE NGOXYI SYLLABLE NGOYI SYLLABLE NGOPYI SYLLABLE NGEXYI SYLLABLE NGE" +
"YI SYLLABLE NGEPYI SYLLABLE HITYI SYLLABLE HIEXYI SYLLABLE HIEYI SYLLABL" +
"E HATYI SYLLABLE HAXYI SYLLABLE HAYI SYLLABLE HAPYI SYLLABLE HUOTYI SYLL" +
"ABLE HUOXYI SYLLABLE HUOYI SYLLABLE HUOPYI SYLLABLE HOTYI SYLLABLE HOXYI" +
" SYLLABLE HOYI SYLLABLE HOPYI SYLLABLE HEXYI SYLLABLE HEYI SYLLABLE HEPY" +
"I SYLLABLE WATYI SYLLABLE WAXYI SYLLABLE WAYI SYLLABLE WAPYI SYLLABLE WU" +
"OXYI SYLLABLE WUOYI SYLLABLE WUOPYI SYLLABLE WOXYI SYLLABLE WOYI SYLLABL" +
"E WOPYI SYLLABLE WEXYI SYLLABLE WEYI SYLLABLE WEPYI SYLLABLE ZITYI SYLLA" +
"BLE ZIXYI SYLLABLE ZIYI SYLLABLE ZIPYI SYLLABLE ZIEXYI SYLLABLE ZIEYI SY" +
"LLABLE ZIEPYI SYLLABLE ZATYI SYLLABLE ZAXYI SYLLABLE ZAYI SYLLABLE ZAPYI" +
" SYLLABLE ZUOXYI SYLLABLE ZUOYI SYLLABLE ZUOPYI SYLLABLE ZOTYI SYLLABLE " +
"ZOXYI SYLLABLE ZOYI SYLLABLE ZOPYI SYLLABLE ZEXYI SYLLABLE ZEYI SYLLABLE" +
" ZEPYI SYLLABLE ZUTYI SYLLABLE ZUXYI SYLLABLE ZUYI SYLLABLE ZUPYI SYLLAB" +
"LE ZURXYI SYLLABLE ZURYI SYLLABLE ZYTYI SYLLABLE ZYXYI SYLLABLE ZYYI SYL" +
"LABLE ZYPYI SYLLABLE ZYRXYI SYLLABLE ZYRYI SYLLABLE CITYI SYLLABLE CIXYI" +
" SYLLABLE CIYI SYLLABLE CIPYI SYLLABLE CIETYI SYLLABLE CIEXYI SYLLABLE C" +
"IEYI SYLLABLE CIEPYI SYLLABLE CATYI SYLLABLE CAXYI SYLLABLE CAYI SYLLABL" +
"E CAPYI SYLLABLE CUOXYI SYLLABLE CUOYI SYLLABLE CUOPYI SYLLABLE COTYI SY") + ("" +
"LLABLE COXYI SYLLABLE COYI SYLLABLE COPYI SYLLABLE CEXYI SYLLABLE CEYI S" +
"YLLABLE CEPYI SYLLABLE CUTYI SYLLABLE CUXYI SYLLABLE CUYI SYLLABLE CUPYI" +
" SYLLABLE CURXYI SYLLABLE CURYI SYLLABLE CYTYI SYLLABLE CYXYI SYLLABLE C" +
"YYI SYLLABLE CYPYI SYLLABLE CYRXYI SYLLABLE CYRYI SYLLABLE ZZITYI SYLLAB" +
"LE ZZIXYI SYLLABLE ZZIYI SYLLABLE ZZIPYI SYLLABLE ZZIETYI SYLLABLE ZZIEX" +
"YI SYLLABLE ZZIEYI SYLLABLE ZZIEPYI SYLLABLE ZZATYI SYLLABLE ZZAXYI SYLL" +
"ABLE ZZAYI SYLLABLE ZZAPYI SYLLABLE ZZOXYI SYLLABLE ZZOYI SYLLABLE ZZOPY" +
"I SYLLABLE ZZEXYI SYLLABLE ZZEYI SYLLABLE ZZEPYI SYLLABLE ZZUXYI SYLLABL" +
"E ZZUYI SYLLABLE ZZUPYI SYLLABLE ZZURXYI SYLLABLE ZZURYI SYLLABLE ZZYTYI" +
" SYLLABLE ZZYXYI SYLLABLE ZZYYI SYLLABLE ZZYPYI SYLLABLE ZZYRXYI SYLLABL" +
"E ZZYRYI SYLLABLE NZITYI SYLLABLE NZIXYI SYLLABLE NZIYI SYLLABLE NZIPYI " +
"SYLLABLE NZIEXYI SYLLABLE NZIEYI SYLLABLE NZIEPYI SYLLABLE NZATYI SYLLAB" +
"LE NZAXYI SYLLABLE NZAYI SYLLABLE NZAPYI SYLLABLE NZUOXYI SYLLABLE NZUOY" +
"I SYLLABLE NZOXYI SYLLABLE NZOPYI SYLLABLE NZEXYI SYLLABLE NZEYI SYLLABL" +
"E NZUXYI SYLLABLE NZUYI SYLLABLE NZUPYI SYLLABLE NZURXYI SYLLABLE NZURYI" +
" SYLLABLE NZYTYI SYLLABLE NZYXYI SYLLABLE NZYYI SYLLABLE NZYPYI SYLLABLE" +
" NZYRXYI SYLLABLE NZYRYI SYLLABLE SITYI SYLLABLE SIXYI SYLLABLE SIYI SYL" +
"LABLE SIPYI SYLLABLE SIEXYI SYLLABLE SIEYI SYLLABLE SIEPYI SYLLABLE SATY" +
"I SYLLABLE SAXYI SYLLABLE SAYI SYLLABLE SAPYI SYLLABLE SUOXYI SYLLABLE S" +
"UOYI SYLLABLE SUOPYI SYLLABLE SOTYI SYLLABLE SOXYI SYLLABLE SOYI SYLLABL" +
"E SOPYI SYLLABLE SEXYI SYLLABLE SEYI SYLLABLE SEPYI SYLLABLE SUTYI SYLLA" +
"BLE SUXYI SYLLABLE SUYI SYLLABLE SUPYI SYLLABLE SURXYI SYLLABLE SURYI SY" +
"LLABLE SYTYI SYLLABLE SYXYI SYLLABLE SYYI SYLLABLE SYPYI SYLLABLE SYRXYI" +
" SYLLABLE SYRYI SYLLABLE SSITYI SYLLABLE SSIXYI SYLLABLE SSIYI SYLLABLE " +
"SSIPYI SYLLABLE SSIEXYI SYLLABLE SSIEYI SYLLABLE SSIEPYI SYLLABLE SSATYI" +
" SYLLABLE SSAXYI SYLLABLE SSAYI SYLLABLE SSAPYI SYLLABLE SSOTYI SYLLABLE" +
" SSOXYI SYLLABLE SSOYI SYLLABLE SSOPYI SYLLABLE SSEXYI SYLLABLE SSEYI SY" +
"LLABLE SSEPYI SYLLABLE SSUTYI SYLLABLE SSUXYI SYLLABLE SSUYI SYLLABLE SS" +
"UPYI SYLLABLE SSYTYI SYLLABLE SSYXYI SYLLABLE SSYYI SYLLABLE SSYPYI SYLL" +
"ABLE SSYRXYI SYLLABLE SSYRYI SYLLABLE ZHATYI SYLLABLE ZHAXYI SYLLABLE ZH" +
"AYI SYLLABLE ZHAPYI SYLLABLE ZHUOXYI SYLLABLE ZHUOYI SYLLABLE ZHUOPYI SY" +
"LLABLE ZHOTYI SYLLABLE ZHOXYI SYLLABLE ZHOYI SYLLABLE ZHOPYI SYLLABLE ZH" +
"ETYI SYLLABLE ZHEXYI SYLLABLE ZHEYI SYLLABLE ZHEPYI SYLLABLE ZHUTYI SYLL" +
"ABLE ZHUXYI SYLLABLE ZHUYI SYLLABLE ZHUPYI SYLLABLE ZHURXYI SYLLABLE ZHU" +
"RYI SYLLABLE ZHYTYI SYLLABLE ZHYXYI SYLLABLE ZHYYI SYLLABLE ZHYPYI SYLLA" +
"BLE ZHYRXYI SYLLABLE ZHYRYI SYLLABLE CHATYI SYLLABLE CHAXYI SYLLABLE CHA" +
"YI SYLLABLE CHAPYI SYLLABLE CHUOTYI SYLLABLE CHUOXYI SYLLABLE CHUOYI SYL" +
"LABLE CHUOPYI SYLLABLE CHOTYI SYLLABLE CHOXYI SYLLABLE CHOYI SYLLABLE CH" +
"OPYI SYLLABLE CHETYI SYLLABLE CHEXYI SYLLABLE CHEYI SYLLABLE CHEPYI SYLL" +
"ABLE CHUXYI SYLLABLE CHUYI SYLLABLE CHUPYI SYLLABLE CHURXYI SYLLABLE CHU" +
"RYI SYLLABLE CHYTYI SYLLABLE CHYXYI SYLLABLE CHYYI SYLLABLE CHYPYI SYLLA" +
"BLE CHYRXYI SYLLABLE CHYRYI SYLLABLE RRAXYI SYLLABLE RRAYI SYLLABLE RRUO" +
"XYI SYLLABLE RRUOYI SYLLABLE RROTYI SYLLABLE RROXYI SYLLABLE RROYI SYLLA" +
"BLE RROPYI SYLLABLE RRETYI SYLLABLE RREXYI SYLLABLE RREYI SYLLABLE RREPY" +
"I SYLLABLE RRUTYI SYLLABLE RRUXYI SYLLABLE RRUYI SYLLABLE RRUPYI SYLLABL" +
"E RRURXYI SYLLABLE RRURYI SYLLABLE RRYTYI SYLLABLE RRYXYI SYLLABLE RRYYI" +
" SYLLABLE RRYPYI SYLLABLE RRYRXYI SYLLABLE RRYRYI SYLLABLE NRATYI SYLLAB" +
"LE NRAXYI SYLLABLE NRAYI SYLLABLE NRAPYI SYLLABLE NROXYI SYLLABLE NROYI " +
"SYLLABLE NROPYI SYLLABLE NRETYI SYLLABLE NREXYI SYLLABLE NREYI SYLLABLE " +
"NREPYI SYLLABLE NRUTYI SYLLABLE NRUXYI SYLLABLE NRUYI SYLLABLE NRUPYI SY" +
"LLABLE NRURXYI SYLLABLE NRURYI SYLLABLE NRYTYI SYLLABLE NRYXYI SYLLABLE " +
"NRYYI SYLLABLE NRYPYI SYLLABLE NRYRXYI SYLLABLE NRYRYI SYLLABLE SHATYI S" +
"YLLABLE SHAXYI SYLLABLE SHAYI SYLLABLE SHAPYI SYLLABLE SHUOXYI SYLLABLE " +
"SHUOYI SYLLABLE SHUOPYI SYLLABLE SHOTYI SYLLABLE SHOXYI SYLLABLE SHOYI S" +
"YLLABLE SHOPYI SYLLABLE SHETYI SYLLABLE SHEXYI SYLLABLE SHEYI SYLLABLE S" +
"HEPYI SYLLABLE SHUTYI SYLLABLE SHUXYI SYLLABLE SHUYI SYLLABLE SHUPYI SYL" +
"LABLE SHURXYI SYLLABLE SHURYI SYLLABLE SHYTYI SYLLABLE SHYXYI SYLLABLE S" +
"HYYI SYLLABLE SHYPYI SYLLABLE SHYRXYI SYLLABLE SHYRYI SYLLABLE RATYI SYL" +
"LABLE RAXYI SYLLABLE RAYI SYLLABLE RAPYI SYLLABLE RUOXYI SYLLABLE RUOYI " +
"SYLLABLE RUOPYI SYLLABLE ROTYI SYLLABLE ROXYI SYLLABLE ROYI SYLLABLE ROP" +
"YI SYLLABLE REXYI SYLLABLE REYI SYLLABLE REPYI SYLLABLE RUTYI SYLLABLE R" +
"UXYI SYLLABLE RUYI SYLLABLE RUPYI SYLLABLE RURXYI SYLLABLE RURYI SYLLABL" +
"E RYTYI SYLLABLE RYXYI SYLLABLE RYYI SYLLABLE RYPYI SYLLABLE RYRXYI SYLL" +
"ABLE RYRYI SYLLABLE JITYI SYLLABLE JIXYI SYLLABLE JIYI SYLLABLE JIPYI SY") + ("" +
"LLABLE JIETYI SYLLABLE JIEXYI SYLLABLE JIEYI SYLLABLE JIEPYI SYLLABLE JU" +
"OTYI SYLLABLE JUOXYI SYLLABLE JUOYI SYLLABLE JUOPYI SYLLABLE JOTYI SYLLA" +
"BLE JOXYI SYLLABLE JOYI SYLLABLE JOPYI SYLLABLE JUTYI SYLLABLE JUXYI SYL" +
"LABLE JUYI SYLLABLE JUPYI SYLLABLE JURXYI SYLLABLE JURYI SYLLABLE JYTYI " +
"SYLLABLE JYXYI SYLLABLE JYYI SYLLABLE JYPYI SYLLABLE JYRXYI SYLLABLE JYR" +
"YI SYLLABLE QITYI SYLLABLE QIXYI SYLLABLE QIYI SYLLABLE QIPYI SYLLABLE Q" +
"IETYI SYLLABLE QIEXYI SYLLABLE QIEYI SYLLABLE QIEPYI SYLLABLE QUOTYI SYL" +
"LABLE QUOXYI SYLLABLE QUOYI SYLLABLE QUOPYI SYLLABLE QOTYI SYLLABLE QOXY" +
"I SYLLABLE QOYI SYLLABLE QOPYI SYLLABLE QUTYI SYLLABLE QUXYI SYLLABLE QU" +
"YI SYLLABLE QUPYI SYLLABLE QURXYI SYLLABLE QURYI SYLLABLE QYTYI SYLLABLE" +
" QYXYI SYLLABLE QYYI SYLLABLE QYPYI SYLLABLE QYRXYI SYLLABLE QYRYI SYLLA" +
"BLE JJITYI SYLLABLE JJIXYI SYLLABLE JJIYI SYLLABLE JJIPYI SYLLABLE JJIET" +
"YI SYLLABLE JJIEXYI SYLLABLE JJIEYI SYLLABLE JJIEPYI SYLLABLE JJUOXYI SY" +
"LLABLE JJUOYI SYLLABLE JJUOPYI SYLLABLE JJOTYI SYLLABLE JJOXYI SYLLABLE " +
"JJOYI SYLLABLE JJOPYI SYLLABLE JJUTYI SYLLABLE JJUXYI SYLLABLE JJUYI SYL" +
"LABLE JJUPYI SYLLABLE JJURXYI SYLLABLE JJURYI SYLLABLE JJYTYI SYLLABLE J" +
"JYXYI SYLLABLE JJYYI SYLLABLE JJYPYI SYLLABLE NJITYI SYLLABLE NJIXYI SYL" +
"LABLE NJIYI SYLLABLE NJIPYI SYLLABLE NJIETYI SYLLABLE NJIEXYI SYLLABLE N" +
"JIEYI SYLLABLE NJIEPYI SYLLABLE NJUOXYI SYLLABLE NJUOYI SYLLABLE NJOTYI " +
"SYLLABLE NJOXYI SYLLABLE NJOYI SYLLABLE NJOPYI SYLLABLE NJUXYI SYLLABLE " +
"NJUYI SYLLABLE NJUPYI SYLLABLE NJURXYI SYLLABLE NJURYI SYLLABLE NJYTYI S" +
"YLLABLE NJYXYI SYLLABLE NJYYI SYLLABLE NJYPYI SYLLABLE NJYRXYI SYLLABLE " +
"NJYRYI SYLLABLE NYITYI SYLLABLE NYIXYI SYLLABLE NYIYI SYLLABLE NYIPYI SY" +
"LLABLE NYIETYI SYLLABLE NYIEXYI SYLLABLE NYIEYI SYLLABLE NYIEPYI SYLLABL" +
"E NYUOXYI SYLLABLE NYUOYI SYLLABLE NYUOPYI SYLLABLE NYOTYI SYLLABLE NYOX" +
"YI SYLLABLE NYOYI SYLLABLE NYOPYI SYLLABLE NYUTYI SYLLABLE NYUXYI SYLLAB" +
"LE NYUYI SYLLABLE NYUPYI SYLLABLE XITYI SYLLABLE XIXYI SYLLABLE XIYI SYL" +
"LABLE XIPYI SYLLABLE XIETYI SYLLABLE XIEXYI SYLLABLE XIEYI SYLLABLE XIEP" +
"YI SYLLABLE XUOXYI SYLLABLE XUOYI SYLLABLE XOTYI SYLLABLE XOXYI SYLLABLE" +
" XOYI SYLLABLE XOPYI SYLLABLE XYTYI SYLLABLE XYXYI SYLLABLE XYYI SYLLABL" +
"E XYPYI SYLLABLE XYRXYI SYLLABLE XYRYI SYLLABLE YITYI SYLLABLE YIXYI SYL" +
"LABLE YIYI SYLLABLE YIPYI SYLLABLE YIETYI SYLLABLE YIEXYI SYLLABLE YIEYI" +
" SYLLABLE YIEPYI SYLLABLE YUOTYI SYLLABLE YUOXYI SYLLABLE YUOYI SYLLABLE" +
" YUOPYI SYLLABLE YOTYI SYLLABLE YOXYI SYLLABLE YOYI SYLLABLE YOPYI SYLLA" +
"BLE YUTYI SYLLABLE YUXYI SYLLABLE YUYI SYLLABLE YUPYI SYLLABLE YURXYI SY" +
"LLABLE YURYI SYLLABLE YYTYI SYLLABLE YYXYI SYLLABLE YYYI SYLLABLE YYPYI " +
"SYLLABLE YYRXYI SYLLABLE YYRYI RADICAL QOTYI RADICAL LIYI RADICAL KITYI " +
"RADICAL NYIPYI RADICAL CYPYI RADICAL SSIYI RADICAL GGOPYI RADICAL GEPYI " +
"RADICAL MIYI RADICAL HXITYI RADICAL LYRYI RADICAL BBUTYI RADICAL MOPYI R" +
"ADICAL YOYI RADICAL PUTYI RADICAL HXUOYI RADICAL TATYI RADICAL GAYI RADI" +
"CAL ZUPYI RADICAL CYTYI RADICAL DDURYI RADICAL BURYI RADICAL GGUOYI RADI" +
"CAL NYOPYI RADICAL TUYI RADICAL OPYI RADICAL JJUTYI RADICAL ZOTYI RADICA" +
"L PYTYI RADICAL HMOYI RADICAL YITYI RADICAL VURYI RADICAL SHYYI RADICAL " +
"VEPYI RADICAL ZAYI RADICAL JOYI RADICAL NZUPYI RADICAL JJYYI RADICAL GOT" +
"YI RADICAL JJIEYI RADICAL WOYI RADICAL DUYI RADICAL SHURYI RADICAL LIEYI" +
" RADICAL CYYI RADICAL CUOPYI RADICAL CIPYI RADICAL HXOPYI RADICAL SHATYI" +
" RADICAL ZURYI RADICAL SHOPYI RADICAL CHEYI RADICAL ZZIETYI RADICAL NBIE" +
"YI RADICAL KELISU LETTER BALISU LETTER PALISU LETTER PHALISU LETTER DALI" +
"SU LETTER TALISU LETTER THALISU LETTER GALISU LETTER KALISU LETTER KHALI" +
"SU LETTER JALISU LETTER CALISU LETTER CHALISU LETTER DZALISU LETTER TSAL" +
"ISU LETTER TSHALISU LETTER MALISU LETTER NALISU LETTER LALISU LETTER SAL" +
"ISU LETTER ZHALISU LETTER ZALISU LETTER NGALISU LETTER HALISU LETTER XAL" +
"ISU LETTER HHALISU LETTER FALISU LETTER WALISU LETTER SHALISU LETTER YAL" +
"ISU LETTER GHALISU LETTER ALISU LETTER AELISU LETTER ELISU LETTER EULISU" +
" LETTER ILISU LETTER OLISU LETTER ULISU LETTER UELISU LETTER UHLISU LETT" +
"ER OELISU LETTER TONE MYA TILISU LETTER TONE NA POLISU LETTER TONE MYA C" +
"YALISU LETTER TONE MYA BOLISU LETTER TONE MYA NALISU LETTER TONE MYA JEU" +
"LISU PUNCTUATION COMMALISU PUNCTUATION FULL STOPVAI SYLLABLE EEVAI SYLLA" +
"BLE EENVAI SYLLABLE HEEVAI SYLLABLE WEEVAI SYLLABLE WEENVAI SYLLABLE PEE" +
"VAI SYLLABLE BHEEVAI SYLLABLE BEEVAI SYLLABLE MBEEVAI SYLLABLE KPEEVAI S" +
"YLLABLE MGBEEVAI SYLLABLE GBEEVAI SYLLABLE FEEVAI SYLLABLE VEEVAI SYLLAB" +
"LE TEEVAI SYLLABLE THEEVAI SYLLABLE DHEEVAI SYLLABLE DHHEEVAI SYLLABLE L" +
"EEVAI SYLLABLE REEVAI SYLLABLE DEEVAI SYLLABLE NDEEVAI SYLLABLE SEEVAI S" +
"YLLABLE SHEEVAI SYLLABLE ZEEVAI SYLLABLE ZHEEVAI SYLLABLE CEEVAI SYLLABL") + ("" +
"E JEEVAI SYLLABLE NJEEVAI SYLLABLE YEEVAI SYLLABLE KEEVAI SYLLABLE NGGEE" +
"VAI SYLLABLE GEEVAI SYLLABLE MEEVAI SYLLABLE NEEVAI SYLLABLE NYEEVAI SYL" +
"LABLE IVAI SYLLABLE INVAI SYLLABLE HIVAI SYLLABLE HINVAI SYLLABLE WIVAI " +
"SYLLABLE WINVAI SYLLABLE PIVAI SYLLABLE BHIVAI SYLLABLE BIVAI SYLLABLE M" +
"BIVAI SYLLABLE KPIVAI SYLLABLE MGBIVAI SYLLABLE GBIVAI SYLLABLE FIVAI SY" +
"LLABLE VIVAI SYLLABLE TIVAI SYLLABLE THIVAI SYLLABLE DHIVAI SYLLABLE DHH" +
"IVAI SYLLABLE LIVAI SYLLABLE RIVAI SYLLABLE DIVAI SYLLABLE NDIVAI SYLLAB" +
"LE SIVAI SYLLABLE SHIVAI SYLLABLE ZIVAI SYLLABLE ZHIVAI SYLLABLE CIVAI S" +
"YLLABLE JIVAI SYLLABLE NJIVAI SYLLABLE YIVAI SYLLABLE KIVAI SYLLABLE NGG" +
"IVAI SYLLABLE GIVAI SYLLABLE MIVAI SYLLABLE NIVAI SYLLABLE NYIVAI SYLLAB" +
"LE AVAI SYLLABLE ANVAI SYLLABLE NGANVAI SYLLABLE HAVAI SYLLABLE HANVAI S" +
"YLLABLE WAVAI SYLLABLE WANVAI SYLLABLE PAVAI SYLLABLE BHAVAI SYLLABLE BA" +
"VAI SYLLABLE MBAVAI SYLLABLE KPAVAI SYLLABLE KPANVAI SYLLABLE MGBAVAI SY" +
"LLABLE GBAVAI SYLLABLE FAVAI SYLLABLE VAVAI SYLLABLE TAVAI SYLLABLE THAV" +
"AI SYLLABLE DHAVAI SYLLABLE DHHAVAI SYLLABLE LAVAI SYLLABLE RAVAI SYLLAB" +
"LE DAVAI SYLLABLE NDAVAI SYLLABLE SAVAI SYLLABLE SHAVAI SYLLABLE ZAVAI S" +
"YLLABLE ZHAVAI SYLLABLE CAVAI SYLLABLE JAVAI SYLLABLE NJAVAI SYLLABLE YA" +
"VAI SYLLABLE KAVAI SYLLABLE KANVAI SYLLABLE NGGAVAI SYLLABLE GAVAI SYLLA" +
"BLE MAVAI SYLLABLE NAVAI SYLLABLE NYAVAI SYLLABLE OOVAI SYLLABLE OONVAI " +
"SYLLABLE HOOVAI SYLLABLE WOOVAI SYLLABLE WOONVAI SYLLABLE POOVAI SYLLABL" +
"E BHOOVAI SYLLABLE BOOVAI SYLLABLE MBOOVAI SYLLABLE KPOOVAI SYLLABLE MGB" +
"OOVAI SYLLABLE GBOOVAI SYLLABLE FOOVAI SYLLABLE VOOVAI SYLLABLE TOOVAI S" +
"YLLABLE THOOVAI SYLLABLE DHOOVAI SYLLABLE DHHOOVAI SYLLABLE LOOVAI SYLLA" +
"BLE ROOVAI SYLLABLE DOOVAI SYLLABLE NDOOVAI SYLLABLE SOOVAI SYLLABLE SHO" +
"OVAI SYLLABLE ZOOVAI SYLLABLE ZHOOVAI SYLLABLE COOVAI SYLLABLE JOOVAI SY" +
"LLABLE NJOOVAI SYLLABLE YOOVAI SYLLABLE KOOVAI SYLLABLE NGGOOVAI SYLLABL" +
"E GOOVAI SYLLABLE MOOVAI SYLLABLE NOOVAI SYLLABLE NYOOVAI SYLLABLE UVAI " +
"SYLLABLE UNVAI SYLLABLE HUVAI SYLLABLE HUNVAI SYLLABLE WUVAI SYLLABLE WU" +
"NVAI SYLLABLE PUVAI SYLLABLE BHUVAI SYLLABLE BUVAI SYLLABLE MBUVAI SYLLA" +
"BLE KPUVAI SYLLABLE MGBUVAI SYLLABLE GBUVAI SYLLABLE FUVAI SYLLABLE VUVA" +
"I SYLLABLE TUVAI SYLLABLE THUVAI SYLLABLE DHUVAI SYLLABLE DHHUVAI SYLLAB" +
"LE LUVAI SYLLABLE RUVAI SYLLABLE DUVAI SYLLABLE NDUVAI SYLLABLE SUVAI SY" +
"LLABLE SHUVAI SYLLABLE ZUVAI SYLLABLE ZHUVAI SYLLABLE CUVAI SYLLABLE JUV" +
"AI SYLLABLE NJUVAI SYLLABLE YUVAI SYLLABLE KUVAI SYLLABLE NGGUVAI SYLLAB" +
"LE GUVAI SYLLABLE MUVAI SYLLABLE NUVAI SYLLABLE NYUVAI SYLLABLE OVAI SYL" +
"LABLE ONVAI SYLLABLE NGONVAI SYLLABLE HOVAI SYLLABLE HONVAI SYLLABLE WOV" +
"AI SYLLABLE WONVAI SYLLABLE POVAI SYLLABLE BHOVAI SYLLABLE BOVAI SYLLABL" +
"E MBOVAI SYLLABLE KPOVAI SYLLABLE MGBOVAI SYLLABLE GBOVAI SYLLABLE GBONV" +
"AI SYLLABLE FOVAI SYLLABLE VOVAI SYLLABLE TOVAI SYLLABLE THOVAI SYLLABLE" +
" DHOVAI SYLLABLE DHHOVAI SYLLABLE LOVAI SYLLABLE ROVAI SYLLABLE DOVAI SY" +
"LLABLE NDOVAI SYLLABLE SOVAI SYLLABLE SHOVAI SYLLABLE ZOVAI SYLLABLE ZHO" +
"VAI SYLLABLE COVAI SYLLABLE JOVAI SYLLABLE NJOVAI SYLLABLE YOVAI SYLLABL" +
"E KOVAI SYLLABLE NGGOVAI SYLLABLE GOVAI SYLLABLE MOVAI SYLLABLE NOVAI SY" +
"LLABLE NYOVAI SYLLABLE EVAI SYLLABLE ENVAI SYLLABLE NGENVAI SYLLABLE HEV" +
"AI SYLLABLE HENVAI SYLLABLE WEVAI SYLLABLE WENVAI SYLLABLE PEVAI SYLLABL" +
"E BHEVAI SYLLABLE BEVAI SYLLABLE MBEVAI SYLLABLE KPEVAI SYLLABLE KPENVAI" +
" SYLLABLE MGBEVAI SYLLABLE GBEVAI SYLLABLE GBENVAI SYLLABLE FEVAI SYLLAB" +
"LE VEVAI SYLLABLE TEVAI SYLLABLE THEVAI SYLLABLE DHEVAI SYLLABLE DHHEVAI" +
" SYLLABLE LEVAI SYLLABLE REVAI SYLLABLE DEVAI SYLLABLE NDEVAI SYLLABLE S" +
"EVAI SYLLABLE SHEVAI SYLLABLE ZEVAI SYLLABLE ZHEVAI SYLLABLE CEVAI SYLLA" +
"BLE JEVAI SYLLABLE NJEVAI SYLLABLE YEVAI SYLLABLE KEVAI SYLLABLE NGGEVAI" +
" SYLLABLE NGGENVAI SYLLABLE GEVAI SYLLABLE GENVAI SYLLABLE MEVAI SYLLABL" +
"E NEVAI SYLLABLE NYEVAI SYLLABLE NGVAI SYLLABLE LENGTHENERVAI COMMAVAI F" +
"ULL STOPVAI QUESTION MARKVAI SYLLABLE NDOLE FAVAI SYLLABLE NDOLE KAVAI S" +
"YLLABLE NDOLE SOOVAI SYMBOL FEENGVAI SYMBOL KEENGVAI SYMBOL TINGVAI SYMB" +
"OL NIIVAI SYMBOL BANGVAI SYMBOL FAAVAI SYMBOL TAAVAI SYMBOL DANGVAI SYMB" +
"OL DOONGVAI SYMBOL KUNGVAI SYMBOL TONGVAI SYMBOL DO-OVAI SYMBOL JONGVAI " +
"DIGIT ZEROVAI DIGIT ONEVAI DIGIT TWOVAI DIGIT THREEVAI DIGIT FOURVAI DIG" +
"IT FIVEVAI DIGIT SIXVAI DIGIT SEVENVAI DIGIT EIGHTVAI DIGIT NINEVAI SYLL" +
"ABLE NDOLE MAVAI SYLLABLE NDOLE DOCYRILLIC CAPITAL LETTER ZEMLYACYRILLIC" +
" SMALL LETTER ZEMLYACYRILLIC CAPITAL LETTER DZELOCYRILLIC SMALL LETTER D" +
"ZELOCYRILLIC CAPITAL LETTER REVERSED DZECYRILLIC SMALL LETTER REVERSED D" +
"ZECYRILLIC CAPITAL LETTER IOTACYRILLIC SMALL LETTER IOTACYRILLIC CAPITAL" +
" LETTER DJERVCYRILLIC SMALL LETTER DJERVCYRILLIC CAPITAL LETTER MONOGRAP") + ("" +
"H UKCYRILLIC SMALL LETTER MONOGRAPH UKCYRILLIC CAPITAL LETTER BROAD OMEG" +
"ACYRILLIC SMALL LETTER BROAD OMEGACYRILLIC CAPITAL LETTER NEUTRAL YERCYR" +
"ILLIC SMALL LETTER NEUTRAL YERCYRILLIC CAPITAL LETTER YERU WITH BACK YER" +
"CYRILLIC SMALL LETTER YERU WITH BACK YERCYRILLIC CAPITAL LETTER IOTIFIED" +
" YATCYRILLIC SMALL LETTER IOTIFIED YATCYRILLIC CAPITAL LETTER REVERSED Y" +
"UCYRILLIC SMALL LETTER REVERSED YUCYRILLIC CAPITAL LETTER IOTIFIED ACYRI" +
"LLIC SMALL LETTER IOTIFIED ACYRILLIC CAPITAL LETTER CLOSED LITTLE YUSCYR" +
"ILLIC SMALL LETTER CLOSED LITTLE YUSCYRILLIC CAPITAL LETTER BLENDED YUSC" +
"YRILLIC SMALL LETTER BLENDED YUSCYRILLIC CAPITAL LETTER IOTIFIED CLOSED " +
"LITTLE YUSCYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUSCYRILLIC CAPIT" +
"AL LETTER YNCYRILLIC SMALL LETTER YNCYRILLIC CAPITAL LETTER REVERSED TSE" +
"CYRILLIC SMALL LETTER REVERSED TSECYRILLIC CAPITAL LETTER SOFT DECYRILLI" +
"C SMALL LETTER SOFT DECYRILLIC CAPITAL LETTER SOFT ELCYRILLIC SMALL LETT" +
"ER SOFT ELCYRILLIC CAPITAL LETTER SOFT EMCYRILLIC SMALL LETTER SOFT EMCY" +
"RILLIC CAPITAL LETTER MONOCULAR OCYRILLIC SMALL LETTER MONOCULAR OCYRILL" +
"IC CAPITAL LETTER BINOCULAR OCYRILLIC SMALL LETTER BINOCULAR OCYRILLIC C" +
"APITAL LETTER DOUBLE MONOCULAR OCYRILLIC SMALL LETTER DOUBLE MONOCULAR O" +
"CYRILLIC LETTER MULTIOCULAR OCOMBINING CYRILLIC VZMETCOMBINING CYRILLIC " +
"TEN MILLIONS SIGNCOMBINING CYRILLIC HUNDRED MILLIONS SIGNCOMBINING CYRIL" +
"LIC THOUSAND MILLIONS SIGNSLAVONIC ASTERISKCOMBINING CYRILLIC LETTER UKR" +
"AINIAN IECOMBINING CYRILLIC LETTER ICOMBINING CYRILLIC LETTER YICOMBININ" +
"G CYRILLIC LETTER UCOMBINING CYRILLIC LETTER HARD SIGNCOMBINING CYRILLIC" +
" LETTER YERUCOMBINING CYRILLIC LETTER SOFT SIGNCOMBINING CYRILLIC LETTER" +
" OMEGACOMBINING CYRILLIC KAVYKACOMBINING CYRILLIC PAYEROKCYRILLIC KAVYKA" +
"CYRILLIC PAYEROKCYRILLIC CAPITAL LETTER DWECYRILLIC SMALL LETTER DWECYRI" +
"LLIC CAPITAL LETTER DZWECYRILLIC SMALL LETTER DZWECYRILLIC CAPITAL LETTE" +
"R ZHWECYRILLIC SMALL LETTER ZHWECYRILLIC CAPITAL LETTER CCHECYRILLIC SMA" +
"LL LETTER CCHECYRILLIC CAPITAL LETTER DZZECYRILLIC SMALL LETTER DZZECYRI" +
"LLIC CAPITAL LETTER TE WITH MIDDLE HOOKCYRILLIC SMALL LETTER TE WITH MID" +
"DLE HOOKCYRILLIC CAPITAL LETTER TWECYRILLIC SMALL LETTER TWECYRILLIC CAP" +
"ITAL LETTER TSWECYRILLIC SMALL LETTER TSWECYRILLIC CAPITAL LETTER TSSECY" +
"RILLIC SMALL LETTER TSSECYRILLIC CAPITAL LETTER TCHECYRILLIC SMALL LETTE" +
"R TCHECYRILLIC CAPITAL LETTER HWECYRILLIC SMALL LETTER HWECYRILLIC CAPIT" +
"AL LETTER SHWECYRILLIC SMALL LETTER SHWECYRILLIC CAPITAL LETTER DOUBLE O" +
"CYRILLIC SMALL LETTER DOUBLE OCYRILLIC CAPITAL LETTER CROSSED OCYRILLIC " +
"SMALL LETTER CROSSED OMODIFIER LETTER CYRILLIC HARD SIGNMODIFIER LETTER " +
"CYRILLIC SOFT SIGNCOMBINING CYRILLIC LETTER EFCOMBINING CYRILLIC LETTER " +
"IOTIFIED EBAMUM LETTER ABAMUM LETTER KABAMUM LETTER UBAMUM LETTER KUBAMU" +
"M LETTER EEBAMUM LETTER REEBAMUM LETTER TAEBAMUM LETTER OBAMUM LETTER NY" +
"IBAMUM LETTER IBAMUM LETTER LABAMUM LETTER PABAMUM LETTER RIIBAMUM LETTE" +
"R RIEEBAMUM LETTER LEEEEBAMUM LETTER MEEEEBAMUM LETTER TAABAMUM LETTER N" +
"DAABAMUM LETTER NJAEMBAMUM LETTER MBAMUM LETTER SUUBAMUM LETTER MUBAMUM " +
"LETTER SHIIBAMUM LETTER SIBAMUM LETTER SHEUXBAMUM LETTER SEUXBAMUM LETTE" +
"R KYEEBAMUM LETTER KETBAMUM LETTER NUAEBAMUM LETTER NUBAMUM LETTER NJUAE" +
"BAMUM LETTER YOQBAMUM LETTER SHUBAMUM LETTER YUQBAMUM LETTER YABAMUM LET" +
"TER NSHABAMUM LETTER KEUXBAMUM LETTER PEUXBAMUM LETTER NJEEBAMUM LETTER " +
"NTEEBAMUM LETTER PUEBAMUM LETTER WUEBAMUM LETTER PEEBAMUM LETTER FEEBAMU" +
"M LETTER RUBAMUM LETTER LUBAMUM LETTER MIBAMUM LETTER NIBAMUM LETTER REU" +
"XBAMUM LETTER RAEBAMUM LETTER KENBAMUM LETTER NGKWAENBAMUM LETTER NGGABA" +
"MUM LETTER NGABAMUM LETTER SHOBAMUM LETTER PUAEBAMUM LETTER FUBAMUM LETT" +
"ER FOMBAMUM LETTER WABAMUM LETTER NABAMUM LETTER LIBAMUM LETTER PIBAMUM " +
"LETTER LOQBAMUM LETTER KOBAMUM LETTER MBENBAMUM LETTER RENBAMUM LETTER M" +
"ENBAMUM LETTER MABAMUM LETTER TIBAMUM LETTER KIBAMUM LETTER MOBAMUM LETT" +
"ER MBAABAMUM LETTER TETBAMUM LETTER KPABAMUM LETTER TENBAMUM LETTER NTUU" +
"BAMUM LETTER SAMBABAMUM LETTER FAAMAEBAMUM LETTER KOVUUBAMUM LETTER KOGH" +
"OMBAMUM COMBINING MARK KOQNDONBAMUM COMBINING MARK TUKWENTISBAMUM NJAEML" +
"IBAMUM FULL STOPBAMUM COLONBAMUM COMMABAMUM SEMICOLONBAMUM QUESTION MARK" +
"MODIFIER LETTER CHINESE TONE YIN PINGMODIFIER LETTER CHINESE TONE YANG P" +
"INGMODIFIER LETTER CHINESE TONE YIN SHANGMODIFIER LETTER CHINESE TONE YA" +
"NG SHANGMODIFIER LETTER CHINESE TONE YIN QUMODIFIER LETTER CHINESE TONE " +
"YANG QUMODIFIER LETTER CHINESE TONE YIN RUMODIFIER LETTER CHINESE TONE Y" +
"ANG RUMODIFIER LETTER EXTRA-HIGH DOTTED TONE BARMODIFIER LETTER HIGH DOT" +
"TED TONE BARMODIFIER LETTER MID DOTTED TONE BARMODIFIER LETTER LOW DOTTE" +
"D TONE BARMODIFIER LETTER EXTRA-LOW DOTTED TONE BARMODIFIER LETTER EXTRA") + ("" +
"-HIGH DOTTED LEFT-STEM TONE BARMODIFIER LETTER HIGH DOTTED LEFT-STEM TON" +
"E BARMODIFIER LETTER MID DOTTED LEFT-STEM TONE BARMODIFIER LETTER LOW DO" +
"TTED LEFT-STEM TONE BARMODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE B" +
"ARMODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BARMODIFIER LETTER HIGH LEFT" +
"-STEM TONE BARMODIFIER LETTER MID LEFT-STEM TONE BARMODIFIER LETTER LOW " +
"LEFT-STEM TONE BARMODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BARMODIFIER L" +
"ETTER DOT VERTICAL BARMODIFIER LETTER DOT SLASHMODIFIER LETTER DOT HORIZ" +
"ONTAL BARMODIFIER LETTER LOWER RIGHT CORNER ANGLEMODIFIER LETTER RAISED " +
"UP ARROWMODIFIER LETTER RAISED DOWN ARROWMODIFIER LETTER RAISED EXCLAMAT" +
"ION MARKMODIFIER LETTER RAISED INVERTED EXCLAMATION MARKMODIFIER LETTER " +
"LOW INVERTED EXCLAMATION MARKMODIFIER LETTER STRESS AND HIGH TONEMODIFIE" +
"R LETTER STRESS AND LOW TONELATIN CAPITAL LETTER EGYPTOLOGICAL ALEFLATIN" +
" SMALL LETTER EGYPTOLOGICAL ALEFLATIN CAPITAL LETTER EGYPTOLOGICAL AINLA" +
"TIN SMALL LETTER EGYPTOLOGICAL AINLATIN CAPITAL LETTER HENGLATIN SMALL L" +
"ETTER HENGLATIN CAPITAL LETTER TZLATIN SMALL LETTER TZLATIN CAPITAL LETT" +
"ER TRESILLOLATIN SMALL LETTER TRESILLOLATIN CAPITAL LETTER CUATRILLOLATI" +
"N SMALL LETTER CUATRILLOLATIN CAPITAL LETTER CUATRILLO WITH COMMALATIN S" +
"MALL LETTER CUATRILLO WITH COMMALATIN LETTER SMALL CAPITAL FLATIN LETTER" +
" SMALL CAPITAL SLATIN CAPITAL LETTER AALATIN SMALL LETTER AALATIN CAPITA" +
"L LETTER AOLATIN SMALL LETTER AOLATIN CAPITAL LETTER AULATIN SMALL LETTE" +
"R AULATIN CAPITAL LETTER AVLATIN SMALL LETTER AVLATIN CAPITAL LETTER AV " +
"WITH HORIZONTAL BARLATIN SMALL LETTER AV WITH HORIZONTAL BARLATIN CAPITA" +
"L LETTER AYLATIN SMALL LETTER AYLATIN CAPITAL LETTER REVERSED C WITH DOT" +
"LATIN SMALL LETTER REVERSED C WITH DOTLATIN CAPITAL LETTER K WITH STROKE" +
"LATIN SMALL LETTER K WITH STROKELATIN CAPITAL LETTER K WITH DIAGONAL STR" +
"OKELATIN SMALL LETTER K WITH DIAGONAL STROKELATIN CAPITAL LETTER K WITH " +
"STROKE AND DIAGONAL STROKELATIN SMALL LETTER K WITH STROKE AND DIAGONAL " +
"STROKELATIN CAPITAL LETTER BROKEN LLATIN SMALL LETTER BROKEN LLATIN CAPI" +
"TAL LETTER L WITH HIGH STROKELATIN SMALL LETTER L WITH HIGH STROKELATIN " +
"CAPITAL LETTER O WITH LONG STROKE OVERLAYLATIN SMALL LETTER O WITH LONG " +
"STROKE OVERLAYLATIN CAPITAL LETTER O WITH LOOPLATIN SMALL LETTER O WITH " +
"LOOPLATIN CAPITAL LETTER OOLATIN SMALL LETTER OOLATIN CAPITAL LETTER P W" +
"ITH STROKE THROUGH DESCENDERLATIN SMALL LETTER P WITH STROKE THROUGH DES" +
"CENDERLATIN CAPITAL LETTER P WITH FLOURISHLATIN SMALL LETTER P WITH FLOU" +
"RISHLATIN CAPITAL LETTER P WITH SQUIRREL TAILLATIN SMALL LETTER P WITH S" +
"QUIRREL TAILLATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDERLATIN SM" +
"ALL LETTER Q WITH STROKE THROUGH DESCENDERLATIN CAPITAL LETTER Q WITH DI" +
"AGONAL STROKELATIN SMALL LETTER Q WITH DIAGONAL STROKELATIN CAPITAL LETT" +
"ER R ROTUNDALATIN SMALL LETTER R ROTUNDALATIN CAPITAL LETTER RUM ROTUNDA" +
"LATIN SMALL LETTER RUM ROTUNDALATIN CAPITAL LETTER V WITH DIAGONAL STROK" +
"ELATIN SMALL LETTER V WITH DIAGONAL STROKELATIN CAPITAL LETTER VYLATIN S" +
"MALL LETTER VYLATIN CAPITAL LETTER VISIGOTHIC ZLATIN SMALL LETTER VISIGO" +
"THIC ZLATIN CAPITAL LETTER THORN WITH STROKELATIN SMALL LETTER THORN WIT" +
"H STROKELATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDERLATIN SM" +
"ALL LETTER THORN WITH STROKE THROUGH DESCENDERLATIN CAPITAL LETTER VENDL" +
"ATIN SMALL LETTER VENDLATIN CAPITAL LETTER ETLATIN SMALL LETTER ETLATIN " +
"CAPITAL LETTER ISLATIN SMALL LETTER ISLATIN CAPITAL LETTER CONLATIN SMAL" +
"L LETTER CONMODIFIER LETTER USLATIN SMALL LETTER DUMLATIN SMALL LETTER L" +
"UMLATIN SMALL LETTER MUMLATIN SMALL LETTER NUMLATIN SMALL LETTER RUMLATI" +
"N LETTER SMALL CAPITAL RUMLATIN SMALL LETTER TUMLATIN SMALL LETTER UMLAT" +
"IN CAPITAL LETTER INSULAR DLATIN SMALL LETTER INSULAR DLATIN CAPITAL LET" +
"TER INSULAR FLATIN SMALL LETTER INSULAR FLATIN CAPITAL LETTER INSULAR GL" +
"ATIN CAPITAL LETTER TURNED INSULAR GLATIN SMALL LETTER TURNED INSULAR GL" +
"ATIN CAPITAL LETTER TURNED LLATIN SMALL LETTER TURNED LLATIN CAPITAL LET" +
"TER INSULAR RLATIN SMALL LETTER INSULAR RLATIN CAPITAL LETTER INSULAR SL" +
"ATIN SMALL LETTER INSULAR SLATIN CAPITAL LETTER INSULAR TLATIN SMALL LET" +
"TER INSULAR TMODIFIER LETTER LOW CIRCUMFLEX ACCENTMODIFIER LETTER COLONM" +
"ODIFIER LETTER SHORT EQUALS SIGNLATIN CAPITAL LETTER SALTILLOLATIN SMALL" +
" LETTER SALTILLOLATIN CAPITAL LETTER TURNED HLATIN SMALL LETTER L WITH R" +
"ETROFLEX HOOK AND BELTLATIN LETTER SINOLOGICAL DOTLATIN CAPITAL LETTER N" +
" WITH DESCENDERLATIN SMALL LETTER N WITH DESCENDERLATIN CAPITAL LETTER C" +
" WITH BARLATIN SMALL LETTER C WITH BARLATIN SMALL LETTER C WITH PALATAL " +
"HOOKLATIN SMALL LETTER H WITH PALATAL HOOKLATIN CAPITAL LETTER B WITH FL" +
"OURISHLATIN SMALL LETTER B WITH FLOURISHLATIN CAPITAL LETTER F WITH STRO") + ("" +
"KELATIN SMALL LETTER F WITH STROKELATIN CAPITAL LETTER VOLAPUK AELATIN S" +
"MALL LETTER VOLAPUK AELATIN CAPITAL LETTER VOLAPUK OELATIN SMALL LETTER " +
"VOLAPUK OELATIN CAPITAL LETTER VOLAPUK UELATIN SMALL LETTER VOLAPUK UELA" +
"TIN CAPITAL LETTER G WITH OBLIQUE STROKELATIN SMALL LETTER G WITH OBLIQU" +
"E STROKELATIN CAPITAL LETTER K WITH OBLIQUE STROKELATIN SMALL LETTER K W" +
"ITH OBLIQUE STROKELATIN CAPITAL LETTER N WITH OBLIQUE STROKELATIN SMALL " +
"LETTER N WITH OBLIQUE STROKELATIN CAPITAL LETTER R WITH OBLIQUE STROKELA" +
"TIN SMALL LETTER R WITH OBLIQUE STROKELATIN CAPITAL LETTER S WITH OBLIQU" +
"E STROKELATIN SMALL LETTER S WITH OBLIQUE STROKELATIN CAPITAL LETTER H W" +
"ITH HOOKLATIN CAPITAL LETTER REVERSED OPEN ELATIN CAPITAL LETTER SCRIPT " +
"GLATIN CAPITAL LETTER L WITH BELTLATIN CAPITAL LETTER SMALL CAPITAL ILAT" +
"IN LETTER SMALL CAPITAL QLATIN CAPITAL LETTER TURNED KLATIN CAPITAL LETT" +
"ER TURNED TLATIN CAPITAL LETTER J WITH CROSSED-TAILLATIN CAPITAL LETTER " +
"CHILATIN CAPITAL LETTER BETALATIN SMALL LETTER BETALATIN CAPITAL LETTER " +
"OMEGALATIN SMALL LETTER OMEGALATIN CAPITAL LETTER U WITH STROKELATIN SMA" +
"LL LETTER U WITH STROKELATIN CAPITAL LETTER GLOTTAL ALATIN SMALL LETTER " +
"GLOTTAL ALATIN CAPITAL LETTER GLOTTAL ILATIN SMALL LETTER GLOTTAL ILATIN" +
" CAPITAL LETTER GLOTTAL ULATIN SMALL LETTER GLOTTAL ULATIN CAPITAL LETTE" +
"R OLD POLISH OLATIN SMALL LETTER OLD POLISH OLATIN CAPITAL LETTER ANGLIC" +
"ANA WLATIN SMALL LETTER ANGLICANA WLATIN CAPITAL LETTER C WITH PALATAL H" +
"OOKLATIN CAPITAL LETTER S WITH HOOKLATIN CAPITAL LETTER Z WITH PALATAL H" +
"OOKLATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAYLATIN SMALL LETTER D " +
"WITH SHORT STROKE OVERLAYLATIN CAPITAL LETTER S WITH SHORT STROKE OVERLA" +
"YLATIN SMALL LETTER S WITH SHORT STROKE OVERLAYLATIN CAPITAL LETTER RAMS" +
" HORNLATIN CAPITAL LETTER S WITH DIAGONAL STROKELATIN SMALL LETTER S WIT" +
"H DIAGONAL STROKELATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVELATIN S" +
"MALL LETTER PHARYNGEAL VOICED FRICATIVELATIN CAPITAL LETTER CLOSED INSUL" +
"AR GLATIN SMALL LETTER CLOSED INSULAR GLATIN CAPITAL LETTER DOUBLE THORN" +
"LATIN SMALL LETTER DOUBLE THORNLATIN CAPITAL LETTER DOUBLE WYNNLATIN SMA" +
"LL LETTER DOUBLE WYNNLATIN CAPITAL LETTER MIDDLE SCOTS SLATIN SMALL LETT" +
"ER MIDDLE SCOTS SLATIN CAPITAL LETTER SIGMOID SLATIN SMALL LETTER SIGMOI" +
"D SLATIN CAPITAL LETTER LAMBDALATIN SMALL LETTER LAMBDALATIN CAPITAL LET" +
"TER LAMBDA WITH STROKEMODIFIER LETTER CAPITAL SMODIFIER LETTER CAPITAL C" +
"MODIFIER LETTER CAPITAL FMODIFIER LETTER CAPITAL QLATIN CAPITAL LETTER R" +
"EVERSED HALF HLATIN SMALL LETTER REVERSED HALF HLATIN EPIGRAPHIC LETTER " +
"SIDEWAYS IMODIFIER LETTER CAPITAL H WITH STROKEMODIFIER LETTER SMALL LIG" +
"ATURE OELATIN LETTER SMALL CAPITAL TURNED MLATIN EPIGRAPHIC LETTER REVER" +
"SED FLATIN EPIGRAPHIC LETTER REVERSED PLATIN EPIGRAPHIC LETTER INVERTED " +
"MLATIN EPIGRAPHIC LETTER I LONGALATIN EPIGRAPHIC LETTER ARCHAIC MSYLOTI " +
"NAGRI LETTER ASYLOTI NAGRI LETTER ISYLOTI NAGRI SIGN DVISVARASYLOTI NAGR" +
"I LETTER USYLOTI NAGRI LETTER ESYLOTI NAGRI LETTER OSYLOTI NAGRI SIGN HA" +
"SANTASYLOTI NAGRI LETTER KOSYLOTI NAGRI LETTER KHOSYLOTI NAGRI LETTER GO" +
"SYLOTI NAGRI LETTER GHOSYLOTI NAGRI SIGN ANUSVARASYLOTI NAGRI LETTER COS" +
"YLOTI NAGRI LETTER CHOSYLOTI NAGRI LETTER JOSYLOTI NAGRI LETTER JHOSYLOT" +
"I NAGRI LETTER TTOSYLOTI NAGRI LETTER TTHOSYLOTI NAGRI LETTER DDOSYLOTI " +
"NAGRI LETTER DDHOSYLOTI NAGRI LETTER TOSYLOTI NAGRI LETTER THOSYLOTI NAG" +
"RI LETTER DOSYLOTI NAGRI LETTER DHOSYLOTI NAGRI LETTER NOSYLOTI NAGRI LE" +
"TTER POSYLOTI NAGRI LETTER PHOSYLOTI NAGRI LETTER BOSYLOTI NAGRI LETTER " +
"BHOSYLOTI NAGRI LETTER MOSYLOTI NAGRI LETTER ROSYLOTI NAGRI LETTER LOSYL" +
"OTI NAGRI LETTER RROSYLOTI NAGRI LETTER SOSYLOTI NAGRI LETTER HOSYLOTI N" +
"AGRI VOWEL SIGN ASYLOTI NAGRI VOWEL SIGN ISYLOTI NAGRI VOWEL SIGN USYLOT" +
"I NAGRI VOWEL SIGN ESYLOTI NAGRI VOWEL SIGN OOSYLOTI NAGRI POETRY MARK-1" +
"SYLOTI NAGRI POETRY MARK-2SYLOTI NAGRI POETRY MARK-3SYLOTI NAGRI POETRY " +
"MARK-4SYLOTI NAGRI SIGN ALTERNATE HASANTANORTH INDIC FRACTION ONE QUARTE" +
"RNORTH INDIC FRACTION ONE HALFNORTH INDIC FRACTION THREE QUARTERSNORTH I" +
"NDIC FRACTION ONE SIXTEENTHNORTH INDIC FRACTION ONE EIGHTHNORTH INDIC FR" +
"ACTION THREE SIXTEENTHSNORTH INDIC QUARTER MARKNORTH INDIC PLACEHOLDER M" +
"ARKNORTH INDIC RUPEE MARKNORTH INDIC QUANTITY MARKPHAGS-PA LETTER KAPHAG" +
"S-PA LETTER KHAPHAGS-PA LETTER GAPHAGS-PA LETTER NGAPHAGS-PA LETTER CAPH" +
"AGS-PA LETTER CHAPHAGS-PA LETTER JAPHAGS-PA LETTER NYAPHAGS-PA LETTER TA" +
"PHAGS-PA LETTER THAPHAGS-PA LETTER DAPHAGS-PA LETTER NAPHAGS-PA LETTER P" +
"APHAGS-PA LETTER PHAPHAGS-PA LETTER BAPHAGS-PA LETTER MAPHAGS-PA LETTER " +
"TSAPHAGS-PA LETTER TSHAPHAGS-PA LETTER DZAPHAGS-PA LETTER WAPHAGS-PA LET" +
"TER ZHAPHAGS-PA LETTER ZAPHAGS-PA LETTER SMALL APHAGS-PA LETTER YAPHAGS-") + ("" +
"PA LETTER RAPHAGS-PA LETTER LAPHAGS-PA LETTER SHAPHAGS-PA LETTER SAPHAGS" +
"-PA LETTER HAPHAGS-PA LETTER APHAGS-PA LETTER IPHAGS-PA LETTER UPHAGS-PA" +
" LETTER EPHAGS-PA LETTER OPHAGS-PA LETTER QAPHAGS-PA LETTER XAPHAGS-PA L" +
"ETTER FAPHAGS-PA LETTER GGAPHAGS-PA LETTER EEPHAGS-PA SUBJOINED LETTER W" +
"APHAGS-PA SUBJOINED LETTER YAPHAGS-PA LETTER TTAPHAGS-PA LETTER TTHAPHAG" +
"S-PA LETTER DDAPHAGS-PA LETTER NNAPHAGS-PA LETTER ALTERNATE YAPHAGS-PA L" +
"ETTER VOICELESS SHAPHAGS-PA LETTER VOICED HAPHAGS-PA LETTER ASPIRATED FA" +
"PHAGS-PA SUBJOINED LETTER RAPHAGS-PA SUPERFIXED LETTER RAPHAGS-PA LETTER" +
" CANDRABINDUPHAGS-PA SINGLE HEAD MARKPHAGS-PA DOUBLE HEAD MARKPHAGS-PA M" +
"ARK SHADPHAGS-PA MARK DOUBLE SHADSAURASHTRA SIGN ANUSVARASAURASHTRA SIGN" +
" VISARGASAURASHTRA LETTER ASAURASHTRA LETTER AASAURASHTRA LETTER ISAURAS" +
"HTRA LETTER IISAURASHTRA LETTER USAURASHTRA LETTER UUSAURASHTRA LETTER V" +
"OCALIC RSAURASHTRA LETTER VOCALIC RRSAURASHTRA LETTER VOCALIC LSAURASHTR" +
"A LETTER VOCALIC LLSAURASHTRA LETTER ESAURASHTRA LETTER EESAURASHTRA LET" +
"TER AISAURASHTRA LETTER OSAURASHTRA LETTER OOSAURASHTRA LETTER AUSAURASH" +
"TRA LETTER KASAURASHTRA LETTER KHASAURASHTRA LETTER GASAURASHTRA LETTER " +
"GHASAURASHTRA LETTER NGASAURASHTRA LETTER CASAURASHTRA LETTER CHASAURASH" +
"TRA LETTER JASAURASHTRA LETTER JHASAURASHTRA LETTER NYASAURASHTRA LETTER" +
" TTASAURASHTRA LETTER TTHASAURASHTRA LETTER DDASAURASHTRA LETTER DDHASAU" +
"RASHTRA LETTER NNASAURASHTRA LETTER TASAURASHTRA LETTER THASAURASHTRA LE" +
"TTER DASAURASHTRA LETTER DHASAURASHTRA LETTER NASAURASHTRA LETTER PASAUR" +
"ASHTRA LETTER PHASAURASHTRA LETTER BASAURASHTRA LETTER BHASAURASHTRA LET" +
"TER MASAURASHTRA LETTER YASAURASHTRA LETTER RASAURASHTRA LETTER LASAURAS" +
"HTRA LETTER VASAURASHTRA LETTER SHASAURASHTRA LETTER SSASAURASHTRA LETTE" +
"R SASAURASHTRA LETTER HASAURASHTRA LETTER LLASAURASHTRA CONSONANT SIGN H" +
"AARUSAURASHTRA VOWEL SIGN AASAURASHTRA VOWEL SIGN ISAURASHTRA VOWEL SIGN" +
" IISAURASHTRA VOWEL SIGN USAURASHTRA VOWEL SIGN UUSAURASHTRA VOWEL SIGN " +
"VOCALIC RSAURASHTRA VOWEL SIGN VOCALIC RRSAURASHTRA VOWEL SIGN VOCALIC L" +
"SAURASHTRA VOWEL SIGN VOCALIC LLSAURASHTRA VOWEL SIGN ESAURASHTRA VOWEL " +
"SIGN EESAURASHTRA VOWEL SIGN AISAURASHTRA VOWEL SIGN OSAURASHTRA VOWEL S" +
"IGN OOSAURASHTRA VOWEL SIGN AUSAURASHTRA SIGN VIRAMASAURASHTRA SIGN CAND" +
"RABINDUSAURASHTRA DANDASAURASHTRA DOUBLE DANDASAURASHTRA DIGIT ZEROSAURA" +
"SHTRA DIGIT ONESAURASHTRA DIGIT TWOSAURASHTRA DIGIT THREESAURASHTRA DIGI" +
"T FOURSAURASHTRA DIGIT FIVESAURASHTRA DIGIT SIXSAURASHTRA DIGIT SEVENSAU" +
"RASHTRA DIGIT EIGHTSAURASHTRA DIGIT NINECOMBINING DEVANAGARI DIGIT ZEROC" +
"OMBINING DEVANAGARI DIGIT ONECOMBINING DEVANAGARI DIGIT TWOCOMBINING DEV" +
"ANAGARI DIGIT THREECOMBINING DEVANAGARI DIGIT FOURCOMBINING DEVANAGARI D" +
"IGIT FIVECOMBINING DEVANAGARI DIGIT SIXCOMBINING DEVANAGARI DIGIT SEVENC" +
"OMBINING DEVANAGARI DIGIT EIGHTCOMBINING DEVANAGARI DIGIT NINECOMBINING " +
"DEVANAGARI LETTER ACOMBINING DEVANAGARI LETTER UCOMBINING DEVANAGARI LET" +
"TER KACOMBINING DEVANAGARI LETTER NACOMBINING DEVANAGARI LETTER PACOMBIN" +
"ING DEVANAGARI LETTER RACOMBINING DEVANAGARI LETTER VICOMBINING DEVANAGA" +
"RI SIGN AVAGRAHADEVANAGARI SIGN SPACING CANDRABINDUDEVANAGARI SIGN CANDR" +
"ABINDU VIRAMADEVANAGARI SIGN DOUBLE CANDRABINDU VIRAMADEVANAGARI SIGN CA" +
"NDRABINDU TWODEVANAGARI SIGN CANDRABINDU THREEDEVANAGARI SIGN CANDRABIND" +
"U AVAGRAHADEVANAGARI SIGN PUSHPIKADEVANAGARI GAP FILLERDEVANAGARI CARETD" +
"EVANAGARI HEADSTROKEDEVANAGARI SIGN SIDDHAMDEVANAGARI JAIN OMDEVANAGARI " +
"LETTER AYDEVANAGARI VOWEL SIGN AYKAYAH LI DIGIT ZEROKAYAH LI DIGIT ONEKA" +
"YAH LI DIGIT TWOKAYAH LI DIGIT THREEKAYAH LI DIGIT FOURKAYAH LI DIGIT FI" +
"VEKAYAH LI DIGIT SIXKAYAH LI DIGIT SEVENKAYAH LI DIGIT EIGHTKAYAH LI DIG" +
"IT NINEKAYAH LI LETTER KAKAYAH LI LETTER KHAKAYAH LI LETTER GAKAYAH LI L" +
"ETTER NGAKAYAH LI LETTER SAKAYAH LI LETTER SHAKAYAH LI LETTER ZAKAYAH LI" +
" LETTER NYAKAYAH LI LETTER TAKAYAH LI LETTER HTAKAYAH LI LETTER NAKAYAH " +
"LI LETTER PAKAYAH LI LETTER PHAKAYAH LI LETTER MAKAYAH LI LETTER DAKAYAH" +
" LI LETTER BAKAYAH LI LETTER RAKAYAH LI LETTER YAKAYAH LI LETTER LAKAYAH" +
" LI LETTER WAKAYAH LI LETTER THAKAYAH LI LETTER HAKAYAH LI LETTER VAKAYA" +
"H LI LETTER CAKAYAH LI LETTER AKAYAH LI LETTER OEKAYAH LI LETTER IKAYAH " +
"LI LETTER OOKAYAH LI VOWEL UEKAYAH LI VOWEL EKAYAH LI VOWEL UKAYAH LI VO" +
"WEL EEKAYAH LI VOWEL OKAYAH LI TONE PLOPHUKAYAH LI TONE CALYAKAYAH LI TO" +
"NE CALYA PLOPHUKAYAH LI SIGN CWIKAYAH LI SIGN SHYAREJANG LETTER KAREJANG" +
" LETTER GAREJANG LETTER NGAREJANG LETTER TAREJANG LETTER DAREJANG LETTER" +
" NAREJANG LETTER PAREJANG LETTER BAREJANG LETTER MAREJANG LETTER CAREJAN" +
"G LETTER JAREJANG LETTER NYAREJANG LETTER SAREJANG LETTER RAREJANG LETTE" +
"R LAREJANG LETTER YAREJANG LETTER WAREJANG LETTER HAREJANG LETTER MBAREJ") + ("" +
"ANG LETTER NGGAREJANG LETTER NDAREJANG LETTER NYJAREJANG LETTER AREJANG " +
"VOWEL SIGN IREJANG VOWEL SIGN UREJANG VOWEL SIGN EREJANG VOWEL SIGN AIRE" +
"JANG VOWEL SIGN OREJANG VOWEL SIGN AUREJANG VOWEL SIGN EUREJANG VOWEL SI" +
"GN EAREJANG CONSONANT SIGN NGREJANG CONSONANT SIGN NREJANG CONSONANT SIG" +
"N RREJANG CONSONANT SIGN HREJANG VIRAMAREJANG SECTION MARKHANGUL CHOSEON" +
"G TIKEUT-MIEUMHANGUL CHOSEONG TIKEUT-PIEUPHANGUL CHOSEONG TIKEUT-SIOSHAN" +
"GUL CHOSEONG TIKEUT-CIEUCHANGUL CHOSEONG RIEUL-KIYEOKHANGUL CHOSEONG RIE" +
"UL-SSANGKIYEOKHANGUL CHOSEONG RIEUL-TIKEUTHANGUL CHOSEONG RIEUL-SSANGTIK" +
"EUTHANGUL CHOSEONG RIEUL-MIEUMHANGUL CHOSEONG RIEUL-PIEUPHANGUL CHOSEONG" +
" RIEUL-SSANGPIEUPHANGUL CHOSEONG RIEUL-KAPYEOUNPIEUPHANGUL CHOSEONG RIEU" +
"L-SIOSHANGUL CHOSEONG RIEUL-CIEUCHANGUL CHOSEONG RIEUL-KHIEUKHHANGUL CHO" +
"SEONG MIEUM-KIYEOKHANGUL CHOSEONG MIEUM-TIKEUTHANGUL CHOSEONG MIEUM-SIOS" +
"HANGUL CHOSEONG PIEUP-SIOS-THIEUTHHANGUL CHOSEONG PIEUP-KHIEUKHHANGUL CH" +
"OSEONG PIEUP-HIEUHHANGUL CHOSEONG SSANGSIOS-PIEUPHANGUL CHOSEONG IEUNG-R" +
"IEULHANGUL CHOSEONG IEUNG-HIEUHHANGUL CHOSEONG SSANGCIEUC-HIEUHHANGUL CH" +
"OSEONG SSANGTHIEUTHHANGUL CHOSEONG PHIEUPH-HIEUHHANGUL CHOSEONG HIEUH-SI" +
"OSHANGUL CHOSEONG SSANGYEORINHIEUHJAVANESE SIGN PANYANGGAJAVANESE SIGN C" +
"ECAKJAVANESE SIGN LAYARJAVANESE SIGN WIGNYANJAVANESE LETTER AJAVANESE LE" +
"TTER I KAWIJAVANESE LETTER IJAVANESE LETTER IIJAVANESE LETTER UJAVANESE " +
"LETTER PA CEREKJAVANESE LETTER NGA LELETJAVANESE LETTER NGA LELET RASWAD" +
"IJAVANESE LETTER EJAVANESE LETTER AIJAVANESE LETTER OJAVANESE LETTER KAJ" +
"AVANESE LETTER KA SASAKJAVANESE LETTER KA MURDAJAVANESE LETTER GAJAVANES" +
"E LETTER GA MURDAJAVANESE LETTER NGAJAVANESE LETTER CAJAVANESE LETTER CA" +
" MURDAJAVANESE LETTER JAJAVANESE LETTER NYA MURDAJAVANESE LETTER JA MAHA" +
"PRANAJAVANESE LETTER NYAJAVANESE LETTER TTAJAVANESE LETTER TTA MAHAPRANA" +
"JAVANESE LETTER DDAJAVANESE LETTER DDA MAHAPRANAJAVANESE LETTER NA MURDA" +
"JAVANESE LETTER TAJAVANESE LETTER TA MURDAJAVANESE LETTER DAJAVANESE LET" +
"TER DA MAHAPRANAJAVANESE LETTER NAJAVANESE LETTER PAJAVANESE LETTER PA M" +
"URDAJAVANESE LETTER BAJAVANESE LETTER BA MURDAJAVANESE LETTER MAJAVANESE" +
" LETTER YAJAVANESE LETTER RAJAVANESE LETTER RA AGUNGJAVANESE LETTER LAJA" +
"VANESE LETTER WAJAVANESE LETTER SA MURDAJAVANESE LETTER SA MAHAPRANAJAVA" +
"NESE LETTER SAJAVANESE LETTER HAJAVANESE SIGN CECAK TELUJAVANESE VOWEL S" +
"IGN TARUNGJAVANESE VOWEL SIGN TOLONGJAVANESE VOWEL SIGN WULUJAVANESE VOW" +
"EL SIGN WULU MELIKJAVANESE VOWEL SIGN SUKUJAVANESE VOWEL SIGN SUKU MENDU" +
"TJAVANESE VOWEL SIGN TALINGJAVANESE VOWEL SIGN DIRGA MUREJAVANESE VOWEL " +
"SIGN PEPETJAVANESE CONSONANT SIGN KERETJAVANESE CONSONANT SIGN PENGKALJA" +
"VANESE CONSONANT SIGN CAKRAJAVANESE PANGKONJAVANESE LEFT RERENGGANJAVANE" +
"SE RIGHT RERENGGANJAVANESE PADA ANDAPJAVANESE PADA MADYAJAVANESE PADA LU" +
"HURJAVANESE PADA WINDUJAVANESE PADA PANGKATJAVANESE PADA LINGSAJAVANESE " +
"PADA LUNGSIJAVANESE PADA ADEGJAVANESE PADA ADEG ADEGJAVANESE PADA PISELE" +
"HJAVANESE TURNED PADA PISELEHJAVANESE PANGRANGKEPJAVANESE DIGIT ZEROJAVA" +
"NESE DIGIT ONEJAVANESE DIGIT TWOJAVANESE DIGIT THREEJAVANESE DIGIT FOURJ" +
"AVANESE DIGIT FIVEJAVANESE DIGIT SIXJAVANESE DIGIT SEVENJAVANESE DIGIT E" +
"IGHTJAVANESE DIGIT NINEJAVANESE PADA TIRTA TUMETESJAVANESE PADA ISEN-ISE" +
"NMYANMAR LETTER SHAN GHAMYANMAR LETTER SHAN CHAMYANMAR LETTER SHAN JHAMY" +
"ANMAR LETTER SHAN NNAMYANMAR LETTER SHAN BHAMYANMAR SIGN SHAN SAWMYANMAR" +
" MODIFIER LETTER SHAN REDUPLICATIONMYANMAR LETTER TAI LAING NYAMYANMAR L" +
"ETTER TAI LAING FAMYANMAR LETTER TAI LAING GAMYANMAR LETTER TAI LAING GH" +
"AMYANMAR LETTER TAI LAING JAMYANMAR LETTER TAI LAING JHAMYANMAR LETTER T" +
"AI LAING DDAMYANMAR LETTER TAI LAING DDHAMYANMAR LETTER TAI LAING NNAMYA" +
"NMAR TAI LAING DIGIT ZEROMYANMAR TAI LAING DIGIT ONEMYANMAR TAI LAING DI" +
"GIT TWOMYANMAR TAI LAING DIGIT THREEMYANMAR TAI LAING DIGIT FOURMYANMAR " +
"TAI LAING DIGIT FIVEMYANMAR TAI LAING DIGIT SIXMYANMAR TAI LAING DIGIT S" +
"EVENMYANMAR TAI LAING DIGIT EIGHTMYANMAR TAI LAING DIGIT NINEMYANMAR LET" +
"TER TAI LAING LLAMYANMAR LETTER TAI LAING DAMYANMAR LETTER TAI LAING DHA" +
"MYANMAR LETTER TAI LAING BAMYANMAR LETTER TAI LAING BHACHAM LETTER ACHAM" +
" LETTER ICHAM LETTER UCHAM LETTER ECHAM LETTER AICHAM LETTER OCHAM LETTE" +
"R KACHAM LETTER KHACHAM LETTER GACHAM LETTER GHACHAM LETTER NGUECHAM LET" +
"TER NGACHAM LETTER CHACHAM LETTER CHHACHAM LETTER JACHAM LETTER JHACHAM " +
"LETTER NHUECHAM LETTER NHACHAM LETTER NHJACHAM LETTER TACHAM LETTER THAC" +
"HAM LETTER DACHAM LETTER DHACHAM LETTER NUECHAM LETTER NACHAM LETTER DDA" +
"CHAM LETTER PACHAM LETTER PPACHAM LETTER PHACHAM LETTER BACHAM LETTER BH" +
"ACHAM LETTER MUECHAM LETTER MACHAM LETTER BBACHAM LETTER YACHAM LETTER R" +
"ACHAM LETTER LACHAM LETTER VACHAM LETTER SSACHAM LETTER SACHAM LETTER HA") + ("" +
"CHAM VOWEL SIGN AACHAM VOWEL SIGN ICHAM VOWEL SIGN IICHAM VOWEL SIGN EIC" +
"HAM VOWEL SIGN UCHAM VOWEL SIGN OECHAM VOWEL SIGN OCHAM VOWEL SIGN AICHA" +
"M VOWEL SIGN AUCHAM VOWEL SIGN UECHAM CONSONANT SIGN YACHAM CONSONANT SI" +
"GN RACHAM CONSONANT SIGN LACHAM CONSONANT SIGN WACHAM LETTER FINAL KCHAM" +
" LETTER FINAL GCHAM LETTER FINAL NGCHAM CONSONANT SIGN FINAL NGCHAM LETT" +
"ER FINAL CHCHAM LETTER FINAL TCHAM LETTER FINAL NCHAM LETTER FINAL PCHAM" +
" LETTER FINAL YCHAM LETTER FINAL RCHAM LETTER FINAL LCHAM LETTER FINAL S" +
"SCHAM CONSONANT SIGN FINAL MCHAM CONSONANT SIGN FINAL HCHAM DIGIT ZEROCH" +
"AM DIGIT ONECHAM DIGIT TWOCHAM DIGIT THREECHAM DIGIT FOURCHAM DIGIT FIVE" +
"CHAM DIGIT SIXCHAM DIGIT SEVENCHAM DIGIT EIGHTCHAM DIGIT NINECHAM PUNCTU" +
"ATION SPIRALCHAM PUNCTUATION DANDACHAM PUNCTUATION DOUBLE DANDACHAM PUNC" +
"TUATION TRIPLE DANDAMYANMAR LETTER KHAMTI GAMYANMAR LETTER KHAMTI CAMYAN" +
"MAR LETTER KHAMTI CHAMYANMAR LETTER KHAMTI JAMYANMAR LETTER KHAMTI JHAMY" +
"ANMAR LETTER KHAMTI NYAMYANMAR LETTER KHAMTI TTAMYANMAR LETTER KHAMTI TT" +
"HAMYANMAR LETTER KHAMTI DDAMYANMAR LETTER KHAMTI DDHAMYANMAR LETTER KHAM" +
"TI DHAMYANMAR LETTER KHAMTI NAMYANMAR LETTER KHAMTI SAMYANMAR LETTER KHA" +
"MTI HAMYANMAR LETTER KHAMTI HHAMYANMAR LETTER KHAMTI FAMYANMAR MODIFIER " +
"LETTER KHAMTI REDUPLICATIONMYANMAR LETTER KHAMTI XAMYANMAR LETTER KHAMTI" +
" ZAMYANMAR LETTER KHAMTI RAMYANMAR LOGOGRAM KHAMTI OAYMYANMAR LOGOGRAM K" +
"HAMTI QNMYANMAR LOGOGRAM KHAMTI HMMYANMAR SYMBOL AITON EXCLAMATIONMYANMA" +
"R SYMBOL AITON ONEMYANMAR SYMBOL AITON TWOMYANMAR LETTER AITON RAMYANMAR" +
" SIGN PAO KAREN TONEMYANMAR 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 LETTER LOW KHHOTAI VIET LETTER HIGH KHHOTAI VIE" +
"T LETTER LOW GOTAI VIET LETTER HIGH GOTAI VIET LETTER LOW NGOTAI VIET LE" +
"TTER HIGH NGOTAI VIET LETTER LOW COTAI VIET LETTER HIGH COTAI VIET LETTE" +
"R LOW CHOTAI VIET LETTER HIGH CHOTAI VIET LETTER LOW SOTAI VIET LETTER H" +
"IGH SOTAI VIET LETTER LOW NYOTAI VIET LETTER HIGH NYOTAI VIET LETTER LOW" +
" DOTAI VIET LETTER HIGH DOTAI VIET LETTER LOW TOTAI VIET LETTER HIGH TOT" +
"AI VIET LETTER LOW THOTAI VIET LETTER HIGH THOTAI VIET LETTER LOW NOTAI " +
"VIET LETTER HIGH NOTAI VIET LETTER LOW BOTAI VIET LETTER HIGH BOTAI VIET" +
" LETTER LOW POTAI VIET LETTER HIGH POTAI VIET LETTER LOW PHOTAI VIET LET" +
"TER HIGH PHOTAI VIET LETTER LOW FOTAI VIET LETTER HIGH FOTAI VIET LETTER" +
" LOW MOTAI VIET LETTER HIGH MOTAI VIET LETTER LOW YOTAI VIET LETTER HIGH" +
" YOTAI VIET LETTER LOW ROTAI VIET LETTER HIGH ROTAI VIET LETTER LOW LOTA" +
"I VIET LETTER HIGH LOTAI VIET LETTER LOW VOTAI VIET LETTER HIGH VOTAI VI" +
"ET LETTER LOW HOTAI VIET LETTER HIGH HOTAI VIET LETTER LOW OTAI VIET LET" +
"TER HIGH OTAI VIET MAI KANGTAI VIET VOWEL AATAI VIET VOWEL ITAI VIET VOW" +
"EL UETAI VIET VOWEL UTAI VIET VOWEL ETAI VIET VOWEL OTAI VIET MAI KHITTA" +
"I VIET VOWEL IATAI VIET VOWEL UEATAI VIET VOWEL UATAI VIET VOWEL AUETAI " +
"VIET VOWEL AYTAI VIET VOWEL ANTAI VIET VOWEL AMTAI VIET TONE MAI EKTAI V" +
"IET TONE MAI NUENGTAI VIET TONE MAI THOTAI VIET TONE MAI SONGTAI VIET SY" +
"MBOL KONTAI VIET SYMBOL NUENGTAI VIET SYMBOL SAMTAI VIET SYMBOL HO HOITA" +
"I VIET SYMBOL KOI KOIMEETEI MAYEK LETTER EMEETEI MAYEK LETTER OMEETEI MA" +
"YEK LETTER CHAMEETEI MAYEK LETTER NYAMEETEI MAYEK LETTER TTAMEETEI MAYEK" +
" LETTER TTHAMEETEI MAYEK LETTER DDAMEETEI MAYEK LETTER DDHAMEETEI MAYEK " +
"LETTER NNAMEETEI MAYEK LETTER SHAMEETEI MAYEK LETTER SSAMEETEI MAYEK VOW" +
"EL SIGN IIMEETEI MAYEK VOWEL SIGN UUMEETEI MAYEK VOWEL SIGN AAIMEETEI MA" +
"YEK VOWEL SIGN AUMEETEI MAYEK VOWEL SIGN AAUMEETEI MAYEK CHEIKHANMEETEI " +
"MAYEK AHANG KHUDAMMEETEI MAYEK ANJIMEETEI MAYEK SYLLABLE REPETITION MARK" +
"MEETEI MAYEK WORD REPETITION MARKMEETEI MAYEK VOWEL SIGN VISARGAMEETEI M" +
"AYEK VIRAMAETHIOPIC SYLLABLE TTHUETHIOPIC SYLLABLE TTHIETHIOPIC SYLLABLE" +
" TTHAAETHIOPIC SYLLABLE TTHEEETHIOPIC SYLLABLE TTHEETHIOPIC SYLLABLE TTH" +
"OETHIOPIC SYLLABLE DDHUETHIOPIC SYLLABLE DDHIETHIOPIC SYLLABLE DDHAAETHI" +
"OPIC SYLLABLE DDHEEETHIOPIC SYLLABLE DDHEETHIOPIC SYLLABLE DDHOETHIOPIC " +
"SYLLABLE DZUETHIOPIC SYLLABLE DZIETHIOPIC SYLLABLE DZAAETHIOPIC SYLLABLE" +
" DZEEETHIOPIC SYLLABLE DZEETHIOPIC SYLLABLE DZOETHIOPIC SYLLABLE CCHHAET" +
"HIOPIC SYLLABLE CCHHUETHIOPIC SYLLABLE CCHHIETHIOPIC SYLLABLE CCHHAAETHI" +
"OPIC SYLLABLE CCHHEEETHIOPIC SYLLABLE CCHHEETHIOPIC SYLLABLE CCHHOETHIOP" +
"IC SYLLABLE BBAETHIOPIC SYLLABLE BBUETHIOPIC SYLLABLE BBIETHIOPIC SYLLAB" +
"LE BBAAETHIOPIC SYLLABLE BBEEETHIOPIC SYLLABLE BBEETHIOPIC SYLLABLE BBOL" +
"ATIN SMALL LETTER BARRED ALPHALATIN SMALL LETTER A REVERSED-SCHWALATIN S" +
"MALL LETTER BLACKLETTER ELATIN SMALL LETTER BARRED ELATIN SMALL LETTER E") + ("" +
" WITH FLOURISHLATIN SMALL LETTER LENIS FLATIN SMALL LETTER SCRIPT G WITH" +
" CROSSED-TAILLATIN SMALL LETTER L WITH INVERTED LAZY SLATIN SMALL LETTER" +
" L WITH DOUBLE MIDDLE TILDELATIN SMALL LETTER L WITH MIDDLE RINGLATIN SM" +
"ALL LETTER M WITH CROSSED-TAILLATIN SMALL LETTER N WITH CROSSED-TAILLATI" +
"N SMALL LETTER ENG WITH CROSSED-TAILLATIN SMALL LETTER BLACKLETTER OLATI" +
"N SMALL LETTER BLACKLETTER O WITH STROKELATIN SMALL LETTER OPEN O WITH S" +
"TROKELATIN SMALL LETTER INVERTED OELATIN SMALL LETTER TURNED OE WITH STR" +
"OKELATIN SMALL LETTER TURNED OE WITH HORIZONTAL STROKELATIN SMALL LETTER" +
" TURNED O OPEN-OLATIN SMALL LETTER TURNED O OPEN-O WITH STROKELATIN SMAL" +
"L LETTER STIRRUP RLATIN LETTER SMALL CAPITAL R WITH RIGHT LEGLATIN SMALL" +
" LETTER R WITHOUT HANDLELATIN SMALL LETTER DOUBLE RLATIN SMALL LETTER R " +
"WITH CROSSED-TAILLATIN SMALL LETTER DOUBLE R WITH CROSSED-TAILLATIN SMAL" +
"L LETTER SCRIPT RLATIN SMALL LETTER SCRIPT R WITH RINGLATIN SMALL LETTER" +
" BASELINE ESHLATIN SMALL LETTER U WITH SHORT RIGHT LEGLATIN SMALL LETTER" +
" U BAR WITH SHORT RIGHT LEGLATIN SMALL LETTER UILATIN SMALL LETTER TURNE" +
"D UILATIN SMALL LETTER U WITH LEFT HOOKLATIN SMALL LETTER CHILATIN SMALL" +
" LETTER CHI WITH LOW RIGHT RINGLATIN SMALL LETTER CHI WITH LOW LEFT SERI" +
"FLATIN 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 LEFT LEG WITH SERIFLATIN SMALL LETTER Y WITH SH" +
"ORT RIGHT LEGMODIFIER BREVE WITH INVERTED BREVEMODIFIER LETTER SMALL HEN" +
"GMODIFIER LETTER SMALL L WITH INVERTED LAZY SMODIFIER LETTER SMALL L WIT" +
"H MIDDLE TILDEMODIFIER LETTER SMALL U WITH LEFT HOOKLATIN SMALL LETTER S" +
"AKHA YATLATIN SMALL LETTER IOTIFIED ELATIN SMALL LETTER OPEN OELATIN SMA" +
"LL LETTER UOLATIN SMALL LETTER 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 T" +
"ILDEMODIFIER LETTER SMALL TURNED WMODIFIER LETTER LEFT TACKMODIFIER LETT" +
"ER RIGHT TACKCHEROKEE SMALL LETTER ACHEROKEE SMALL LETTER ECHEROKEE SMAL" +
"L LETTER ICHEROKEE SMALL LETTER OCHEROKEE SMALL LETTER UCHEROKEE SMALL L" +
"ETTER VCHEROKEE SMALL LETTER GACHEROKEE SMALL LETTER KACHEROKEE SMALL LE" +
"TTER GECHEROKEE SMALL LETTER GICHEROKEE SMALL LETTER GOCHEROKEE SMALL LE" +
"TTER GUCHEROKEE SMALL LETTER GVCHEROKEE SMALL LETTER HACHEROKEE SMALL LE" +
"TTER HECHEROKEE SMALL LETTER HICHEROKEE SMALL LETTER HOCHEROKEE SMALL LE" +
"TTER HUCHEROKEE SMALL LETTER HVCHEROKEE SMALL LETTER LACHEROKEE SMALL LE" +
"TTER LECHEROKEE SMALL LETTER LICHEROKEE SMALL LETTER LOCHEROKEE SMALL LE" +
"TTER LUCHEROKEE SMALL LETTER LVCHEROKEE SMALL LETTER MACHEROKEE SMALL LE" +
"TTER MECHEROKEE SMALL LETTER MICHEROKEE SMALL LETTER MOCHEROKEE SMALL LE" +
"TTER MUCHEROKEE SMALL LETTER NACHEROKEE SMALL LETTER HNACHEROKEE SMALL L" +
"ETTER NAHCHEROKEE SMALL LETTER NECHEROKEE SMALL LETTER NICHEROKEE SMALL " +
"LETTER NOCHEROKEE SMALL LETTER NUCHEROKEE SMALL LETTER NVCHEROKEE SMALL " +
"LETTER QUACHEROKEE SMALL LETTER QUECHEROKEE SMALL LETTER QUICHEROKEE SMA" +
"LL LETTER QUOCHEROKEE SMALL LETTER QUUCHEROKEE SMALL LETTER QUVCHEROKEE " +
"SMALL LETTER SACHEROKEE SMALL LETTER SCHEROKEE SMALL LETTER SECHEROKEE S" +
"MALL LETTER SICHEROKEE SMALL LETTER SOCHEROKEE SMALL LETTER SUCHEROKEE S" +
"MALL LETTER SVCHEROKEE SMALL LETTER DACHEROKEE SMALL LETTER TACHEROKEE S" +
"MALL LETTER DECHEROKEE SMALL LETTER TECHEROKEE SMALL LETTER DICHEROKEE S" +
"MALL LETTER TICHEROKEE SMALL LETTER DOCHEROKEE SMALL LETTER DUCHEROKEE S" +
"MALL LETTER DVCHEROKEE SMALL LETTER DLACHEROKEE SMALL LETTER TLACHEROKEE" +
" SMALL LETTER TLECHEROKEE SMALL LETTER TLICHEROKEE SMALL LETTER TLOCHERO" +
"KEE SMALL LETTER TLUCHEROKEE SMALL LETTER TLVCHEROKEE SMALL LETTER TSACH" +
"EROKEE SMALL LETTER TSECHEROKEE SMALL LETTER TSICHEROKEE SMALL LETTER TS" +
"OCHEROKEE SMALL LETTER TSUCHEROKEE SMALL LETTER TSVCHEROKEE SMALL LETTER" +
" WACHEROKEE SMALL LETTER WECHEROKEE SMALL LETTER WICHEROKEE SMALL LETTER" +
" WOCHEROKEE SMALL LETTER WUCHEROKEE SMALL LETTER WVCHEROKEE SMALL LETTER" +
" YAMEETEI MAYEK LETTER KOKMEETEI MAYEK LETTER SAMMEETEI MAYEK LETTER LAI" +
"MEETEI MAYEK LETTER MITMEETEI MAYEK LETTER PAMEETEI MAYEK LETTER NAMEETE" +
"I MAYEK LETTER CHILMEETEI MAYEK LETTER TILMEETEI MAYEK LETTER KHOUMEETEI" +
" MAYEK LETTER NGOUMEETEI MAYEK LETTER THOUMEETEI MAYEK LETTER WAIMEETEI " +
"MAYEK LETTER YANGMEETEI MAYEK LETTER HUKMEETEI MAYEK LETTER UNMEETEI MAY" +
"EK LETTER IMEETEI MAYEK LETTER PHAMMEETEI MAYEK LETTER ATIYAMEETEI MAYEK" +
" LETTER GOKMEETEI MAYEK LETTER JHAMMEETEI MAYEK LETTER RAIMEETEI MAYEK L" +
"ETTER BAMEETEI MAYEK LETTER JILMEETEI MAYEK LETTER DILMEETEI MAYEK LETTE" +
"R GHOUMEETEI MAYEK LETTER DHOUMEETEI MAYEK LETTER BHAMMEETEI MAYEK LETTE") + ("" +
"R KOK LONSUMMEETEI MAYEK LETTER LAI LONSUMMEETEI MAYEK LETTER MIT LONSUM" +
"MEETEI MAYEK LETTER PA LONSUMMEETEI MAYEK LETTER NA LONSUMMEETEI MAYEK L" +
"ETTER TIL LONSUMMEETEI MAYEK LETTER NGOU LONSUMMEETEI MAYEK LETTER I LON" +
"SUMMEETEI MAYEK VOWEL SIGN ONAPMEETEI MAYEK VOWEL SIGN INAPMEETEI MAYEK " +
"VOWEL SIGN ANAPMEETEI MAYEK VOWEL SIGN YENAPMEETEI MAYEK VOWEL SIGN SOUN" +
"APMEETEI MAYEK VOWEL SIGN UNAPMEETEI MAYEK VOWEL SIGN CHEINAPMEETEI MAYE" +
"K VOWEL SIGN NUNGMEETEI MAYEK CHEIKHEIMEETEI MAYEK LUM IYEKMEETEI MAYEK " +
"APUN IYEKMEETEI MAYEK DIGIT ZEROMEETEI MAYEK DIGIT ONEMEETEI MAYEK DIGIT" +
" TWOMEETEI MAYEK DIGIT THREEMEETEI MAYEK DIGIT FOURMEETEI MAYEK DIGIT FI" +
"VEMEETEI MAYEK DIGIT SIXMEETEI MAYEK DIGIT SEVENMEETEI MAYEK DIGIT EIGHT" +
"MEETEI MAYEK DIGIT NINEHANGUL JUNGSEONG O-YEOHANGUL JUNGSEONG O-O-IHANGU" +
"L JUNGSEONG YO-AHANGUL JUNGSEONG YO-AEHANGUL JUNGSEONG YO-EOHANGUL JUNGS" +
"EONG U-YEOHANGUL JUNGSEONG U-I-IHANGUL JUNGSEONG YU-AEHANGUL JUNGSEONG Y" +
"U-OHANGUL JUNGSEONG EU-AHANGUL JUNGSEONG EU-EOHANGUL JUNGSEONG EU-EHANGU" +
"L JUNGSEONG EU-OHANGUL JUNGSEONG I-YA-OHANGUL JUNGSEONG I-YAEHANGUL JUNG" +
"SEONG I-YEOHANGUL JUNGSEONG I-YEHANGUL JUNGSEONG I-O-IHANGUL JUNGSEONG I" +
"-YOHANGUL JUNGSEONG I-YUHANGUL JUNGSEONG I-IHANGUL JUNGSEONG ARAEA-AHANG" +
"UL JUNGSEONG ARAEA-EHANGUL JONGSEONG NIEUN-RIEULHANGUL JONGSEONG NIEUN-C" +
"HIEUCHHANGUL JONGSEONG SSANGTIKEUTHANGUL JONGSEONG SSANGTIKEUT-PIEUPHANG" +
"UL JONGSEONG TIKEUT-PIEUPHANGUL JONGSEONG TIKEUT-SIOSHANGUL JONGSEONG TI" +
"KEUT-SIOS-KIYEOKHANGUL JONGSEONG TIKEUT-CIEUCHANGUL JONGSEONG TIKEUT-CHI" +
"EUCHHANGUL JONGSEONG TIKEUT-THIEUTHHANGUL JONGSEONG RIEUL-SSANGKIYEOKHAN" +
"GUL JONGSEONG RIEUL-KIYEOK-HIEUHHANGUL JONGSEONG SSANGRIEUL-KHIEUKHHANGU" +
"L JONGSEONG RIEUL-MIEUM-HIEUHHANGUL JONGSEONG RIEUL-PIEUP-TIKEUTHANGUL J" +
"ONGSEONG RIEUL-PIEUP-PHIEUPHHANGUL JONGSEONG RIEUL-YESIEUNGHANGUL JONGSE" +
"ONG RIEUL-YEORINHIEUH-HIEUHHANGUL JONGSEONG KAPYEOUNRIEULHANGUL JONGSEON" +
"G MIEUM-NIEUNHANGUL JONGSEONG MIEUM-SSANGNIEUNHANGUL JONGSEONG SSANGMIEU" +
"MHANGUL JONGSEONG MIEUM-PIEUP-SIOSHANGUL JONGSEONG MIEUM-CIEUCHANGUL JON" +
"GSEONG PIEUP-TIKEUTHANGUL JONGSEONG PIEUP-RIEUL-PHIEUPHHANGUL JONGSEONG " +
"PIEUP-MIEUMHANGUL JONGSEONG SSANGPIEUPHANGUL JONGSEONG PIEUP-SIOS-TIKEUT" +
"HANGUL JONGSEONG PIEUP-CIEUCHANGUL JONGSEONG PIEUP-CHIEUCHHANGUL JONGSEO" +
"NG SIOS-MIEUMHANGUL JONGSEONG SIOS-KAPYEOUNPIEUPHANGUL JONGSEONG SSANGSI" +
"OS-KIYEOKHANGUL JONGSEONG SSANGSIOS-TIKEUTHANGUL JONGSEONG SIOS-PANSIOSH" +
"ANGUL JONGSEONG SIOS-CIEUCHANGUL JONGSEONG SIOS-CHIEUCHHANGUL JONGSEONG " +
"SIOS-THIEUTHHANGUL JONGSEONG SIOS-HIEUHHANGUL JONGSEONG PANSIOS-PIEUPHAN" +
"GUL JONGSEONG PANSIOS-KAPYEOUNPIEUPHANGUL JONGSEONG YESIEUNG-MIEUMHANGUL" +
" JONGSEONG YESIEUNG-HIEUHHANGUL JONGSEONG CIEUC-PIEUPHANGUL JONGSEONG CI" +
"EUC-SSANGPIEUPHANGUL JONGSEONG SSANGCIEUCHANGUL JONGSEONG PHIEUPH-SIOSHA" +
"NGUL JONGSEONG PHIEUPH-THIEUTHCJK COMPATIBILITY IDEOGRAPH-F900CJK COMPAT" +
"IBILITY IDEOGRAPH-F901CJK COMPATIBILITY IDEOGRAPH-F902CJK COMPATIBILITY " +
"IDEOGRAPH-F903CJK COMPATIBILITY IDEOGRAPH-F904CJK COMPATIBILITY IDEOGRAP" +
"H-F905CJK COMPATIBILITY IDEOGRAPH-F906CJK COMPATIBILITY IDEOGRAPH-F907CJ" +
"K COMPATIBILITY IDEOGRAPH-F908CJK COMPATIBILITY IDEOGRAPH-F909CJK COMPAT" +
"IBILITY IDEOGRAPH-F90ACJK COMPATIBILITY IDEOGRAPH-F90BCJK COMPATIBILITY " +
"IDEOGRAPH-F90CCJK COMPATIBILITY IDEOGRAPH-F90DCJK COMPATIBILITY IDEOGRAP" +
"H-F90ECJK COMPATIBILITY IDEOGRAPH-F90FCJK COMPATIBILITY IDEOGRAPH-F910CJ" +
"K COMPATIBILITY IDEOGRAPH-F911CJK COMPATIBILITY IDEOGRAPH-F912CJK COMPAT" +
"IBILITY IDEOGRAPH-F913CJK COMPATIBILITY IDEOGRAPH-F914CJK COMPATIBILITY " +
"IDEOGRAPH-F915CJK COMPATIBILITY IDEOGRAPH-F916CJK COMPATIBILITY IDEOGRAP" +
"H-F917CJK COMPATIBILITY IDEOGRAPH-F918CJK COMPATIBILITY IDEOGRAPH-F919CJ" +
"K COMPATIBILITY IDEOGRAPH-F91ACJK COMPATIBILITY IDEOGRAPH-F91BCJK COMPAT" +
"IBILITY IDEOGRAPH-F91CCJK COMPATIBILITY IDEOGRAPH-F91DCJK COMPATIBILITY " +
"IDEOGRAPH-F91ECJK COMPATIBILITY IDEOGRAPH-F91FCJK COMPATIBILITY IDEOGRAP" +
"H-F920CJK COMPATIBILITY IDEOGRAPH-F921CJK COMPATIBILITY IDEOGRAPH-F922CJ" +
"K COMPATIBILITY IDEOGRAPH-F923CJK COMPATIBILITY IDEOGRAPH-F924CJK COMPAT" +
"IBILITY IDEOGRAPH-F925CJK COMPATIBILITY IDEOGRAPH-F926CJK COMPATIBILITY " +
"IDEOGRAPH-F927CJK COMPATIBILITY IDEOGRAPH-F928CJK COMPATIBILITY IDEOGRAP" +
"H-F929CJK COMPATIBILITY IDEOGRAPH-F92ACJK COMPATIBILITY IDEOGRAPH-F92BCJ" +
"K COMPATIBILITY IDEOGRAPH-F92CCJK COMPATIBILITY IDEOGRAPH-F92DCJK COMPAT" +
"IBILITY IDEOGRAPH-F92ECJK COMPATIBILITY IDEOGRAPH-F92FCJK COMPATIBILITY " +
"IDEOGRAPH-F930CJK COMPATIBILITY IDEOGRAPH-F931CJK COMPATIBILITY IDEOGRAP" +
"H-F932CJK COMPATIBILITY IDEOGRAPH-F933CJK COMPATIBILITY IDEOGRAPH-F934CJ" +
"K COMPATIBILITY IDEOGRAPH-F935CJK COMPATIBILITY IDEOGRAPH-F936CJK COMPAT" +
"IBILITY IDEOGRAPH-F937CJK COMPATIBILITY IDEOGRAPH-F938CJK COMPATIBILITY ") + ("" +
"IDEOGRAPH-F939CJK COMPATIBILITY IDEOGRAPH-F93ACJK COMPATIBILITY IDEOGRAP" +
"H-F93BCJK COMPATIBILITY IDEOGRAPH-F93CCJK COMPATIBILITY IDEOGRAPH-F93DCJ" +
"K COMPATIBILITY IDEOGRAPH-F93ECJK COMPATIBILITY IDEOGRAPH-F93FCJK COMPAT" +
"IBILITY IDEOGRAPH-F940CJK COMPATIBILITY IDEOGRAPH-F941CJK COMPATIBILITY " +
"IDEOGRAPH-F942CJK COMPATIBILITY IDEOGRAPH-F943CJK COMPATIBILITY IDEOGRAP" +
"H-F944CJK COMPATIBILITY IDEOGRAPH-F945CJK COMPATIBILITY IDEOGRAPH-F946CJ" +
"K COMPATIBILITY IDEOGRAPH-F947CJK COMPATIBILITY IDEOGRAPH-F948CJK COMPAT" +
"IBILITY IDEOGRAPH-F949CJK COMPATIBILITY IDEOGRAPH-F94ACJK COMPATIBILITY " +
"IDEOGRAPH-F94BCJK COMPATIBILITY IDEOGRAPH-F94CCJK COMPATIBILITY IDEOGRAP" +
"H-F94DCJK COMPATIBILITY IDEOGRAPH-F94ECJK COMPATIBILITY IDEOGRAPH-F94FCJ" +
"K COMPATIBILITY IDEOGRAPH-F950CJK COMPATIBILITY IDEOGRAPH-F951CJK COMPAT" +
"IBILITY IDEOGRAPH-F952CJK COMPATIBILITY IDEOGRAPH-F953CJK COMPATIBILITY " +
"IDEOGRAPH-F954CJK COMPATIBILITY IDEOGRAPH-F955CJK COMPATIBILITY IDEOGRAP" +
"H-F956CJK COMPATIBILITY IDEOGRAPH-F957CJK COMPATIBILITY IDEOGRAPH-F958CJ" +
"K COMPATIBILITY IDEOGRAPH-F959CJK COMPATIBILITY IDEOGRAPH-F95ACJK COMPAT" +
"IBILITY IDEOGRAPH-F95BCJK COMPATIBILITY IDEOGRAPH-F95CCJK COMPATIBILITY " +
"IDEOGRAPH-F95DCJK COMPATIBILITY IDEOGRAPH-F95ECJK COMPATIBILITY IDEOGRAP" +
"H-F95FCJK COMPATIBILITY IDEOGRAPH-F960CJK COMPATIBILITY IDEOGRAPH-F961CJ" +
"K COMPATIBILITY IDEOGRAPH-F962CJK COMPATIBILITY IDEOGRAPH-F963CJK COMPAT" +
"IBILITY IDEOGRAPH-F964CJK COMPATIBILITY IDEOGRAPH-F965CJK COMPATIBILITY " +
"IDEOGRAPH-F966CJK COMPATIBILITY IDEOGRAPH-F967CJK COMPATIBILITY IDEOGRAP" +
"H-F968CJK COMPATIBILITY IDEOGRAPH-F969CJK COMPATIBILITY IDEOGRAPH-F96ACJ" +
"K COMPATIBILITY IDEOGRAPH-F96BCJK COMPATIBILITY IDEOGRAPH-F96CCJK COMPAT" +
"IBILITY IDEOGRAPH-F96DCJK COMPATIBILITY IDEOGRAPH-F96ECJK COMPATIBILITY " +
"IDEOGRAPH-F96FCJK COMPATIBILITY IDEOGRAPH-F970CJK COMPATIBILITY IDEOGRAP" +
"H-F971CJK COMPATIBILITY IDEOGRAPH-F972CJK COMPATIBILITY IDEOGRAPH-F973CJ" +
"K COMPATIBILITY IDEOGRAPH-F974CJK COMPATIBILITY IDEOGRAPH-F975CJK COMPAT" +
"IBILITY IDEOGRAPH-F976CJK COMPATIBILITY IDEOGRAPH-F977CJK COMPATIBILITY " +
"IDEOGRAPH-F978CJK COMPATIBILITY IDEOGRAPH-F979CJK COMPATIBILITY IDEOGRAP" +
"H-F97ACJK COMPATIBILITY IDEOGRAPH-F97BCJK COMPATIBILITY IDEOGRAPH-F97CCJ" +
"K COMPATIBILITY IDEOGRAPH-F97DCJK COMPATIBILITY IDEOGRAPH-F97ECJK COMPAT" +
"IBILITY IDEOGRAPH-F97FCJK COMPATIBILITY IDEOGRAPH-F980CJK COMPATIBILITY " +
"IDEOGRAPH-F981CJK COMPATIBILITY IDEOGRAPH-F982CJK COMPATIBILITY IDEOGRAP" +
"H-F983CJK COMPATIBILITY IDEOGRAPH-F984CJK COMPATIBILITY IDEOGRAPH-F985CJ" +
"K COMPATIBILITY IDEOGRAPH-F986CJK COMPATIBILITY IDEOGRAPH-F987CJK COMPAT" +
"IBILITY IDEOGRAPH-F988CJK COMPATIBILITY IDEOGRAPH-F989CJK COMPATIBILITY " +
"IDEOGRAPH-F98ACJK COMPATIBILITY IDEOGRAPH-F98BCJK COMPATIBILITY IDEOGRAP" +
"H-F98CCJK COMPATIBILITY IDEOGRAPH-F98DCJK COMPATIBILITY IDEOGRAPH-F98ECJ" +
"K COMPATIBILITY IDEOGRAPH-F98FCJK COMPATIBILITY IDEOGRAPH-F990CJK COMPAT" +
"IBILITY IDEOGRAPH-F991CJK COMPATIBILITY IDEOGRAPH-F992CJK COMPATIBILITY " +
"IDEOGRAPH-F993CJK COMPATIBILITY IDEOGRAPH-F994CJK COMPATIBILITY IDEOGRAP" +
"H-F995CJK COMPATIBILITY IDEOGRAPH-F996CJK COMPATIBILITY IDEOGRAPH-F997CJ" +
"K COMPATIBILITY IDEOGRAPH-F998CJK COMPATIBILITY IDEOGRAPH-F999CJK COMPAT" +
"IBILITY IDEOGRAPH-F99ACJK COMPATIBILITY IDEOGRAPH-F99BCJK COMPATIBILITY " +
"IDEOGRAPH-F99CCJK COMPATIBILITY IDEOGRAPH-F99DCJK COMPATIBILITY IDEOGRAP" +
"H-F99ECJK COMPATIBILITY IDEOGRAPH-F99FCJK COMPATIBILITY IDEOGRAPH-F9A0CJ" +
"K COMPATIBILITY IDEOGRAPH-F9A1CJK COMPATIBILITY IDEOGRAPH-F9A2CJK COMPAT" +
"IBILITY IDEOGRAPH-F9A3CJK COMPATIBILITY IDEOGRAPH-F9A4CJK COMPATIBILITY " +
"IDEOGRAPH-F9A5CJK COMPATIBILITY IDEOGRAPH-F9A6CJK COMPATIBILITY IDEOGRAP" +
"H-F9A7CJK COMPATIBILITY IDEOGRAPH-F9A8CJK COMPATIBILITY IDEOGRAPH-F9A9CJ" +
"K COMPATIBILITY IDEOGRAPH-F9AACJK COMPATIBILITY IDEOGRAPH-F9ABCJK COMPAT" +
"IBILITY IDEOGRAPH-F9ACCJK COMPATIBILITY IDEOGRAPH-F9ADCJK COMPATIBILITY " +
"IDEOGRAPH-F9AECJK COMPATIBILITY IDEOGRAPH-F9AFCJK COMPATIBILITY IDEOGRAP" +
"H-F9B0CJK COMPATIBILITY IDEOGRAPH-F9B1CJK COMPATIBILITY IDEOGRAPH-F9B2CJ" +
"K COMPATIBILITY IDEOGRAPH-F9B3CJK COMPATIBILITY IDEOGRAPH-F9B4CJK COMPAT" +
"IBILITY IDEOGRAPH-F9B5CJK COMPATIBILITY IDEOGRAPH-F9B6CJK COMPATIBILITY " +
"IDEOGRAPH-F9B7CJK COMPATIBILITY IDEOGRAPH-F9B8CJK COMPATIBILITY IDEOGRAP" +
"H-F9B9CJK COMPATIBILITY IDEOGRAPH-F9BACJK COMPATIBILITY IDEOGRAPH-F9BBCJ" +
"K COMPATIBILITY IDEOGRAPH-F9BCCJK COMPATIBILITY IDEOGRAPH-F9BDCJK COMPAT" +
"IBILITY IDEOGRAPH-F9BECJK COMPATIBILITY IDEOGRAPH-F9BFCJK COMPATIBILITY " +
"IDEOGRAPH-F9C0CJK COMPATIBILITY IDEOGRAPH-F9C1CJK COMPATIBILITY IDEOGRAP" +
"H-F9C2CJK COMPATIBILITY IDEOGRAPH-F9C3CJK COMPATIBILITY IDEOGRAPH-F9C4CJ" +
"K COMPATIBILITY IDEOGRAPH-F9C5CJK COMPATIBILITY IDEOGRAPH-F9C6CJK COMPAT" +
"IBILITY IDEOGRAPH-F9C7CJK COMPATIBILITY IDEOGRAPH-F9C8CJK COMPATIBILITY ") + ("" +
"IDEOGRAPH-F9C9CJK COMPATIBILITY IDEOGRAPH-F9CACJK COMPATIBILITY IDEOGRAP" +
"H-F9CBCJK COMPATIBILITY IDEOGRAPH-F9CCCJK COMPATIBILITY IDEOGRAPH-F9CDCJ" +
"K COMPATIBILITY IDEOGRAPH-F9CECJK COMPATIBILITY IDEOGRAPH-F9CFCJK COMPAT" +
"IBILITY IDEOGRAPH-F9D0CJK COMPATIBILITY IDEOGRAPH-F9D1CJK COMPATIBILITY " +
"IDEOGRAPH-F9D2CJK COMPATIBILITY IDEOGRAPH-F9D3CJK COMPATIBILITY IDEOGRAP" +
"H-F9D4CJK COMPATIBILITY IDEOGRAPH-F9D5CJK COMPATIBILITY IDEOGRAPH-F9D6CJ" +
"K COMPATIBILITY IDEOGRAPH-F9D7CJK COMPATIBILITY IDEOGRAPH-F9D8CJK COMPAT" +
"IBILITY IDEOGRAPH-F9D9CJK COMPATIBILITY IDEOGRAPH-F9DACJK COMPATIBILITY " +
"IDEOGRAPH-F9DBCJK COMPATIBILITY IDEOGRAPH-F9DCCJK COMPATIBILITY IDEOGRAP" +
"H-F9DDCJK COMPATIBILITY IDEOGRAPH-F9DECJK COMPATIBILITY IDEOGRAPH-F9DFCJ" +
"K COMPATIBILITY IDEOGRAPH-F9E0CJK COMPATIBILITY IDEOGRAPH-F9E1CJK COMPAT" +
"IBILITY IDEOGRAPH-F9E2CJK COMPATIBILITY IDEOGRAPH-F9E3CJK COMPATIBILITY " +
"IDEOGRAPH-F9E4CJK COMPATIBILITY IDEOGRAPH-F9E5CJK COMPATIBILITY IDEOGRAP" +
"H-F9E6CJK COMPATIBILITY IDEOGRAPH-F9E7CJK COMPATIBILITY IDEOGRAPH-F9E8CJ" +
"K COMPATIBILITY IDEOGRAPH-F9E9CJK COMPATIBILITY IDEOGRAPH-F9EACJK COMPAT" +
"IBILITY IDEOGRAPH-F9EBCJK COMPATIBILITY IDEOGRAPH-F9ECCJK COMPATIBILITY " +
"IDEOGRAPH-F9EDCJK COMPATIBILITY IDEOGRAPH-F9EECJK COMPATIBILITY IDEOGRAP" +
"H-F9EFCJK COMPATIBILITY IDEOGRAPH-F9F0CJK COMPATIBILITY IDEOGRAPH-F9F1CJ" +
"K COMPATIBILITY IDEOGRAPH-F9F2CJK COMPATIBILITY IDEOGRAPH-F9F3CJK COMPAT" +
"IBILITY IDEOGRAPH-F9F4CJK COMPATIBILITY IDEOGRAPH-F9F5CJK COMPATIBILITY " +
"IDEOGRAPH-F9F6CJK COMPATIBILITY IDEOGRAPH-F9F7CJK COMPATIBILITY IDEOGRAP" +
"H-F9F8CJK COMPATIBILITY IDEOGRAPH-F9F9CJK COMPATIBILITY IDEOGRAPH-F9FACJ" +
"K COMPATIBILITY IDEOGRAPH-F9FBCJK COMPATIBILITY IDEOGRAPH-F9FCCJK COMPAT" +
"IBILITY IDEOGRAPH-F9FDCJK COMPATIBILITY IDEOGRAPH-F9FECJK COMPATIBILITY " +
"IDEOGRAPH-F9FFCJK COMPATIBILITY IDEOGRAPH-FA00CJK COMPATIBILITY IDEOGRAP" +
"H-FA01CJK COMPATIBILITY IDEOGRAPH-FA02CJK COMPATIBILITY IDEOGRAPH-FA03CJ" +
"K COMPATIBILITY IDEOGRAPH-FA04CJK COMPATIBILITY IDEOGRAPH-FA05CJK COMPAT" +
"IBILITY IDEOGRAPH-FA06CJK COMPATIBILITY IDEOGRAPH-FA07CJK COMPATIBILITY " +
"IDEOGRAPH-FA08CJK COMPATIBILITY IDEOGRAPH-FA09CJK COMPATIBILITY IDEOGRAP" +
"H-FA0ACJK COMPATIBILITY IDEOGRAPH-FA0BCJK COMPATIBILITY IDEOGRAPH-FA0CCJ" +
"K COMPATIBILITY IDEOGRAPH-FA0DCJK COMPATIBILITY IDEOGRAPH-FA0ECJK COMPAT" +
"IBILITY IDEOGRAPH-FA0FCJK COMPATIBILITY IDEOGRAPH-FA10CJK COMPATIBILITY " +
"IDEOGRAPH-FA11CJK COMPATIBILITY IDEOGRAPH-FA12CJK COMPATIBILITY IDEOGRAP" +
"H-FA13CJK COMPATIBILITY IDEOGRAPH-FA14CJK COMPATIBILITY IDEOGRAPH-FA15CJ" +
"K COMPATIBILITY IDEOGRAPH-FA16CJK COMPATIBILITY IDEOGRAPH-FA17CJK COMPAT" +
"IBILITY IDEOGRAPH-FA18CJK COMPATIBILITY IDEOGRAPH-FA19CJK COMPATIBILITY " +
"IDEOGRAPH-FA1ACJK COMPATIBILITY IDEOGRAPH-FA1BCJK COMPATIBILITY IDEOGRAP" +
"H-FA1CCJK COMPATIBILITY IDEOGRAPH-FA1DCJK COMPATIBILITY IDEOGRAPH-FA1ECJ" +
"K COMPATIBILITY IDEOGRAPH-FA1FCJK COMPATIBILITY IDEOGRAPH-FA20CJK COMPAT" +
"IBILITY IDEOGRAPH-FA21CJK COMPATIBILITY IDEOGRAPH-FA22CJK COMPATIBILITY " +
"IDEOGRAPH-FA23CJK COMPATIBILITY IDEOGRAPH-FA24CJK COMPATIBILITY IDEOGRAP" +
"H-FA25CJK COMPATIBILITY IDEOGRAPH-FA26CJK COMPATIBILITY IDEOGRAPH-FA27CJ" +
"K COMPATIBILITY IDEOGRAPH-FA28CJK COMPATIBILITY IDEOGRAPH-FA29CJK COMPAT" +
"IBILITY IDEOGRAPH-FA2ACJK COMPATIBILITY IDEOGRAPH-FA2BCJK COMPATIBILITY " +
"IDEOGRAPH-FA2CCJK COMPATIBILITY IDEOGRAPH-FA2DCJK COMPATIBILITY IDEOGRAP" +
"H-FA2ECJK COMPATIBILITY IDEOGRAPH-FA2FCJK COMPATIBILITY IDEOGRAPH-FA30CJ" +
"K COMPATIBILITY IDEOGRAPH-FA31CJK COMPATIBILITY IDEOGRAPH-FA32CJK COMPAT" +
"IBILITY IDEOGRAPH-FA33CJK COMPATIBILITY IDEOGRAPH-FA34CJK COMPATIBILITY " +
"IDEOGRAPH-FA35CJK COMPATIBILITY IDEOGRAPH-FA36CJK COMPATIBILITY IDEOGRAP" +
"H-FA37CJK COMPATIBILITY IDEOGRAPH-FA38CJK COMPATIBILITY IDEOGRAPH-FA39CJ" +
"K COMPATIBILITY IDEOGRAPH-FA3ACJK COMPATIBILITY IDEOGRAPH-FA3BCJK COMPAT" +
"IBILITY IDEOGRAPH-FA3CCJK COMPATIBILITY IDEOGRAPH-FA3DCJK COMPATIBILITY " +
"IDEOGRAPH-FA3ECJK COMPATIBILITY IDEOGRAPH-FA3FCJK COMPATIBILITY IDEOGRAP" +
"H-FA40CJK COMPATIBILITY IDEOGRAPH-FA41CJK COMPATIBILITY IDEOGRAPH-FA42CJ" +
"K COMPATIBILITY IDEOGRAPH-FA43CJK COMPATIBILITY IDEOGRAPH-FA44CJK COMPAT" +
"IBILITY IDEOGRAPH-FA45CJK COMPATIBILITY IDEOGRAPH-FA46CJK COMPATIBILITY " +
"IDEOGRAPH-FA47CJK COMPATIBILITY IDEOGRAPH-FA48CJK COMPATIBILITY IDEOGRAP" +
"H-FA49CJK COMPATIBILITY IDEOGRAPH-FA4ACJK COMPATIBILITY IDEOGRAPH-FA4BCJ" +
"K COMPATIBILITY IDEOGRAPH-FA4CCJK COMPATIBILITY IDEOGRAPH-FA4DCJK COMPAT" +
"IBILITY IDEOGRAPH-FA4ECJK COMPATIBILITY IDEOGRAPH-FA4FCJK COMPATIBILITY " +
"IDEOGRAPH-FA50CJK COMPATIBILITY IDEOGRAPH-FA51CJK COMPATIBILITY IDEOGRAP" +
"H-FA52CJK COMPATIBILITY IDEOGRAPH-FA53CJK COMPATIBILITY IDEOGRAPH-FA54CJ" +
"K COMPATIBILITY IDEOGRAPH-FA55CJK COMPATIBILITY IDEOGRAPH-FA56CJK COMPAT" +
"IBILITY IDEOGRAPH-FA57CJK COMPATIBILITY IDEOGRAPH-FA58CJK COMPATIBILITY ") + ("" +
"IDEOGRAPH-FA59CJK COMPATIBILITY IDEOGRAPH-FA5ACJK COMPATIBILITY IDEOGRAP" +
"H-FA5BCJK COMPATIBILITY IDEOGRAPH-FA5CCJK COMPATIBILITY IDEOGRAPH-FA5DCJ" +
"K COMPATIBILITY IDEOGRAPH-FA5ECJK COMPATIBILITY IDEOGRAPH-FA5FCJK COMPAT" +
"IBILITY IDEOGRAPH-FA60CJK COMPATIBILITY IDEOGRAPH-FA61CJK COMPATIBILITY " +
"IDEOGRAPH-FA62CJK COMPATIBILITY IDEOGRAPH-FA63CJK COMPATIBILITY IDEOGRAP" +
"H-FA64CJK COMPATIBILITY IDEOGRAPH-FA65CJK COMPATIBILITY IDEOGRAPH-FA66CJ" +
"K COMPATIBILITY IDEOGRAPH-FA67CJK COMPATIBILITY IDEOGRAPH-FA68CJK COMPAT" +
"IBILITY IDEOGRAPH-FA69CJK COMPATIBILITY IDEOGRAPH-FA6ACJK COMPATIBILITY " +
"IDEOGRAPH-FA6BCJK COMPATIBILITY IDEOGRAPH-FA6CCJK COMPATIBILITY IDEOGRAP" +
"H-FA6DCJK COMPATIBILITY IDEOGRAPH-FA70CJK COMPATIBILITY IDEOGRAPH-FA71CJ" +
"K COMPATIBILITY IDEOGRAPH-FA72CJK COMPATIBILITY IDEOGRAPH-FA73CJK COMPAT" +
"IBILITY IDEOGRAPH-FA74CJK COMPATIBILITY IDEOGRAPH-FA75CJK COMPATIBILITY " +
"IDEOGRAPH-FA76CJK COMPATIBILITY IDEOGRAPH-FA77CJK COMPATIBILITY IDEOGRAP" +
"H-FA78CJK COMPATIBILITY IDEOGRAPH-FA79CJK COMPATIBILITY IDEOGRAPH-FA7ACJ" +
"K COMPATIBILITY IDEOGRAPH-FA7BCJK COMPATIBILITY IDEOGRAPH-FA7CCJK COMPAT" +
"IBILITY IDEOGRAPH-FA7DCJK COMPATIBILITY IDEOGRAPH-FA7ECJK COMPATIBILITY " +
"IDEOGRAPH-FA7FCJK COMPATIBILITY IDEOGRAPH-FA80CJK COMPATIBILITY IDEOGRAP" +
"H-FA81CJK COMPATIBILITY IDEOGRAPH-FA82CJK COMPATIBILITY IDEOGRAPH-FA83CJ" +
"K COMPATIBILITY IDEOGRAPH-FA84CJK COMPATIBILITY IDEOGRAPH-FA85CJK COMPAT" +
"IBILITY IDEOGRAPH-FA86CJK COMPATIBILITY IDEOGRAPH-FA87CJK COMPATIBILITY " +
"IDEOGRAPH-FA88CJK COMPATIBILITY IDEOGRAPH-FA89CJK COMPATIBILITY IDEOGRAP" +
"H-FA8ACJK COMPATIBILITY IDEOGRAPH-FA8BCJK COMPATIBILITY IDEOGRAPH-FA8CCJ" +
"K COMPATIBILITY IDEOGRAPH-FA8DCJK COMPATIBILITY IDEOGRAPH-FA8ECJK COMPAT" +
"IBILITY IDEOGRAPH-FA8FCJK COMPATIBILITY IDEOGRAPH-FA90CJK COMPATIBILITY " +
"IDEOGRAPH-FA91CJK COMPATIBILITY IDEOGRAPH-FA92CJK COMPATIBILITY IDEOGRAP" +
"H-FA93CJK COMPATIBILITY IDEOGRAPH-FA94CJK COMPATIBILITY IDEOGRAPH-FA95CJ" +
"K COMPATIBILITY IDEOGRAPH-FA96CJK COMPATIBILITY IDEOGRAPH-FA97CJK COMPAT" +
"IBILITY IDEOGRAPH-FA98CJK COMPATIBILITY IDEOGRAPH-FA99CJK COMPATIBILITY " +
"IDEOGRAPH-FA9ACJK COMPATIBILITY IDEOGRAPH-FA9BCJK COMPATIBILITY IDEOGRAP" +
"H-FA9CCJK COMPATIBILITY IDEOGRAPH-FA9DCJK COMPATIBILITY IDEOGRAPH-FA9ECJ" +
"K COMPATIBILITY IDEOGRAPH-FA9FCJK COMPATIBILITY IDEOGRAPH-FAA0CJK COMPAT" +
"IBILITY IDEOGRAPH-FAA1CJK COMPATIBILITY IDEOGRAPH-FAA2CJK COMPATIBILITY " +
"IDEOGRAPH-FAA3CJK COMPATIBILITY IDEOGRAPH-FAA4CJK COMPATIBILITY IDEOGRAP" +
"H-FAA5CJK COMPATIBILITY IDEOGRAPH-FAA6CJK COMPATIBILITY IDEOGRAPH-FAA7CJ" +
"K COMPATIBILITY IDEOGRAPH-FAA8CJK COMPATIBILITY IDEOGRAPH-FAA9CJK COMPAT" +
"IBILITY IDEOGRAPH-FAAACJK COMPATIBILITY IDEOGRAPH-FAABCJK COMPATIBILITY " +
"IDEOGRAPH-FAACCJK COMPATIBILITY IDEOGRAPH-FAADCJK COMPATIBILITY IDEOGRAP" +
"H-FAAECJK COMPATIBILITY IDEOGRAPH-FAAFCJK COMPATIBILITY IDEOGRAPH-FAB0CJ" +
"K COMPATIBILITY IDEOGRAPH-FAB1CJK COMPATIBILITY IDEOGRAPH-FAB2CJK COMPAT" +
"IBILITY IDEOGRAPH-FAB3CJK COMPATIBILITY IDEOGRAPH-FAB4CJK COMPATIBILITY " +
"IDEOGRAPH-FAB5CJK COMPATIBILITY IDEOGRAPH-FAB6CJK COMPATIBILITY IDEOGRAP" +
"H-FAB7CJK COMPATIBILITY IDEOGRAPH-FAB8CJK COMPATIBILITY IDEOGRAPH-FAB9CJ" +
"K COMPATIBILITY IDEOGRAPH-FABACJK COMPATIBILITY IDEOGRAPH-FABBCJK COMPAT" +
"IBILITY IDEOGRAPH-FABCCJK COMPATIBILITY IDEOGRAPH-FABDCJK COMPATIBILITY " +
"IDEOGRAPH-FABECJK COMPATIBILITY IDEOGRAPH-FABFCJK COMPATIBILITY IDEOGRAP" +
"H-FAC0CJK COMPATIBILITY IDEOGRAPH-FAC1CJK COMPATIBILITY IDEOGRAPH-FAC2CJ" +
"K COMPATIBILITY IDEOGRAPH-FAC3CJK COMPATIBILITY IDEOGRAPH-FAC4CJK COMPAT" +
"IBILITY IDEOGRAPH-FAC5CJK COMPATIBILITY IDEOGRAPH-FAC6CJK COMPATIBILITY " +
"IDEOGRAPH-FAC7CJK COMPATIBILITY IDEOGRAPH-FAC8CJK COMPATIBILITY IDEOGRAP" +
"H-FAC9CJK COMPATIBILITY IDEOGRAPH-FACACJK COMPATIBILITY IDEOGRAPH-FACBCJ" +
"K COMPATIBILITY IDEOGRAPH-FACCCJK COMPATIBILITY IDEOGRAPH-FACDCJK COMPAT" +
"IBILITY IDEOGRAPH-FACECJK COMPATIBILITY IDEOGRAPH-FACFCJK COMPATIBILITY " +
"IDEOGRAPH-FAD0CJK COMPATIBILITY IDEOGRAPH-FAD1CJK COMPATIBILITY IDEOGRAP" +
"H-FAD2CJK COMPATIBILITY IDEOGRAPH-FAD3CJK COMPATIBILITY IDEOGRAPH-FAD4CJ" +
"K COMPATIBILITY IDEOGRAPH-FAD5CJK COMPATIBILITY IDEOGRAPH-FAD6CJK COMPAT" +
"IBILITY IDEOGRAPH-FAD7CJK COMPATIBILITY IDEOGRAPH-FAD8CJK COMPATIBILITY " +
"IDEOGRAPH-FAD9LATIN SMALL LIGATURE FFLATIN SMALL LIGATURE FILATIN SMALL " +
"LIGATURE FLLATIN SMALL LIGATURE FFILATIN SMALL LIGATURE FFLLATIN SMALL L" +
"IGATURE LONG S TLATIN SMALL LIGATURE STARMENIAN SMALL LIGATURE MEN NOWAR" +
"MENIAN SMALL LIGATURE MEN ECHARMENIAN SMALL LIGATURE MEN INIARMENIAN SMA" +
"LL LIGATURE VEW NOWARMENIAN SMALL LIGATURE MEN XEHHEBREW LETTER YOD WITH" +
" HIRIQHEBREW POINT JUDEO-SPANISH VARIKAHEBREW LIGATURE YIDDISH YOD YOD P" +
"ATAHHEBREW LETTER ALTERNATIVE AYINHEBREW LETTER WIDE ALEFHEBREW LETTER W" +
"IDE DALETHEBREW LETTER WIDE HEHEBREW LETTER WIDE KAFHEBREW LETTER WIDE L") + ("" +
"AMEDHEBREW LETTER WIDE FINAL MEMHEBREW LETTER WIDE RESHHEBREW LETTER WID" +
"E TAVHEBREW LETTER ALTERNATIVE PLUS SIGNHEBREW LETTER SHIN WITH SHIN DOT" +
"HEBREW LETTER SHIN WITH SIN DOTHEBREW LETTER SHIN WITH DAGESH AND SHIN D" +
"OTHEBREW LETTER SHIN WITH DAGESH AND SIN DOTHEBREW LETTER ALEF WITH PATA" +
"HHEBREW LETTER ALEF WITH QAMATSHEBREW LETTER ALEF WITH MAPIQHEBREW LETTE" +
"R BET WITH DAGESHHEBREW LETTER GIMEL WITH DAGESHHEBREW LETTER DALET WITH" +
" DAGESHHEBREW LETTER HE WITH MAPIQHEBREW LETTER VAV WITH DAGESHHEBREW LE" +
"TTER ZAYIN WITH DAGESHHEBREW LETTER TET WITH DAGESHHEBREW LETTER YOD WIT" +
"H DAGESHHEBREW LETTER FINAL KAF WITH DAGESHHEBREW LETTER KAF WITH DAGESH" +
"HEBREW LETTER LAMED WITH DAGESHHEBREW LETTER MEM WITH DAGESHHEBREW LETTE" +
"R NUN WITH DAGESHHEBREW LETTER SAMEKH WITH DAGESHHEBREW LETTER FINAL PE " +
"WITH DAGESHHEBREW LETTER PE WITH DAGESHHEBREW LETTER TSADI WITH DAGESHHE" +
"BREW LETTER QOF WITH DAGESHHEBREW LETTER RESH WITH DAGESHHEBREW LETTER S" +
"HIN WITH DAGESHHEBREW LETTER TAV WITH DAGESHHEBREW LETTER VAV WITH HOLAM" +
"HEBREW LETTER BET WITH RAFEHEBREW LETTER KAF WITH RAFEHEBREW LETTER PE W" +
"ITH RAFEHEBREW LIGATURE ALEF LAMEDARABIC LETTER ALEF WASLA ISOLATED FORM" +
"ARABIC LETTER ALEF WASLA FINAL FORMARABIC LETTER BEEH ISOLATED FORMARABI" +
"C LETTER BEEH FINAL FORMARABIC LETTER BEEH INITIAL FORMARABIC LETTER BEE" +
"H MEDIAL FORMARABIC LETTER PEH ISOLATED FORMARABIC LETTER PEH FINAL FORM" +
"ARABIC LETTER PEH INITIAL FORMARABIC LETTER PEH MEDIAL FORMARABIC LETTER" +
" BEHEH ISOLATED FORMARABIC LETTER BEHEH FINAL FORMARABIC LETTER BEHEH IN" +
"ITIAL FORMARABIC LETTER BEHEH MEDIAL FORMARABIC LETTER TTEHEH ISOLATED F" +
"ORMARABIC LETTER TTEHEH FINAL FORMARABIC LETTER TTEHEH INITIAL FORMARABI" +
"C LETTER TTEHEH MEDIAL FORMARABIC LETTER TEHEH ISOLATED FORMARABIC LETTE" +
"R TEHEH FINAL FORMARABIC LETTER TEHEH INITIAL FORMARABIC LETTER TEHEH ME" +
"DIAL FORMARABIC LETTER TTEH ISOLATED FORMARABIC LETTER TTEH FINAL FORMAR" +
"ABIC LETTER TTEH INITIAL FORMARABIC LETTER TTEH MEDIAL FORMARABIC LETTER" +
" VEH ISOLATED FORMARABIC LETTER VEH FINAL FORMARABIC LETTER VEH INITIAL " +
"FORMARABIC LETTER VEH MEDIAL FORMARABIC LETTER PEHEH ISOLATED FORMARABIC" +
" LETTER PEHEH FINAL FORMARABIC LETTER PEHEH INITIAL FORMARABIC LETTER PE" +
"HEH MEDIAL FORMARABIC LETTER DYEH ISOLATED FORMARABIC LETTER DYEH FINAL " +
"FORMARABIC LETTER DYEH INITIAL FORMARABIC LETTER DYEH MEDIAL FORMARABIC " +
"LETTER NYEH ISOLATED FORMARABIC LETTER NYEH FINAL FORMARABIC LETTER NYEH" +
" INITIAL FORMARABIC LETTER NYEH MEDIAL FORMARABIC LETTER TCHEH ISOLATED " +
"FORMARABIC LETTER TCHEH FINAL FORMARABIC LETTER TCHEH INITIAL FORMARABIC" +
" LETTER TCHEH MEDIAL FORMARABIC LETTER TCHEHEH ISOLATED FORMARABIC LETTE" +
"R TCHEHEH FINAL FORMARABIC LETTER TCHEHEH INITIAL FORMARABIC LETTER TCHE" +
"HEH MEDIAL FORMARABIC LETTER DDAHAL ISOLATED FORMARABIC LETTER DDAHAL FI" +
"NAL FORMARABIC LETTER DAHAL ISOLATED FORMARABIC LETTER DAHAL FINAL FORMA" +
"RABIC LETTER DUL ISOLATED FORMARABIC LETTER DUL FINAL FORMARABIC LETTER " +
"DDAL ISOLATED FORMARABIC LETTER DDAL FINAL FORMARABIC LETTER JEH ISOLATE" +
"D FORMARABIC LETTER JEH FINAL FORMARABIC LETTER RREH ISOLATED FORMARABIC" +
" LETTER RREH FINAL FORMARABIC LETTER KEHEH ISOLATED FORMARABIC LETTER KE" +
"HEH FINAL FORMARABIC LETTER KEHEH INITIAL FORMARABIC LETTER KEHEH MEDIAL" +
" FORMARABIC LETTER GAF ISOLATED FORMARABIC LETTER GAF FINAL FORMARABIC L" +
"ETTER GAF INITIAL FORMARABIC LETTER GAF MEDIAL FORMARABIC LETTER GUEH IS" +
"OLATED FORMARABIC LETTER GUEH FINAL FORMARABIC LETTER GUEH INITIAL FORMA" +
"RABIC LETTER GUEH MEDIAL FORMARABIC LETTER NGOEH ISOLATED FORMARABIC LET" +
"TER NGOEH FINAL FORMARABIC LETTER NGOEH INITIAL FORMARABIC LETTER NGOEH " +
"MEDIAL FORMARABIC LETTER NOON GHUNNA ISOLATED FORMARABIC LETTER NOON GHU" +
"NNA FINAL FORMARABIC LETTER RNOON ISOLATED FORMARABIC LETTER RNOON FINAL" +
" FORMARABIC LETTER RNOON INITIAL FORMARABIC LETTER RNOON MEDIAL FORMARAB" +
"IC LETTER HEH WITH YEH ABOVE ISOLATED FORMARABIC LETTER HEH WITH YEH ABO" +
"VE FINAL FORMARABIC LETTER HEH GOAL ISOLATED FORMARABIC LETTER HEH GOAL " +
"FINAL FORMARABIC LETTER HEH GOAL INITIAL FORMARABIC LETTER HEH GOAL MEDI" +
"AL FORMARABIC LETTER HEH DOACHASHMEE ISOLATED FORMARABIC LETTER HEH DOAC" +
"HASHMEE FINAL FORMARABIC LETTER HEH DOACHASHMEE INITIAL FORMARABIC LETTE" +
"R HEH DOACHASHMEE MEDIAL FORMARABIC LETTER YEH BARREE ISOLATED FORMARABI" +
"C LETTER YEH BARREE FINAL FORMARABIC LETTER YEH BARREE WITH HAMZA ABOVE " +
"ISOLATED FORMARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORMARABIC " +
"SYMBOL DOT ABOVEARABIC SYMBOL DOT BELOWARABIC SYMBOL TWO DOTS ABOVEARABI" +
"C SYMBOL TWO DOTS BELOWARABIC SYMBOL THREE DOTS ABOVEARABIC SYMBOL THREE" +
" DOTS BELOWARABIC SYMBOL THREE DOTS POINTING DOWNWARDS ABOVEARABIC SYMBO" +
"L THREE DOTS POINTING DOWNWARDS BELOWARABIC SYMBOL FOUR DOTS ABOVEARABIC") + ("" +
" SYMBOL FOUR DOTS BELOWARABIC SYMBOL DOUBLE VERTICAL BAR BELOWARABIC SYM" +
"BOL TWO DOTS VERTICALLY ABOVEARABIC SYMBOL TWO DOTS VERTICALLY BELOWARAB" +
"IC SYMBOL RINGARABIC SYMBOL SMALL TAH ABOVEARABIC SYMBOL SMALL TAH BELOW" +
"ARABIC SYMBOL WASLA ABOVEARABIC LIGATURE JALLA WA-ALAAARABIC LIGATURE DA" +
"AMAT BARAKAATUHUMARABIC LIGATURE RAHMATU ALLAAHI TAAALAA ALAYHARABIC LIG" +
"ATURE RAHMATU ALLAAHI ALAYHIMARABIC LIGATURE RAHMATU ALLAAHI ALAYHIMAAAR" +
"ABIC LIGATURE RAHIMAHUM ALLAAHU TAAALAAARABIC LIGATURE RAHIMAHUMAA ALLAA" +
"HARABIC LIGATURE RAHIMAHUMAA ALLAAHU TAAALAAARABIC LIGATURE RADI ALLAAHU" +
" TAAALAA ANHUMARABIC LIGATURE HAFIZAHU ALLAAHARABIC LIGATURE HAFIZAHU AL" +
"LAAHU TAAALAAARABIC LIGATURE HAFIZAHUM ALLAAHU TAAALAAARABIC LIGATURE HA" +
"FIZAHUMAA ALLAAHU TAAALAAARABIC LIGATURE SALLALLAAHU TAAALAA ALAYHI WA-S" +
"ALLAMARABIC LIGATURE AJJAL ALLAAHU FARAJAHU ASH-SHAREEFARABIC LIGATURE A" +
"LAYHI AR-RAHMAHARABIC LETTER NG ISOLATED FORMARABIC LETTER NG FINAL FORM" +
"ARABIC LETTER NG INITIAL FORMARABIC LETTER NG MEDIAL FORMARABIC LETTER U" +
" ISOLATED FORMARABIC LETTER U FINAL FORMARABIC LETTER OE ISOLATED FORMAR" +
"ABIC LETTER OE FINAL FORMARABIC LETTER YU ISOLATED FORMARABIC LETTER YU " +
"FINAL FORMARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORMARABIC LETTER VE" +
" ISOLATED FORMARABIC LETTER VE FINAL FORMARABIC LETTER KIRGHIZ OE ISOLAT" +
"ED FORMARABIC LETTER KIRGHIZ OE FINAL FORMARABIC LETTER KIRGHIZ YU ISOLA" +
"TED FORMARABIC LETTER KIRGHIZ YU FINAL FORMARABIC LETTER E ISOLATED FORM" +
"ARABIC LETTER E FINAL FORMARABIC LETTER E INITIAL FORMARABIC LETTER E ME" +
"DIAL FORMARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORMAR" +
"ABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORMARABIC LIGATUR" +
"E YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORMARABIC LIGATURE YEH WITH H" +
"AMZA ABOVE WITH ALEF FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH" +
" AE ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM" +
"ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORMARABIC LIGATU" +
"RE YEH WITH HAMZA ABOVE WITH WAW FINAL FORMARABIC LIGATURE YEH WITH HAMZ" +
"A ABOVE WITH U ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U " +
"FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORMARAB" +
"IC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORMARABIC LIGATURE YEH W" +
"ITH HAMZA ABOVE WITH YU ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOV" +
"E WITH YU FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED" +
" FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORMARABIC LIGATU" +
"RE YEH WITH HAMZA ABOVE WITH E INITIAL FORMARABIC LIGATURE UIGHUR KIRGHI" +
"Z YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE UI" +
"GHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORMARABIC LIG" +
"ATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM" +
"ARABIC LETTER FARSI YEH ISOLATED FORMARABIC LETTER FARSI YEH FINAL FORMA" +
"RABIC LETTER FARSI YEH INITIAL FORMARABIC LETTER FARSI YEH MEDIAL FORMAR" +
"ABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORMARABIC LIGATUR" +
"E YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORMARABIC LIGATURE YEH WITH HA" +
"MZA ABOVE WITH MEEM ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WI" +
"TH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH Y" +
"EH ISOLATED FORMARABIC LIGATURE BEH WITH JEEM ISOLATED FORMARABIC LIGATU" +
"RE BEH WITH HAH ISOLATED FORMARABIC LIGATURE BEH WITH KHAH ISOLATED FORM" +
"ARABIC LIGATURE BEH WITH MEEM ISOLATED FORMARABIC LIGATURE BEH WITH ALEF" +
" MAKSURA ISOLATED FORMARABIC LIGATURE BEH WITH YEH ISOLATED FORMARABIC L" +
"IGATURE TEH WITH JEEM ISOLATED FORMARABIC LIGATURE TEH WITH HAH ISOLATED" +
" FORMARABIC LIGATURE TEH WITH KHAH ISOLATED FORMARABIC LIGATURE TEH WITH" +
" MEEM ISOLATED FORMARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORMAR" +
"ABIC LIGATURE TEH WITH YEH ISOLATED FORMARABIC LIGATURE THEH WITH JEEM I" +
"SOLATED FORMARABIC LIGATURE THEH WITH MEEM ISOLATED FORMARABIC LIGATURE " +
"THEH WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE THEH WITH YEH ISOLAT" +
"ED FORMARABIC LIGATURE JEEM WITH HAH ISOLATED FORMARABIC LIGATURE JEEM W" +
"ITH MEEM ISOLATED FORMARABIC LIGATURE HAH WITH JEEM ISOLATED FORMARABIC " +
"LIGATURE HAH WITH MEEM ISOLATED FORMARABIC LIGATURE KHAH WITH JEEM ISOLA" +
"TED FORMARABIC LIGATURE KHAH WITH HAH ISOLATED FORMARABIC LIGATURE KHAH " +
"WITH MEEM ISOLATED FORMARABIC LIGATURE SEEN WITH JEEM ISOLATED FORMARABI" +
"C LIGATURE SEEN WITH HAH ISOLATED FORMARABIC LIGATURE SEEN WITH KHAH ISO" +
"LATED FORMARABIC LIGATURE SEEN WITH MEEM ISOLATED FORMARABIC LIGATURE SA" +
"D WITH HAH ISOLATED FORMARABIC LIGATURE SAD WITH MEEM ISOLATED FORMARABI" +
"C LIGATURE DAD WITH JEEM ISOLATED FORMARABIC LIGATURE DAD WITH HAH ISOLA" +
"TED FORMARABIC LIGATURE DAD WITH KHAH ISOLATED FORMARABIC LIGATURE DAD W") + ("" +
"ITH MEEM ISOLATED FORMARABIC LIGATURE TAH WITH HAH ISOLATED FORMARABIC L" +
"IGATURE TAH WITH MEEM ISOLATED FORMARABIC LIGATURE ZAH WITH MEEM ISOLATE" +
"D FORMARABIC LIGATURE AIN WITH JEEM ISOLATED FORMARABIC LIGATURE AIN WIT" +
"H MEEM ISOLATED FORMARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORMARABIC " +
"LIGATURE GHAIN WITH MEEM ISOLATED FORMARABIC LIGATURE FEH WITH JEEM ISOL" +
"ATED FORMARABIC LIGATURE FEH WITH HAH ISOLATED FORMARABIC LIGATURE FEH W" +
"ITH KHAH ISOLATED FORMARABIC LIGATURE FEH WITH MEEM ISOLATED FORMARABIC " +
"LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE FEH WITH YEH" +
" ISOLATED FORMARABIC LIGATURE QAF WITH HAH ISOLATED FORMARABIC LIGATURE " +
"QAF WITH MEEM ISOLATED FORMARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATE" +
"D FORMARABIC LIGATURE QAF WITH YEH ISOLATED FORMARABIC LIGATURE KAF WITH" +
" ALEF ISOLATED FORMARABIC LIGATURE KAF WITH JEEM ISOLATED FORMARABIC LIG" +
"ATURE KAF WITH HAH ISOLATED FORMARABIC LIGATURE KAF WITH KHAH ISOLATED F" +
"ORMARABIC LIGATURE KAF WITH LAM ISOLATED FORMARABIC LIGATURE KAF WITH ME" +
"EM ISOLATED FORMARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORMARABI" +
"C LIGATURE KAF WITH YEH ISOLATED FORMARABIC LIGATURE LAM WITH JEEM ISOLA" +
"TED FORMARABIC LIGATURE LAM WITH HAH ISOLATED FORMARABIC LIGATURE LAM WI" +
"TH KHAH ISOLATED FORMARABIC LIGATURE LAM WITH MEEM ISOLATED FORMARABIC L" +
"IGATURE LAM WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE LAM WITH YEH " +
"ISOLATED FORMARABIC LIGATURE MEEM WITH JEEM ISOLATED FORMARABIC LIGATURE" +
" MEEM WITH HAH ISOLATED FORMARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM" +
"ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORMARABIC LIGATURE MEEM WITH AL" +
"EF MAKSURA ISOLATED FORMARABIC LIGATURE MEEM WITH YEH ISOLATED FORMARABI" +
"C LIGATURE NOON WITH JEEM ISOLATED FORMARABIC LIGATURE NOON WITH HAH ISO" +
"LATED FORMARABIC LIGATURE NOON WITH KHAH ISOLATED FORMARABIC LIGATURE NO" +
"ON WITH MEEM ISOLATED FORMARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATE" +
"D FORMARABIC LIGATURE NOON WITH YEH ISOLATED FORMARABIC LIGATURE HEH WIT" +
"H JEEM ISOLATED FORMARABIC LIGATURE HEH WITH MEEM ISOLATED FORMARABIC LI" +
"GATURE HEH WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE HEH WITH YEH I" +
"SOLATED FORMARABIC LIGATURE YEH WITH JEEM ISOLATED FORMARABIC LIGATURE Y" +
"EH WITH HAH ISOLATED FORMARABIC LIGATURE YEH WITH KHAH ISOLATED FORMARAB" +
"IC LIGATURE YEH WITH MEEM ISOLATED FORMARABIC LIGATURE YEH WITH ALEF MAK" +
"SURA ISOLATED FORMARABIC LIGATURE YEH WITH YEH ISOLATED FORMARABIC LIGAT" +
"URE THAL WITH SUPERSCRIPT ALEF ISOLATED FORMARABIC LIGATURE REH WITH SUP" +
"ERSCRIPT ALEF ISOLATED FORMARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT" +
" ALEF ISOLATED FORMARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORMARA" +
"BIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORMARABIC LIGATURE SHADDA WI" +
"TH FATHA ISOLATED FORMARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORMARA" +
"BIC LIGATURE SHADDA WITH KASRA ISOLATED FORMARABIC LIGATURE SHADDA WITH " +
"SUPERSCRIPT ALEF ISOLATED FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH " +
"REH FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORMA" +
"RABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORMARABIC LIGATURE " +
"YEH WITH HAMZA ABOVE WITH NOON FINAL FORMARABIC LIGATURE YEH WITH HAMZA " +
"ABOVE WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE W" +
"ITH YEH FINAL FORMARABIC LIGATURE BEH WITH REH FINAL FORMARABIC LIGATURE" +
" BEH WITH ZAIN FINAL FORMARABIC LIGATURE BEH WITH MEEM FINAL FORMARABIC " +
"LIGATURE BEH WITH NOON FINAL FORMARABIC LIGATURE BEH WITH ALEF MAKSURA F" +
"INAL FORMARABIC LIGATURE BEH WITH YEH FINAL FORMARABIC LIGATURE TEH WITH" +
" REH FINAL FORMARABIC LIGATURE TEH WITH ZAIN FINAL FORMARABIC LIGATURE T" +
"EH WITH MEEM FINAL FORMARABIC LIGATURE TEH WITH NOON FINAL FORMARABIC LI" +
"GATURE TEH WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE TEH WITH YEH FINA" +
"L FORMARABIC LIGATURE THEH WITH REH FINAL FORMARABIC LIGATURE THEH WITH " +
"ZAIN FINAL FORMARABIC LIGATURE THEH WITH MEEM FINAL FORMARABIC LIGATURE " +
"THEH WITH NOON FINAL FORMARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FO" +
"RMARABIC LIGATURE THEH WITH YEH FINAL FORMARABIC LIGATURE FEH WITH ALEF " +
"MAKSURA FINAL FORMARABIC LIGATURE FEH WITH YEH FINAL FORMARABIC LIGATURE" +
" QAF WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE QAF WITH YEH FINAL FORM" +
"ARABIC LIGATURE KAF WITH ALEF FINAL FORMARABIC LIGATURE KAF WITH LAM FIN" +
"AL FORMARABIC LIGATURE KAF WITH MEEM FINAL FORMARABIC LIGATURE KAF WITH " +
"ALEF MAKSURA FINAL FORMARABIC LIGATURE KAF WITH YEH FINAL FORMARABIC LIG" +
"ATURE LAM WITH MEEM FINAL FORMARABIC LIGATURE LAM WITH ALEF MAKSURA FINA" +
"L FORMARABIC LIGATURE LAM WITH YEH FINAL FORMARABIC LIGATURE MEEM WITH A" +
"LEF FINAL FORMARABIC LIGATURE MEEM WITH MEEM FINAL FORMARABIC LIGATURE N" +
"OON WITH REH FINAL FORMARABIC LIGATURE NOON WITH ZAIN FINAL FORMARABIC L") + ("" +
"IGATURE NOON WITH MEEM FINAL FORMARABIC LIGATURE NOON WITH NOON FINAL FO" +
"RMARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE NOON " +
"WITH YEH FINAL FORMARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FI" +
"NAL FORMARABIC LIGATURE YEH WITH REH FINAL FORMARABIC LIGATURE YEH WITH " +
"ZAIN FINAL FORMARABIC LIGATURE YEH WITH MEEM FINAL FORMARABIC LIGATURE Y" +
"EH WITH NOON FINAL FORMARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORMA" +
"RABIC LIGATURE YEH WITH YEH FINAL FORMARABIC LIGATURE YEH WITH HAMZA ABO" +
"VE WITH JEEM INITIAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH I" +
"NITIAL FORMARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORMAR" +
"ABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORMARABIC LIGATURE" +
" YEH WITH HAMZA ABOVE WITH HEH INITIAL FORMARABIC LIGATURE BEH WITH JEEM" +
" INITIAL FORMARABIC LIGATURE BEH WITH HAH INITIAL FORMARABIC LIGATURE BE" +
"H WITH KHAH INITIAL FORMARABIC LIGATURE BEH WITH MEEM INITIAL FORMARABIC" +
" LIGATURE BEH WITH HEH INITIAL FORMARABIC LIGATURE TEH WITH JEEM INITIAL" +
" FORMARABIC LIGATURE TEH WITH HAH INITIAL FORMARABIC LIGATURE TEH WITH K" +
"HAH INITIAL FORMARABIC LIGATURE TEH WITH MEEM INITIAL FORMARABIC LIGATUR" +
"E TEH WITH HEH INITIAL FORMARABIC LIGATURE THEH WITH MEEM INITIAL FORMAR" +
"ABIC LIGATURE JEEM WITH HAH INITIAL FORMARABIC LIGATURE JEEM WITH MEEM I" +
"NITIAL FORMARABIC LIGATURE HAH WITH JEEM INITIAL FORMARABIC LIGATURE HAH" +
" WITH MEEM INITIAL FORMARABIC LIGATURE KHAH WITH JEEM INITIAL FORMARABIC" +
" LIGATURE KHAH WITH MEEM INITIAL FORMARABIC LIGATURE SEEN WITH JEEM INIT" +
"IAL FORMARABIC LIGATURE SEEN WITH HAH INITIAL FORMARABIC LIGATURE SEEN W" +
"ITH KHAH INITIAL FORMARABIC LIGATURE SEEN WITH MEEM INITIAL FORMARABIC L" +
"IGATURE SAD WITH HAH INITIAL FORMARABIC LIGATURE SAD WITH KHAH INITIAL F" +
"ORMARABIC LIGATURE SAD WITH MEEM INITIAL FORMARABIC LIGATURE DAD WITH JE" +
"EM INITIAL FORMARABIC LIGATURE DAD WITH HAH INITIAL FORMARABIC LIGATURE " +
"DAD WITH KHAH INITIAL FORMARABIC LIGATURE DAD WITH MEEM INITIAL FORMARAB" +
"IC LIGATURE TAH WITH HAH INITIAL FORMARABIC LIGATURE ZAH WITH MEEM INITI" +
"AL FORMARABIC LIGATURE AIN WITH JEEM INITIAL FORMARABIC LIGATURE AIN WIT" +
"H MEEM INITIAL FORMARABIC LIGATURE GHAIN WITH JEEM INITIAL FORMARABIC LI" +
"GATURE GHAIN WITH MEEM INITIAL FORMARABIC LIGATURE FEH WITH JEEM INITIAL" +
" FORMARABIC LIGATURE FEH WITH HAH INITIAL FORMARABIC LIGATURE FEH WITH K" +
"HAH INITIAL FORMARABIC LIGATURE FEH WITH MEEM INITIAL FORMARABIC LIGATUR" +
"E QAF WITH HAH INITIAL FORMARABIC LIGATURE QAF WITH MEEM INITIAL FORMARA" +
"BIC LIGATURE KAF WITH JEEM INITIAL FORMARABIC LIGATURE KAF WITH HAH INIT" +
"IAL FORMARABIC LIGATURE KAF WITH KHAH INITIAL FORMARABIC LIGATURE KAF WI" +
"TH LAM INITIAL FORMARABIC LIGATURE KAF WITH MEEM INITIAL FORMARABIC LIGA" +
"TURE LAM WITH JEEM INITIAL FORMARABIC LIGATURE LAM WITH HAH INITIAL FORM" +
"ARABIC LIGATURE LAM WITH KHAH INITIAL FORMARABIC LIGATURE LAM WITH MEEM " +
"INITIAL FORMARABIC LIGATURE LAM WITH HEH INITIAL FORMARABIC LIGATURE MEE" +
"M WITH JEEM INITIAL FORMARABIC LIGATURE MEEM WITH HAH INITIAL FORMARABIC" +
" LIGATURE MEEM WITH KHAH INITIAL FORMARABIC LIGATURE MEEM WITH MEEM INIT" +
"IAL FORMARABIC LIGATURE NOON WITH JEEM INITIAL FORMARABIC LIGATURE NOON " +
"WITH HAH INITIAL FORMARABIC LIGATURE NOON WITH KHAH INITIAL FORMARABIC L" +
"IGATURE NOON WITH MEEM INITIAL FORMARABIC LIGATURE NOON WITH HEH INITIAL" +
" FORMARABIC LIGATURE HEH WITH JEEM INITIAL FORMARABIC LIGATURE HEH WITH " +
"MEEM INITIAL FORMARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORMA" +
"RABIC LIGATURE YEH WITH JEEM INITIAL FORMARABIC LIGATURE YEH WITH HAH IN" +
"ITIAL FORMARABIC LIGATURE YEH WITH KHAH INITIAL FORMARABIC LIGATURE YEH " +
"WITH MEEM INITIAL FORMARABIC LIGATURE YEH WITH HEH INITIAL FORMARABIC LI" +
"GATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORMARABIC LIGATURE YEH WIT" +
"H HAMZA ABOVE WITH HEH MEDIAL FORMARABIC LIGATURE BEH WITH MEEM MEDIAL F" +
"ORMARABIC LIGATURE BEH WITH HEH MEDIAL FORMARABIC LIGATURE TEH WITH MEEM" +
" MEDIAL FORMARABIC LIGATURE TEH WITH HEH MEDIAL FORMARABIC LIGATURE THEH" +
" WITH MEEM MEDIAL FORMARABIC LIGATURE THEH WITH HEH MEDIAL FORMARABIC LI" +
"GATURE SEEN WITH MEEM MEDIAL FORMARABIC LIGATURE SEEN WITH HEH MEDIAL FO" +
"RMARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORMARABIC LIGATURE SHEEN WITH " +
"HEH MEDIAL FORMARABIC LIGATURE KAF WITH LAM MEDIAL FORMARABIC LIGATURE K" +
"AF WITH MEEM MEDIAL FORMARABIC LIGATURE LAM WITH MEEM MEDIAL FORMARABIC " +
"LIGATURE NOON WITH MEEM MEDIAL FORMARABIC LIGATURE NOON WITH HEH MEDIAL " +
"FORMARABIC LIGATURE YEH WITH MEEM MEDIAL FORMARABIC LIGATURE YEH WITH HE" +
"H MEDIAL FORMARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORMARABIC LIGATUR" +
"E SHADDA WITH DAMMA MEDIAL FORMARABIC LIGATURE SHADDA WITH KASRA MEDIAL " +
"FORMARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE T") + ("" +
"AH WITH YEH ISOLATED FORMARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED " +
"FORMARABIC LIGATURE AIN WITH YEH ISOLATED FORMARABIC LIGATURE GHAIN WITH" +
" ALEF MAKSURA ISOLATED FORMARABIC LIGATURE GHAIN WITH YEH ISOLATED FORMA" +
"RABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE SEEN " +
"WITH YEH ISOLATED FORMARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED F" +
"ORMARABIC LIGATURE SHEEN WITH YEH ISOLATED FORMARABIC LIGATURE HAH WITH " +
"ALEF MAKSURA ISOLATED FORMARABIC LIGATURE HAH WITH YEH ISOLATED FORMARAB" +
"IC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE JEEM WIT" +
"H YEH ISOLATED FORMARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORMA" +
"RABIC LIGATURE KHAH WITH YEH ISOLATED FORMARABIC LIGATURE SAD WITH ALEF " +
"MAKSURA ISOLATED FORMARABIC LIGATURE SAD WITH YEH ISOLATED FORMARABIC LI" +
"GATURE DAD WITH ALEF MAKSURA ISOLATED FORMARABIC LIGATURE DAD WITH YEH I" +
"SOLATED FORMARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORMARABIC LIGATURE" +
" SHEEN WITH HAH ISOLATED FORMARABIC LIGATURE SHEEN WITH KHAH ISOLATED FO" +
"RMARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORMARABIC LIGATURE SHEEN WIT" +
"H REH ISOLATED FORMARABIC LIGATURE SEEN WITH REH ISOLATED FORMARABIC LIG" +
"ATURE SAD WITH REH ISOLATED FORMARABIC LIGATURE DAD WITH REH ISOLATED FO" +
"RMARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE TAH WI" +
"TH YEH FINAL FORMARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORMARABIC " +
"LIGATURE AIN WITH YEH FINAL FORMARABIC LIGATURE GHAIN WITH ALEF MAKSURA " +
"FINAL FORMARABIC LIGATURE GHAIN WITH YEH FINAL FORMARABIC LIGATURE SEEN " +
"WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE SEEN WITH YEH FINAL FORMARAB" +
"IC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE SHEEN WITH" +
" YEH FINAL FORMARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORMARABIC LI" +
"GATURE HAH WITH YEH FINAL FORMARABIC LIGATURE JEEM WITH ALEF MAKSURA FIN" +
"AL FORMARABIC LIGATURE JEEM WITH YEH FINAL FORMARABIC LIGATURE KHAH WITH" +
" ALEF MAKSURA FINAL FORMARABIC LIGATURE KHAH WITH YEH FINAL FORMARABIC L" +
"IGATURE SAD WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE SAD WITH YEH FIN" +
"AL FORMARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE D" +
"AD WITH YEH FINAL FORMARABIC LIGATURE SHEEN WITH JEEM FINAL FORMARABIC L" +
"IGATURE SHEEN WITH HAH FINAL FORMARABIC LIGATURE SHEEN WITH KHAH FINAL F" +
"ORMARABIC LIGATURE SHEEN WITH MEEM FINAL FORMARABIC LIGATURE SHEEN WITH " +
"REH FINAL FORMARABIC LIGATURE SEEN WITH REH FINAL FORMARABIC LIGATURE SA" +
"D WITH REH FINAL FORMARABIC LIGATURE DAD WITH REH FINAL FORMARABIC LIGAT" +
"URE SHEEN WITH JEEM INITIAL FORMARABIC LIGATURE SHEEN WITH HAH INITIAL F" +
"ORMARABIC LIGATURE SHEEN WITH KHAH INITIAL FORMARABIC LIGATURE SHEEN WIT" +
"H MEEM INITIAL FORMARABIC LIGATURE SEEN WITH HEH INITIAL FORMARABIC LIGA" +
"TURE SHEEN WITH HEH INITIAL FORMARABIC LIGATURE TAH WITH MEEM INITIAL FO" +
"RMARABIC LIGATURE SEEN WITH JEEM MEDIAL FORMARABIC LIGATURE SEEN WITH HA" +
"H MEDIAL FORMARABIC LIGATURE SEEN WITH KHAH MEDIAL FORMARABIC LIGATURE S" +
"HEEN WITH JEEM MEDIAL FORMARABIC LIGATURE SHEEN WITH HAH MEDIAL FORMARAB" +
"IC LIGATURE SHEEN WITH KHAH MEDIAL FORMARABIC LIGATURE TAH WITH MEEM MED" +
"IAL FORMARABIC LIGATURE ZAH WITH MEEM MEDIAL FORMARABIC LIGATURE ALEF WI" +
"TH FATHATAN FINAL FORMARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORMOR" +
"NATE LEFT PARENTHESISORNATE RIGHT PARENTHESISARABIC LIGATURE RAHIMAHU AL" +
"LAAHARABIC LIGATURE RADI ALLAAHU ANHARABIC LIGATURE RADI ALLAAHU ANHAAAR" +
"ABIC LIGATURE RADI ALLAAHU ANHUMARABIC LIGATURE RADI ALLAAHU ANHUMAAARAB" +
"IC LIGATURE RADI ALLAAHU ANHUNNAARABIC LIGATURE SALLALLAAHU ALAYHI WA-AA" +
"LIHARABIC LIGATURE ALAYHI AS-SALAAMARABIC LIGATURE ALAYHIM AS-SALAAMARAB" +
"IC LIGATURE ALAYHIMAA AS-SALAAMARABIC LIGATURE ALAYHI AS-SALAATU WAS-SAL" +
"AAMARABIC LIGATURE QUDDISA SIRRAHARABIC LIGATURE SALLALLAHU ALAYHI WAAAL" +
"IHEE WA-SALLAMARABIC LIGATURE ALAYHAA AS-SALAAMARABIC LIGATURE TABAARAKA" +
" WA-TAAALAAARABIC LIGATURE RAHIMAHUM ALLAAHARABIC LIGATURE TEH WITH JEEM" +
" WITH MEEM INITIAL FORMARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM" +
"ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORMARABIC LIGATURE TEH W" +
"ITH HAH WITH MEEM INITIAL FORMARABIC LIGATURE TEH WITH KHAH WITH MEEM IN" +
"ITIAL FORMARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORMARABIC LIG" +
"ATURE TEH WITH MEEM WITH HAH INITIAL FORMARABIC LIGATURE TEH WITH MEEM W" +
"ITH KHAH INITIAL FORMARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORMA" +
"RABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORMARABIC LIGATURE HAH W" +
"ITH MEEM WITH YEH FINAL FORMARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKS" +
"URA FINAL FORMARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORMARABIC" +
" LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORMARABIC LIGATURE SEEN WITH " +
"JEEM WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE SEEN WITH MEEM WITH HAH") + ("" +
" FINAL FORMARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORMARABIC LI" +
"GATURE SEEN WITH MEEM WITH JEEM INITIAL FORMARABIC LIGATURE SEEN WITH ME" +
"EM WITH MEEM FINAL FORMARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL " +
"FORMARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORMARABIC LIGATURE SAD " +
"WITH HAH WITH HAH INITIAL FORMARABIC LIGATURE SAD WITH MEEM WITH MEEM FI" +
"NAL FORMARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORMARABIC LIGATU" +
"RE SHEEN WITH HAH WITH MEEM INITIAL FORMARABIC LIGATURE SHEEN WITH JEEM " +
"WITH YEH FINAL FORMARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORMA" +
"RABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORMARABIC LIGATURE SHE" +
"EN WITH MEEM WITH MEEM FINAL FORMARABIC LIGATURE SHEEN WITH MEEM WITH ME" +
"EM INITIAL FORMARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM" +
"ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORMARABIC LIGATURE DAD WI" +
"TH KHAH WITH MEEM INITIAL FORMARABIC LIGATURE TAH WITH MEEM WITH HAH FIN" +
"AL FORMARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORMARABIC LIGATUR" +
"E TAH WITH MEEM WITH MEEM INITIAL FORMARABIC LIGATURE TAH WITH MEEM WITH" +
" YEH FINAL FORMARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORMARABIC " +
"LIGATURE AIN WITH MEEM WITH MEEM FINAL FORMARABIC LIGATURE AIN WITH MEEM" +
" WITH MEEM INITIAL FORMARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA F" +
"INAL FORMARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORMARABIC LIGA" +
"TURE GHAIN WITH MEEM WITH YEH FINAL FORMARABIC LIGATURE GHAIN WITH MEEM " +
"WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE FEH WITH KHAH WITH MEEM FINA" +
"L FORMARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORMARABIC LIGATUR" +
"E QAF WITH MEEM WITH HAH FINAL FORMARABIC LIGATURE QAF WITH MEEM WITH ME" +
"EM FINAL FORMARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORMARABIC LIG" +
"ATURE LAM WITH HAH WITH YEH FINAL FORMARABIC LIGATURE LAM WITH HAH WITH " +
"ALEF MAKSURA FINAL FORMARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL F" +
"ORMARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORMARABIC LIGATURE LAM" +
" WITH KHAH WITH MEEM FINAL FORMARABIC LIGATURE LAM WITH KHAH WITH MEEM I" +
"NITIAL FORMARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORMARABIC LIGAT" +
"URE LAM WITH MEEM WITH HAH INITIAL FORMARABIC LIGATURE MEEM WITH HAH WIT" +
"H JEEM INITIAL FORMARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORMA" +
"RABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORMARABIC LIGATURE MEEM WIT" +
"H JEEM WITH HAH INITIAL FORMARABIC LIGATURE MEEM WITH JEEM WITH MEEM INI" +
"TIAL FORMARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORMARABIC LIG" +
"ATURE MEEM WITH KHAH WITH MEEM INITIAL FORMARABIC LIGATURE RAHMATU ALLAA" +
"HI ALAYHARABIC LIGATURE RAHMATU ALLAAHI ALAYHAAARABIC LIGATURE MEEM WITH" +
" JEEM WITH KHAH INITIAL FORMARABIC LIGATURE HEH WITH MEEM WITH JEEM INIT" +
"IAL FORMARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORMARABIC LIGAT" +
"URE NOON WITH HAH WITH MEEM INITIAL FORMARABIC LIGATURE NOON WITH HAH WI" +
"TH ALEF MAKSURA FINAL FORMARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL" +
" FORMARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORMARABIC LIGATUR" +
"E NOON WITH JEEM WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE NOON WITH M" +
"EEM WITH YEH FINAL FORMARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA " +
"FINAL FORMARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORMARABIC LIGAT" +
"URE YEH WITH MEEM WITH MEEM INITIAL FORMARABIC LIGATURE BEH WITH KHAH WI" +
"TH YEH FINAL FORMARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORMARABIC" +
" LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE TEH " +
"WITH KHAH WITH YEH FINAL FORMARABIC LIGATURE TEH WITH KHAH WITH ALEF MAK" +
"SURA FINAL FORMARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORMARABIC L" +
"IGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORMARABIC LIGATURE JEEM W" +
"ITH MEEM WITH YEH FINAL FORMARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKS" +
"URA FINAL FORMARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FOR" +
"MARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORMARABIC LIGAT" +
"URE SAD WITH HAH WITH YEH FINAL FORMARABIC LIGATURE SHEEN WITH HAH WITH " +
"YEH FINAL FORMARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORMARABIC LIG" +
"ATURE LAM WITH JEEM WITH YEH FINAL FORMARABIC LIGATURE LAM WITH MEEM WIT" +
"H YEH FINAL FORMARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORMARABIC L" +
"IGATURE YEH WITH JEEM WITH YEH FINAL FORMARABIC LIGATURE YEH WITH MEEM W" +
"ITH YEH FINAL FORMARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORMARAB" +
"IC LIGATURE QAF WITH MEEM WITH YEH FINAL FORMARABIC LIGATURE NOON WITH H" +
"AH WITH YEH FINAL FORMARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FOR" +
"MARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORMARABIC LIGATURE AIN " +
"WITH MEEM WITH YEH FINAL FORMARABIC LIGATURE KAF WITH MEEM WITH YEH FINA" +
"L FORMARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORMARABIC LIGATUR") + ("" +
"E MEEM WITH KHAH WITH YEH FINAL FORMARABIC LIGATURE LAM WITH JEEM WITH M" +
"EEM INITIAL FORMARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORMARABIC" +
" LIGATURE LAM WITH JEEM WITH MEEM FINAL FORMARABIC LIGATURE NOON WITH JE" +
"EM WITH HAH FINAL FORMARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORMA" +
"RABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORMARABIC LIGATURE MEEM WIT" +
"H JEEM WITH YEH FINAL FORMARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL F" +
"ORMARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORMARABIC LIGATURE KAF W" +
"ITH MEEM WITH MEEM INITIAL FORMARABIC LIGATURE AIN WITH JEEM WITH MEEM I" +
"NITIAL FORMARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORMARABIC LI" +
"GATURE SEEN WITH KHAH WITH YEH FINAL FORMARABIC LIGATURE NOON WITH JEEM " +
"WITH YEH FINAL FORMARABIC LIGATURE RAHIMAHU ALLAAH TAAALAAARABIC LIGATUR" +
"E RADI ALLAAHU TAAALAA ANHARABIC LIGATURE RADI ALLAAHU TAAALAA ANHAAARAB" +
"IC LIGATURE RADI ALLAAHU TAAALAA ANHUMAAARABIC LIGATURE SALLALLAHU ALAYH" +
"I WA-ALAA AALIHEE WA-SALLAMARABIC LIGATURE AJJAL ALLAAHU TAAALAA FARAJAH" +
"U ASH-SHAREEFARABIC LIGATURE KARRAMA ALLAAHU WAJHAHARABIC LIGATURE SALAA" +
"MUHU ALAYNAAARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FOR" +
"MARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORMARABIC LIGA" +
"TURE ALLAH ISOLATED FORMARABIC LIGATURE AKBAR ISOLATED FORMARABIC LIGATU" +
"RE MOHAMMAD ISOLATED FORMARABIC LIGATURE SALAM ISOLATED FORMARABIC LIGAT" +
"URE RASOUL ISOLATED FORMARABIC LIGATURE ALAYHE ISOLATED FORMARABIC LIGAT" +
"URE WASALLAM ISOLATED FORMARABIC LIGATURE SALLA ISOLATED FORMARABIC LIGA" +
"TURE SALLALLAHOU ALAYHE WASALLAMARABIC LIGATURE JALLAJALALOUHOURIAL SIGN" +
"ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEMARABIC LIGATURE SUBHAANAHU " +
"WA TAAALAAARABIC LIGATURE AZZA WA JALLVARIATION SELECTOR-1VARIATION SELE" +
"CTOR-2VARIATION SELECTOR-3VARIATION SELECTOR-4VARIATION SELECTOR-5VARIAT" +
"ION SELECTOR-6VARIATION SELECTOR-7VARIATION SELECTOR-8VARIATION SELECTOR" +
"-9VARIATION SELECTOR-10VARIATION SELECTOR-11VARIATION SELECTOR-12VARIATI" +
"ON SELECTOR-13VARIATION SELECTOR-14VARIATION SELECTOR-15VARIATION SELECT" +
"OR-16PRESENTATION FORM FOR VERTICAL COMMAPRESENTATION FORM FOR VERTICAL " +
"IDEOGRAPHIC COMMAPRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOPPRE" +
"SENTATION FORM FOR VERTICAL COLONPRESENTATION FORM FOR VERTICAL SEMICOLO" +
"NPRESENTATION FORM FOR VERTICAL EXCLAMATION MARKPRESENTATION FORM FOR VE" +
"RTICAL QUESTION MARKPRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR" +
" BRACKETPRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCETPRE" +
"SENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSISCOMBINING LIGATURE LEFT H" +
"ALFCOMBINING LIGATURE RIGHT HALFCOMBINING DOUBLE TILDE LEFT HALFCOMBININ" +
"G DOUBLE TILDE RIGHT HALFCOMBINING MACRON LEFT HALFCOMBINING MACRON RIGH" +
"T HALFCOMBINING CONJOINING MACRONCOMBINING LIGATURE LEFT HALF BELOWCOMBI" +
"NING LIGATURE RIGHT HALF BELOWCOMBINING TILDE LEFT HALF BELOWCOMBINING T" +
"ILDE RIGHT HALF BELOWCOMBINING MACRON LEFT HALF BELOWCOMBINING MACRON RI" +
"GHT HALF BELOWCOMBINING CONJOINING MACRON BELOWCOMBINING CYRILLIC TITLO " +
"LEFT HALFCOMBINING CYRILLIC TITLO RIGHT HALFPRESENTATION FORM FOR VERTIC" +
"AL TWO DOT LEADERPRESENTATION FORM FOR VERTICAL EM DASHPRESENTATION FORM" +
" FOR VERTICAL EN DASHPRESENTATION FORM FOR VERTICAL LOW LINEPRESENTATION" +
" FORM FOR VERTICAL WAVY LOW LINEPRESENTATION FORM FOR VERTICAL LEFT PARE" +
"NTHESISPRESENTATION FORM FOR VERTICAL RIGHT PARENTHESISPRESENTATION FORM" +
" FOR VERTICAL LEFT CURLY BRACKETPRESENTATION FORM FOR VERTICAL RIGHT CUR" +
"LY BRACKETPRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKETPRES" +
"ENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKETPRESENTATION FORM" +
" FOR VERTICAL LEFT BLACK LENTICULAR BRACKETPRESENTATION FORM FOR VERTICA" +
"L RIGHT BLACK LENTICULAR BRACKETPRESENTATION FORM FOR VERTICAL LEFT DOUB" +
"LE ANGLE BRACKETPRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKE" +
"TPRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKETPRESENTATION FORM FOR " +
"VERTICAL RIGHT ANGLE BRACKETPRESENTATION FORM FOR VERTICAL LEFT CORNER B" +
"RACKETPRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKETPRESENTATION FO" +
"RM FOR VERTICAL LEFT WHITE CORNER BRACKETPRESENTATION FORM FOR VERTICAL " +
"RIGHT WHITE CORNER BRACKETSESAME DOTWHITE SESAME DOTPRESENTATION FORM FO" +
"R VERTICAL LEFT SQUARE BRACKETPRESENTATION FORM FOR VERTICAL RIGHT SQUAR" +
"E BRACKETDASHED OVERLINECENTRELINE OVERLINEWAVY OVERLINEDOUBLE WAVY OVER" +
"LINEDASHED LOW LINECENTRELINE LOW LINEWAVY LOW LINESMALL COMMASMALL IDEO" +
"GRAPHIC COMMASMALL FULL STOPSMALL SEMICOLONSMALL COLONSMALL QUESTION MAR" +
"KSMALL EXCLAMATION MARKSMALL EM DASHSMALL LEFT PARENTHESISSMALL RIGHT PA" +
"RENTHESISSMALL LEFT CURLY BRACKETSMALL RIGHT CURLY BRACKETSMALL LEFT TOR" +
"TOISE SHELL BRACKETSMALL RIGHT TORTOISE SHELL BRACKETSMALL NUMBER SIGNSM") + ("" +
"ALL AMPERSANDSMALL ASTERISKSMALL PLUS SIGNSMALL HYPHEN-MINUSSMALL LESS-T" +
"HAN SIGNSMALL GREATER-THAN SIGNSMALL EQUALS SIGNSMALL REVERSE SOLIDUSSMA" +
"LL DOLLAR SIGNSMALL PERCENT SIGNSMALL COMMERCIAL ATARABIC FATHATAN ISOLA" +
"TED FORMARABIC TATWEEL WITH FATHATAN ABOVEARABIC DAMMATAN ISOLATED FORMA" +
"RABIC TAIL FRAGMENTARABIC KASRATAN ISOLATED FORMARABIC FATHA ISOLATED FO" +
"RMARABIC FATHA MEDIAL FORMARABIC DAMMA ISOLATED FORMARABIC DAMMA MEDIAL " +
"FORMARABIC KASRA ISOLATED FORMARABIC KASRA MEDIAL FORMARABIC SHADDA ISOL" +
"ATED FORMARABIC SHADDA MEDIAL FORMARABIC SUKUN ISOLATED FORMARABIC SUKUN" +
" MEDIAL FORMARABIC LETTER HAMZA ISOLATED FORMARABIC LETTER ALEF WITH MAD" +
"DA ABOVE ISOLATED FORMARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORMARAB" +
"IC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORMARABIC LETTER ALEF WITH HAM" +
"ZA ABOVE FINAL FORMARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORMARABI" +
"C LETTER WAW WITH HAMZA ABOVE FINAL FORMARABIC LETTER ALEF WITH HAMZA BE" +
"LOW ISOLATED FORMARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORMARABIC LE" +
"TTER YEH WITH HAMZA ABOVE ISOLATED FORMARABIC LETTER YEH WITH HAMZA ABOV" +
"E FINAL FORMARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORMARABIC LETTER" +
" YEH WITH HAMZA ABOVE MEDIAL FORMARABIC LETTER ALEF ISOLATED FORMARABIC " +
"LETTER ALEF FINAL FORMARABIC LETTER BEH ISOLATED FORMARABIC LETTER BEH F" +
"INAL FORMARABIC LETTER BEH INITIAL FORMARABIC LETTER BEH MEDIAL FORMARAB" +
"IC LETTER TEH MARBUTA ISOLATED FORMARABIC LETTER TEH MARBUTA FINAL FORMA" +
"RABIC LETTER TEH ISOLATED FORMARABIC LETTER TEH FINAL 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 FORMARABIC LETTER JEE" +
"M FINAL FORMARABIC LETTER JEEM INITIAL FORMARABIC LETTER JEEM MEDIAL FOR" +
"MARABIC LETTER HAH ISOLATED FORMARABIC LETTER HAH FINAL FORMARABIC LETTE" +
"R HAH INITIAL FORMARABIC LETTER HAH MEDIAL FORMARABIC LETTER KHAH ISOLAT" +
"ED FORMARABIC LETTER KHAH FINAL FORMARABIC LETTER KHAH INITIAL FORMARABI" +
"C LETTER KHAH MEDIAL FORMARABIC LETTER DAL ISOLATED FORMARABIC LETTER DA" +
"L FINAL FORMARABIC LETTER THAL ISOLATED FORMARABIC LETTER THAL FINAL FOR" +
"MARABIC LETTER REH ISOLATED FORMARABIC LETTER REH FINAL FORMARABIC LETTE" +
"R ZAIN ISOLATED FORMARABIC LETTER ZAIN FINAL FORMARABIC LETTER SEEN ISOL" +
"ATED FORMARABIC LETTER SEEN FINAL FORMARABIC LETTER SEEN INITIAL FORMARA" +
"BIC LETTER SEEN MEDIAL FORMARABIC LETTER SHEEN ISOLATED FORMARABIC LETTE" +
"R SHEEN FINAL FORMARABIC LETTER SHEEN INITIAL FORMARABIC LETTER SHEEN ME" +
"DIAL FORMARABIC LETTER SAD ISOLATED FORMARABIC LETTER SAD FINAL FORMARAB" +
"IC LETTER SAD INITIAL FORMARABIC LETTER SAD MEDIAL FORMARABIC LETTER DAD" +
" ISOLATED FORMARABIC LETTER DAD FINAL FORMARABIC LETTER DAD INITIAL FORM" +
"ARABIC LETTER DAD MEDIAL FORMARABIC LETTER TAH ISOLATED FORMARABIC LETTE" +
"R TAH FINAL FORMARABIC LETTER TAH INITIAL FORMARABIC LETTER TAH MEDIAL F" +
"ORMARABIC LETTER ZAH ISOLATED FORMARABIC LETTER ZAH FINAL FORMARABIC LET" +
"TER ZAH INITIAL FORMARABIC LETTER ZAH MEDIAL FORMARABIC LETTER AIN ISOLA" +
"TED FORMARABIC LETTER AIN FINAL FORMARABIC LETTER AIN INITIAL FORMARABIC" +
" LETTER AIN MEDIAL FORMARABIC LETTER GHAIN ISOLATED FORMARABIC LETTER GH" +
"AIN FINAL FORMARABIC LETTER GHAIN INITIAL FORMARABIC LETTER GHAIN MEDIAL" +
" FORMARABIC LETTER FEH ISOLATED FORMARABIC LETTER FEH FINAL FORMARABIC L" +
"ETTER FEH INITIAL FORMARABIC LETTER FEH MEDIAL FORMARABIC LETTER QAF ISO" +
"LATED FORMARABIC LETTER QAF FINAL FORMARABIC LETTER QAF INITIAL FORMARAB" +
"IC LETTER QAF MEDIAL FORMARABIC LETTER KAF ISOLATED FORMARABIC LETTER KA" +
"F FINAL FORMARABIC LETTER KAF INITIAL FORMARABIC LETTER KAF MEDIAL FORMA" +
"RABIC LETTER LAM ISOLATED FORMARABIC LETTER LAM FINAL 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 FORMARABIC LETTER NOO" +
"N FINAL FORMARABIC LETTER NOON INITIAL FORMARABIC LETTER NOON MEDIAL FOR" +
"MARABIC LETTER HEH ISOLATED FORMARABIC LETTER HEH FINAL FORMARABIC LETTE" +
"R HEH INITIAL FORMARABIC LETTER HEH MEDIAL FORMARABIC LETTER WAW ISOLATE" +
"D FORMARABIC LETTER WAW FINAL FORMARABIC LETTER ALEF MAKSURA ISOLATED FO" +
"RMARABIC LETTER ALEF MAKSURA FINAL FORMARABIC LETTER YEH ISOLATED FORMAR" +
"ABIC LETTER YEH FINAL FORMARABIC LETTER YEH INITIAL FORMARABIC LETTER YE" +
"H MEDIAL FORMARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FOR" +
"MARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORMARABIC LIGATUR" +
"E LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORMARABIC LIGATURE LAM WITH A" +
"LEF WITH HAMZA ABOVE FINAL FORMARABIC LIGATURE LAM WITH ALEF WITH HAMZA ") + ("" +
"BELOW ISOLATED FORMARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL " +
"FORMARABIC LIGATURE LAM WITH ALEF ISOLATED FORMARABIC LIGATURE LAM WITH " +
"ALEF FINAL FORMZERO WIDTH NO-BREAK SPACEFULLWIDTH EXCLAMATION MARKFULLWI" +
"DTH QUOTATION MARKFULLWIDTH NUMBER SIGNFULLWIDTH DOLLAR SIGNFULLWIDTH PE" +
"RCENT SIGNFULLWIDTH AMPERSANDFULLWIDTH APOSTROPHEFULLWIDTH LEFT PARENTHE" +
"SISFULLWIDTH RIGHT PARENTHESISFULLWIDTH ASTERISKFULLWIDTH PLUS SIGNFULLW" +
"IDTH COMMAFULLWIDTH HYPHEN-MINUSFULLWIDTH FULL STOPFULLWIDTH SOLIDUSFULL" +
"WIDTH DIGIT ZEROFULLWIDTH DIGIT ONEFULLWIDTH DIGIT TWOFULLWIDTH DIGIT TH" +
"REEFULLWIDTH DIGIT FOURFULLWIDTH DIGIT FIVEFULLWIDTH DIGIT SIXFULLWIDTH " +
"DIGIT SEVENFULLWIDTH DIGIT EIGHTFULLWIDTH DIGIT NINEFULLWIDTH COLONFULLW" +
"IDTH SEMICOLONFULLWIDTH LESS-THAN SIGNFULLWIDTH EQUALS SIGNFULLWIDTH GRE" +
"ATER-THAN SIGNFULLWIDTH QUESTION MARKFULLWIDTH COMMERCIAL ATFULLWIDTH LA" +
"TIN CAPITAL LETTER AFULLWIDTH LATIN CAPITAL LETTER BFULLWIDTH LATIN CAPI" +
"TAL LETTER CFULLWIDTH LATIN CAPITAL LETTER DFULLWIDTH LATIN CAPITAL LETT" +
"ER EFULLWIDTH LATIN CAPITAL LETTER FFULLWIDTH LATIN CAPITAL LETTER GFULL" +
"WIDTH LATIN CAPITAL LETTER HFULLWIDTH LATIN CAPITAL LETTER IFULLWIDTH LA" +
"TIN CAPITAL LETTER JFULLWIDTH LATIN CAPITAL LETTER KFULLWIDTH LATIN CAPI" +
"TAL LETTER LFULLWIDTH LATIN CAPITAL LETTER MFULLWIDTH LATIN CAPITAL LETT" +
"ER NFULLWIDTH LATIN CAPITAL LETTER OFULLWIDTH LATIN CAPITAL LETTER PFULL" +
"WIDTH LATIN CAPITAL LETTER QFULLWIDTH LATIN CAPITAL LETTER RFULLWIDTH LA" +
"TIN CAPITAL LETTER SFULLWIDTH LATIN CAPITAL LETTER TFULLWIDTH LATIN CAPI" +
"TAL LETTER UFULLWIDTH LATIN CAPITAL LETTER VFULLWIDTH LATIN CAPITAL LETT" +
"ER WFULLWIDTH LATIN CAPITAL LETTER XFULLWIDTH LATIN CAPITAL LETTER YFULL" +
"WIDTH LATIN CAPITAL LETTER ZFULLWIDTH LEFT SQUARE BRACKETFULLWIDTH REVER" +
"SE SOLIDUSFULLWIDTH RIGHT SQUARE BRACKETFULLWIDTH CIRCUMFLEX ACCENTFULLW" +
"IDTH LOW LINEFULLWIDTH GRAVE ACCENTFULLWIDTH LATIN SMALL LETTER AFULLWID" +
"TH LATIN SMALL LETTER BFULLWIDTH LATIN SMALL LETTER CFULLWIDTH LATIN SMA" +
"LL LETTER DFULLWIDTH LATIN SMALL LETTER EFULLWIDTH LATIN SMALL LETTER FF" +
"ULLWIDTH LATIN SMALL LETTER GFULLWIDTH LATIN SMALL LETTER HFULLWIDTH LAT" +
"IN SMALL LETTER IFULLWIDTH LATIN SMALL LETTER JFULLWIDTH LATIN SMALL LET" +
"TER KFULLWIDTH LATIN SMALL LETTER LFULLWIDTH LATIN SMALL LETTER MFULLWID" +
"TH LATIN SMALL LETTER NFULLWIDTH LATIN SMALL LETTER OFULLWIDTH LATIN SMA" +
"LL LETTER PFULLWIDTH LATIN SMALL LETTER QFULLWIDTH LATIN SMALL LETTER RF" +
"ULLWIDTH LATIN SMALL LETTER SFULLWIDTH LATIN SMALL LETTER TFULLWIDTH LAT" +
"IN SMALL LETTER UFULLWIDTH LATIN SMALL LETTER VFULLWIDTH LATIN SMALL LET" +
"TER WFULLWIDTH LATIN SMALL LETTER XFULLWIDTH LATIN SMALL LETTER YFULLWID" +
"TH LATIN SMALL LETTER ZFULLWIDTH LEFT CURLY BRACKETFULLWIDTH VERTICAL LI" +
"NEFULLWIDTH RIGHT CURLY BRACKETFULLWIDTH TILDEFULLWIDTH LEFT WHITE PAREN" +
"THESISFULLWIDTH RIGHT WHITE PARENTHESISHALFWIDTH IDEOGRAPHIC FULL STOPHA" +
"LFWIDTH LEFT CORNER BRACKETHALFWIDTH RIGHT CORNER BRACKETHALFWIDTH IDEOG" +
"RAPHIC COMMAHALFWIDTH KATAKANA MIDDLE DOTHALFWIDTH KATAKANA LETTER WOHAL" +
"FWIDTH KATAKANA LETTER SMALL AHALFWIDTH KATAKANA LETTER SMALL IHALFWIDTH" +
" KATAKANA LETTER SMALL UHALFWIDTH KATAKANA LETTER SMALL EHALFWIDTH KATAK" +
"ANA LETTER SMALL OHALFWIDTH KATAKANA LETTER SMALL YAHALFWIDTH KATAKANA L" +
"ETTER SMALL YUHALFWIDTH KATAKANA LETTER SMALL YOHALFWIDTH KATAKANA LETTE" +
"R SMALL TUHALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARKHALFWIDTH KATA" +
"KANA LETTER AHALFWIDTH KATAKANA LETTER IHALFWIDTH KATAKANA LETTER UHALFW" +
"IDTH KATAKANA LETTER EHALFWIDTH KATAKANA LETTER OHALFWIDTH KATAKANA LETT" +
"ER KAHALFWIDTH KATAKANA LETTER KIHALFWIDTH KATAKANA LETTER KUHALFWIDTH K" +
"ATAKANA LETTER KEHALFWIDTH KATAKANA LETTER KOHALFWIDTH KATAKANA LETTER S" +
"AHALFWIDTH KATAKANA LETTER SIHALFWIDTH KATAKANA LETTER SUHALFWIDTH KATAK" +
"ANA LETTER SEHALFWIDTH KATAKANA LETTER SOHALFWIDTH KATAKANA LETTER TAHAL" +
"FWIDTH KATAKANA LETTER TIHALFWIDTH KATAKANA LETTER TUHALFWIDTH KATAKANA " +
"LETTER TEHALFWIDTH KATAKANA LETTER TOHALFWIDTH KATAKANA LETTER NAHALFWID" +
"TH KATAKANA LETTER NIHALFWIDTH KATAKANA LETTER NUHALFWIDTH KATAKANA LETT" +
"ER NEHALFWIDTH KATAKANA LETTER NOHALFWIDTH KATAKANA LETTER HAHALFWIDTH K" +
"ATAKANA LETTER HIHALFWIDTH KATAKANA LETTER HUHALFWIDTH KATAKANA LETTER H" +
"EHALFWIDTH KATAKANA LETTER HOHALFWIDTH KATAKANA LETTER MAHALFWIDTH KATAK" +
"ANA LETTER MIHALFWIDTH KATAKANA LETTER MUHALFWIDTH KATAKANA LETTER MEHAL" +
"FWIDTH KATAKANA LETTER MOHALFWIDTH KATAKANA LETTER YAHALFWIDTH KATAKANA " +
"LETTER YUHALFWIDTH KATAKANA LETTER YOHALFWIDTH KATAKANA LETTER RAHALFWID" +
"TH KATAKANA LETTER RIHALFWIDTH KATAKANA LETTER RUHALFWIDTH KATAKANA LETT" +
"ER REHALFWIDTH KATAKANA LETTER ROHALFWIDTH KATAKANA LETTER WAHALFWIDTH K" +
"ATAKANA LETTER NHALFWIDTH KATAKANA VOICED SOUND MARKHALFWIDTH KATAKANA S") + ("" +
"EMI-VOICED SOUND MARKHALFWIDTH HANGUL FILLERHALFWIDTH HANGUL LETTER KIYE" +
"OKHALFWIDTH HANGUL LETTER SSANGKIYEOKHALFWIDTH HANGUL LETTER KIYEOK-SIOS" +
"HALFWIDTH HANGUL LETTER NIEUNHALFWIDTH HANGUL LETTER NIEUN-CIEUCHALFWIDT" +
"H HANGUL LETTER NIEUN-HIEUHHALFWIDTH HANGUL LETTER TIKEUTHALFWIDTH HANGU" +
"L LETTER SSANGTIKEUTHALFWIDTH HANGUL LETTER RIEULHALFWIDTH HANGUL LETTER" +
" RIEUL-KIYEOKHALFWIDTH HANGUL LETTER RIEUL-MIEUMHALFWIDTH HANGUL LETTER " +
"RIEUL-PIEUPHALFWIDTH HANGUL LETTER RIEUL-SIOSHALFWIDTH HANGUL LETTER RIE" +
"UL-THIEUTHHALFWIDTH HANGUL LETTER RIEUL-PHIEUPHHALFWIDTH HANGUL LETTER R" +
"IEUL-HIEUHHALFWIDTH HANGUL LETTER MIEUMHALFWIDTH HANGUL LETTER PIEUPHALF" +
"WIDTH HANGUL LETTER SSANGPIEUPHALFWIDTH HANGUL LETTER PIEUP-SIOSHALFWIDT" +
"H HANGUL LETTER SIOSHALFWIDTH HANGUL LETTER SSANGSIOSHALFWIDTH HANGUL LE" +
"TTER IEUNGHALFWIDTH HANGUL LETTER CIEUCHALFWIDTH HANGUL LETTER SSANGCIEU" +
"CHALFWIDTH HANGUL LETTER CHIEUCHHALFWIDTH HANGUL LETTER KHIEUKHHALFWIDTH" +
" HANGUL LETTER THIEUTHHALFWIDTH HANGUL LETTER PHIEUPHHALFWIDTH HANGUL LE" +
"TTER HIEUHHALFWIDTH HANGUL LETTER AHALFWIDTH HANGUL LETTER AEHALFWIDTH H" +
"ANGUL LETTER YAHALFWIDTH HANGUL LETTER YAEHALFWIDTH HANGUL LETTER EOHALF" +
"WIDTH HANGUL LETTER EHALFWIDTH HANGUL LETTER YEOHALFWIDTH HANGUL LETTER " +
"YEHALFWIDTH HANGUL LETTER OHALFWIDTH HANGUL LETTER WAHALFWIDTH HANGUL LE" +
"TTER WAEHALFWIDTH HANGUL LETTER OEHALFWIDTH HANGUL LETTER YOHALFWIDTH HA" +
"NGUL LETTER UHALFWIDTH HANGUL LETTER WEOHALFWIDTH HANGUL LETTER WEHALFWI" +
"DTH HANGUL LETTER WIHALFWIDTH HANGUL LETTER YUHALFWIDTH HANGUL LETTER EU" +
"HALFWIDTH HANGUL LETTER YIHALFWIDTH HANGUL LETTER IFULLWIDTH CENT SIGNFU" +
"LLWIDTH POUND SIGNFULLWIDTH NOT SIGNFULLWIDTH MACRONFULLWIDTH BROKEN BAR" +
"FULLWIDTH YEN SIGNFULLWIDTH WON SIGNHALFWIDTH FORMS LIGHT VERTICALHALFWI" +
"DTH LEFTWARDS ARROWHALFWIDTH UPWARDS ARROWHALFWIDTH RIGHTWARDS ARROWHALF" +
"WIDTH DOWNWARDS ARROWHALFWIDTH BLACK SQUAREHALFWIDTH WHITE CIRCLEINTERLI" +
"NEAR ANNOTATION ANCHORINTERLINEAR ANNOTATION SEPARATORINTERLINEAR ANNOTA" +
"TION TERMINATOROBJECT REPLACEMENT CHARACTERREPLACEMENT CHARACTERLINEAR B" +
" SYLLABLE B008 ALINEAR B SYLLABLE B038 ELINEAR B SYLLABLE B028 ILINEAR B" +
" SYLLABLE B061 OLINEAR B SYLLABLE B010 ULINEAR B SYLLABLE B001 DALINEAR " +
"B SYLLABLE B045 DELINEAR B SYLLABLE B007 DILINEAR B SYLLABLE B014 DOLINE" +
"AR B SYLLABLE B051 DULINEAR B SYLLABLE B057 JALINEAR B SYLLABLE B046 JEL" +
"INEAR B SYLLABLE B036 JOLINEAR B SYLLABLE B065 JULINEAR B SYLLABLE B077 " +
"KALINEAR B SYLLABLE B044 KELINEAR B SYLLABLE B067 KILINEAR B SYLLABLE B0" +
"70 KOLINEAR B SYLLABLE B081 KULINEAR B SYLLABLE B080 MALINEAR B SYLLABLE" +
" B013 MELINEAR B SYLLABLE B073 MILINEAR B SYLLABLE B015 MOLINEAR B SYLLA" +
"BLE B023 MULINEAR B SYLLABLE B006 NALINEAR B SYLLABLE B024 NELINEAR B SY" +
"LLABLE B030 NILINEAR B SYLLABLE B052 NOLINEAR B SYLLABLE B055 NULINEAR B" +
" SYLLABLE B003 PALINEAR B SYLLABLE B072 PELINEAR B SYLLABLE B039 PILINEA" +
"R B SYLLABLE B011 POLINEAR B SYLLABLE B050 PULINEAR B SYLLABLE B016 QALI" +
"NEAR B SYLLABLE B078 QELINEAR B SYLLABLE B021 QILINEAR B SYLLABLE B032 Q" +
"OLINEAR B SYLLABLE B060 RALINEAR B SYLLABLE B027 RELINEAR B SYLLABLE B05" +
"3 RILINEAR B SYLLABLE B002 ROLINEAR B SYLLABLE B026 RULINEAR B SYLLABLE " +
"B031 SALINEAR B SYLLABLE B009 SELINEAR B SYLLABLE B041 SILINEAR B SYLLAB" +
"LE B012 SOLINEAR B SYLLABLE B058 SULINEAR B SYLLABLE B059 TALINEAR B SYL" +
"LABLE B004 TELINEAR B SYLLABLE B037 TILINEAR B SYLLABLE B005 TOLINEAR B " +
"SYLLABLE B069 TULINEAR B SYLLABLE B054 WALINEAR B SYLLABLE B075 WELINEAR" +
" B SYLLABLE B040 WILINEAR B SYLLABLE B042 WOLINEAR B SYLLABLE B017 ZALIN" +
"EAR B SYLLABLE B074 ZELINEAR B SYLLABLE B020 ZOLINEAR B SYLLABLE B025 A2" +
"LINEAR B SYLLABLE B043 A3LINEAR B SYLLABLE B085 AULINEAR B SYLLABLE B071" +
" DWELINEAR B SYLLABLE B090 DWOLINEAR B SYLLABLE B048 NWALINEAR B SYLLABL" +
"E B029 PU2LINEAR B SYLLABLE B062 PTELINEAR B SYLLABLE B076 RA2LINEAR B S" +
"YLLABLE B033 RA3LINEAR B SYLLABLE B068 RO2LINEAR B SYLLABLE B066 TA2LINE" +
"AR B SYLLABLE B087 TWELINEAR B SYLLABLE B091 TWOLINEAR B SYMBOL B018LINE" +
"AR 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 B082LINEAR B SYMBOL B083" +
"LINEAR B SYMBOL B086LINEAR B SYMBOL B089LINEAR B IDEOGRAM B100 MANLINEAR" +
" B IDEOGRAM B102 WOMANLINEAR B IDEOGRAM B104 DEERLINEAR B IDEOGRAM B105 " +
"EQUIDLINEAR B IDEOGRAM B105F MARELINEAR B IDEOGRAM B105M STALLIONLINEAR " +
"B IDEOGRAM B106F EWELINEAR B IDEOGRAM B106M RAMLINEAR B IDEOGRAM B107F S" +
"HE-GOATLINEAR B IDEOGRAM B107M HE-GOATLINEAR B IDEOGRAM B108F SOWLINEAR " +
"B IDEOGRAM B108M BOARLINEAR B IDEOGRAM B109F COWLINEAR B IDEOGRAM B109M " +
"BULLLINEAR B IDEOGRAM B120 WHEATLINEAR B IDEOGRAM B121 BARLEYLINEAR B ID") + ("" +
"EOGRAM B122 OLIVELINEAR B IDEOGRAM B123 SPICELINEAR B IDEOGRAM B125 CYPE" +
"RUSLINEAR B MONOGRAM B127 KAPOLINEAR B MONOGRAM B128 KANAKOLINEAR B IDEO" +
"GRAM B130 OILLINEAR B IDEOGRAM B131 WINELINEAR B IDEOGRAM B132LINEAR B M" +
"ONOGRAM B133 AREPALINEAR B MONOGRAM B135 MERILINEAR B IDEOGRAM B140 BRON" +
"ZELINEAR B IDEOGRAM B141 GOLDLINEAR B IDEOGRAM B142LINEAR B IDEOGRAM B14" +
"5 WOOLLINEAR B IDEOGRAM B146LINEAR B IDEOGRAM B150LINEAR B IDEOGRAM B151" +
" HORNLINEAR B IDEOGRAM B152LINEAR B IDEOGRAM B153LINEAR B IDEOGRAM B154L" +
"INEAR B MONOGRAM B156 TURO2LINEAR B IDEOGRAM B157LINEAR B IDEOGRAM B158L" +
"INEAR B IDEOGRAM B159 CLOTHLINEAR B IDEOGRAM B160LINEAR B IDEOGRAM B161L" +
"INEAR B IDEOGRAM B162 GARMENTLINEAR B IDEOGRAM B163 ARMOURLINEAR B IDEOG" +
"RAM B164LINEAR B IDEOGRAM B165LINEAR B IDEOGRAM B166LINEAR B IDEOGRAM B1" +
"67LINEAR B IDEOGRAM B168LINEAR B IDEOGRAM B169LINEAR B IDEOGRAM B170LINE" +
"AR B IDEOGRAM B171LINEAR B IDEOGRAM B172LINEAR B IDEOGRAM B173 MONTHLINE" +
"AR B IDEOGRAM B174LINEAR B IDEOGRAM B176 TREELINEAR B IDEOGRAM B177LINEA" +
"R B IDEOGRAM B178LINEAR B IDEOGRAM B179LINEAR B IDEOGRAM B180LINEAR B ID" +
"EOGRAM B181LINEAR B IDEOGRAM B182LINEAR B IDEOGRAM B183LINEAR B IDEOGRAM" +
" B184LINEAR B IDEOGRAM B185LINEAR B IDEOGRAM B189LINEAR B IDEOGRAM B190L" +
"INEAR B IDEOGRAM B191 HELMETLINEAR B IDEOGRAM B220 FOOTSTOOLLINEAR B IDE" +
"OGRAM B225 BATHTUBLINEAR B IDEOGRAM B230 SPEARLINEAR B IDEOGRAM B231 ARR" +
"OWLINEAR B IDEOGRAM B232LINEAR B IDEOGRAM B233 SWORDLINEAR B IDEOGRAM B2" +
"34LINEAR B IDEOGRAM B236LINEAR B IDEOGRAM B240 WHEELED CHARIOTLINEAR B I" +
"DEOGRAM B241 CHARIOTLINEAR B IDEOGRAM B242 CHARIOT FRAMELINEAR B IDEOGRA" +
"M B243 WHEELLINEAR B IDEOGRAM B245LINEAR B IDEOGRAM B246LINEAR B MONOGRA" +
"M B247 DIPTELINEAR B IDEOGRAM B248LINEAR B IDEOGRAM B249LINEAR B IDEOGRA" +
"M B251LINEAR B IDEOGRAM B252LINEAR B IDEOGRAM B253LINEAR B IDEOGRAM B254" +
" DARTLINEAR B IDEOGRAM B255LINEAR B IDEOGRAM B256LINEAR B IDEOGRAM B257L" +
"INEAR B IDEOGRAM B258LINEAR B IDEOGRAM B259LINEAR B IDEOGRAM VESSEL B155" +
"LINEAR B IDEOGRAM VESSEL B200LINEAR B IDEOGRAM VESSEL B201LINEAR B IDEOG" +
"RAM VESSEL B202LINEAR B IDEOGRAM VESSEL B203LINEAR B IDEOGRAM VESSEL B20" +
"4LINEAR B IDEOGRAM VESSEL B205LINEAR B IDEOGRAM VESSEL B206LINEAR B IDEO" +
"GRAM VESSEL B207LINEAR B IDEOGRAM VESSEL B208LINEAR B IDEOGRAM VESSEL B2" +
"09LINEAR B IDEOGRAM VESSEL B210LINEAR B IDEOGRAM VESSEL B211LINEAR B IDE" +
"OGRAM VESSEL B212LINEAR B IDEOGRAM VESSEL B213LINEAR B IDEOGRAM VESSEL B" +
"214LINEAR B IDEOGRAM VESSEL B215LINEAR B IDEOGRAM VESSEL B216LINEAR B ID" +
"EOGRAM VESSEL B217LINEAR B IDEOGRAM VESSEL B218LINEAR B IDEOGRAM VESSEL " +
"B219LINEAR B IDEOGRAM VESSEL B221LINEAR B IDEOGRAM VESSEL B222LINEAR B I" +
"DEOGRAM VESSEL B226LINEAR B IDEOGRAM VESSEL B227LINEAR B IDEOGRAM VESSEL" +
" B228LINEAR B IDEOGRAM VESSEL B229LINEAR B IDEOGRAM VESSEL B250LINEAR B " +
"IDEOGRAM VESSEL B305AEGEAN WORD SEPARATOR LINEAEGEAN WORD SEPARATOR DOTA" +
"EGEAN CHECK MARKAEGEAN NUMBER ONEAEGEAN NUMBER TWOAEGEAN NUMBER THREEAEG" +
"EAN NUMBER FOURAEGEAN NUMBER FIVEAEGEAN NUMBER SIXAEGEAN NUMBER SEVENAEG" +
"EAN NUMBER EIGHTAEGEAN NUMBER NINEAEGEAN NUMBER TENAEGEAN NUMBER TWENTYA" +
"EGEAN NUMBER THIRTYAEGEAN NUMBER FORTYAEGEAN NUMBER FIFTYAEGEAN NUMBER S" +
"IXTYAEGEAN NUMBER SEVENTYAEGEAN NUMBER EIGHTYAEGEAN NUMBER NINETYAEGEAN " +
"NUMBER ONE HUNDREDAEGEAN NUMBER TWO HUNDREDAEGEAN NUMBER THREE HUNDREDAE" +
"GEAN NUMBER FOUR HUNDREDAEGEAN NUMBER FIVE HUNDREDAEGEAN NUMBER SIX HUND" +
"REDAEGEAN NUMBER SEVEN HUNDREDAEGEAN NUMBER EIGHT HUNDREDAEGEAN NUMBER N" +
"INE HUNDREDAEGEAN NUMBER ONE THOUSANDAEGEAN NUMBER TWO THOUSANDAEGEAN NU" +
"MBER THREE THOUSANDAEGEAN NUMBER FOUR THOUSANDAEGEAN NUMBER FIVE THOUSAN" +
"DAEGEAN NUMBER SIX THOUSANDAEGEAN NUMBER SEVEN THOUSANDAEGEAN NUMBER EIG" +
"HT THOUSANDAEGEAN NUMBER NINE THOUSANDAEGEAN NUMBER TEN THOUSANDAEGEAN N" +
"UMBER TWENTY THOUSANDAEGEAN NUMBER THIRTY THOUSANDAEGEAN NUMBER FORTY TH" +
"OUSANDAEGEAN NUMBER FIFTY THOUSANDAEGEAN NUMBER SIXTY THOUSANDAEGEAN NUM" +
"BER SEVENTY THOUSANDAEGEAN NUMBER EIGHTY THOUSANDAEGEAN NUMBER NINETY TH" +
"OUSANDAEGEAN WEIGHT BASE UNITAEGEAN WEIGHT FIRST SUBUNITAEGEAN WEIGHT SE" +
"COND SUBUNITAEGEAN WEIGHT THIRD SUBUNITAEGEAN WEIGHT FOURTH SUBUNITAEGEA" +
"N DRY MEASURE FIRST SUBUNITAEGEAN LIQUID MEASURE FIRST SUBUNITAEGEAN MEA" +
"SURE SECOND SUBUNITAEGEAN MEASURE THIRD SUBUNITGREEK ACROPHONIC ATTIC ON" +
"E QUARTERGREEK ACROPHONIC ATTIC ONE HALFGREEK ACROPHONIC ATTIC ONE DRACH" +
"MAGREEK ACROPHONIC ATTIC FIVEGREEK ACROPHONIC ATTIC FIFTYGREEK ACROPHONI" +
"C ATTIC FIVE HUNDREDGREEK ACROPHONIC ATTIC FIVE THOUSANDGREEK ACROPHONIC" +
" ATTIC FIFTY THOUSANDGREEK ACROPHONIC ATTIC FIVE TALENTSGREEK ACROPHONIC" +
" ATTIC TEN TALENTSGREEK ACROPHONIC ATTIC FIFTY TALENTSGREEK ACROPHONIC A" +
"TTIC ONE HUNDRED TALENTSGREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTSGREEK") + ("" +
" ACROPHONIC ATTIC ONE THOUSAND TALENTSGREEK ACROPHONIC ATTIC FIVE THOUSA" +
"ND TALENTSGREEK ACROPHONIC ATTIC FIVE STATERSGREEK ACROPHONIC ATTIC TEN " +
"STATERSGREEK ACROPHONIC ATTIC FIFTY STATERSGREEK ACROPHONIC ATTIC ONE HU" +
"NDRED STATERSGREEK ACROPHONIC ATTIC FIVE HUNDRED STATERSGREEK ACROPHONIC" +
" ATTIC ONE THOUSAND STATERSGREEK ACROPHONIC ATTIC TEN THOUSAND STATERSGR" +
"EEK ACROPHONIC ATTIC FIFTY THOUSAND STATERSGREEK ACROPHONIC ATTIC TEN MN" +
"ASGREEK ACROPHONIC HERAEUM ONE PLETHRONGREEK ACROPHONIC THESPIAN ONEGREE" +
"K ACROPHONIC HERMIONIAN ONEGREEK ACROPHONIC EPIDAUREAN TWOGREEK ACROPHON" +
"IC THESPIAN TWOGREEK ACROPHONIC CYRENAIC TWO DRACHMASGREEK ACROPHONIC EP" +
"IDAUREAN TWO DRACHMASGREEK ACROPHONIC TROEZENIAN FIVEGREEK ACROPHONIC TR" +
"OEZENIAN TENGREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORMGREEK ACROPHON" +
"IC HERMIONIAN TENGREEK ACROPHONIC MESSENIAN TENGREEK ACROPHONIC THESPIAN" +
" TENGREEK ACROPHONIC THESPIAN THIRTYGREEK ACROPHONIC TROEZENIAN FIFTYGRE" +
"EK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORMGREEK ACROPHONIC HERMIONIAN" +
" FIFTYGREEK ACROPHONIC THESPIAN FIFTYGREEK ACROPHONIC THESPIAN ONE HUNDR" +
"EDGREEK ACROPHONIC THESPIAN THREE HUNDREDGREEK ACROPHONIC EPIDAUREAN FIV" +
"E HUNDREDGREEK ACROPHONIC TROEZENIAN FIVE HUNDREDGREEK ACROPHONIC THESPI" +
"AN FIVE HUNDREDGREEK ACROPHONIC CARYSTIAN FIVE HUNDREDGREEK ACROPHONIC N" +
"AXIAN FIVE HUNDREDGREEK ACROPHONIC THESPIAN ONE THOUSANDGREEK ACROPHONIC" +
" THESPIAN FIVE THOUSANDGREEK ACROPHONIC DELPHIC FIVE MNASGREEK ACROPHONI" +
"C STRATIAN FIFTY MNASGREEK ONE HALF SIGNGREEK ONE HALF SIGN ALTERNATE FO" +
"RMGREEK TWO THIRDS SIGNGREEK THREE QUARTERS SIGNGREEK YEAR SIGNGREEK TAL" +
"ENT SIGNGREEK DRACHMA SIGNGREEK OBOL SIGNGREEK TWO OBOLS SIGNGREEK THREE" +
" OBOLS SIGNGREEK FOUR OBOLS SIGNGREEK FIVE OBOLS SIGNGREEK METRETES SIGN" +
"GREEK KYATHOS BASE SIGNGREEK LITRA SIGNGREEK OUNKIA SIGNGREEK XESTES SIG" +
"NGREEK ARTABE SIGNGREEK AROURA SIGNGREEK GRAMMA SIGNGREEK TRYBLION BASE " +
"SIGNGREEK ZERO SIGNGREEK ONE QUARTER SIGNGREEK SINUSOID SIGNGREEK INDICT" +
"ION SIGNNOMISMA SIGNROMAN SEXTANS SIGNROMAN UNCIA SIGNROMAN SEMUNCIA SIG" +
"NROMAN SEXTULA SIGNROMAN DIMIDIA SEXTULA SIGNROMAN SILIQUA SIGNROMAN DEN" +
"ARIUS SIGNROMAN QUINARIUS SIGNROMAN SESTERTIUS SIGNROMAN DUPONDIUS SIGNR" +
"OMAN AS SIGNROMAN CENTURIAL SIGNASCIA SYMBOLGREEK SYMBOL TAU RHOPHAISTOS" +
" DISC SIGN PEDESTRIANPHAISTOS DISC SIGN PLUMED HEADPHAISTOS DISC SIGN TA" +
"TTOOED HEADPHAISTOS DISC SIGN CAPTIVEPHAISTOS DISC SIGN CHILDPHAISTOS DI" +
"SC SIGN WOMANPHAISTOS DISC SIGN HELMETPHAISTOS DISC SIGN GAUNTLETPHAISTO" +
"S DISC SIGN TIARAPHAISTOS DISC SIGN ARROWPHAISTOS DISC SIGN BOWPHAISTOS " +
"DISC SIGN SHIELDPHAISTOS DISC SIGN CLUBPHAISTOS DISC SIGN MANACLESPHAIST" +
"OS DISC SIGN MATTOCKPHAISTOS DISC SIGN SAWPHAISTOS DISC SIGN LIDPHAISTOS" +
" DISC SIGN BOOMERANGPHAISTOS DISC SIGN CARPENTRY PLANEPHAISTOS DISC SIGN" +
" DOLIUMPHAISTOS DISC SIGN COMBPHAISTOS DISC SIGN SLINGPHAISTOS DISC SIGN" +
" COLUMNPHAISTOS DISC SIGN BEEHIVEPHAISTOS DISC SIGN SHIPPHAISTOS DISC SI" +
"GN HORNPHAISTOS DISC SIGN HIDEPHAISTOS DISC SIGN BULLS LEGPHAISTOS DISC " +
"SIGN CATPHAISTOS DISC SIGN RAMPHAISTOS DISC SIGN EAGLEPHAISTOS DISC SIGN" +
" DOVEPHAISTOS DISC SIGN TUNNYPHAISTOS DISC SIGN BEEPHAISTOS DISC SIGN PL" +
"ANE TREEPHAISTOS DISC SIGN VINEPHAISTOS DISC SIGN PAPYRUSPHAISTOS DISC S" +
"IGN ROSETTEPHAISTOS DISC SIGN LILYPHAISTOS DISC SIGN OX BACKPHAISTOS DIS" +
"C SIGN FLUTEPHAISTOS DISC SIGN GRATERPHAISTOS DISC SIGN STRAINERPHAISTOS" +
" DISC SIGN SMALL AXEPHAISTOS DISC SIGN WAVY BANDPHAISTOS DISC SIGN COMBI" +
"NING OBLIQUE STROKELYCIAN LETTER ALYCIAN LETTER ELYCIAN LETTER BLYCIAN L" +
"ETTER BHLYCIAN LETTER GLYCIAN LETTER DLYCIAN LETTER ILYCIAN LETTER WLYCI" +
"AN LETTER ZLYCIAN LETTER THLYCIAN LETTER JLYCIAN LETTER KLYCIAN LETTER Q" +
"LYCIAN LETTER LLYCIAN LETTER MLYCIAN LETTER NLYCIAN LETTER MMLYCIAN LETT" +
"ER NNLYCIAN LETTER ULYCIAN LETTER PLYCIAN LETTER KKLYCIAN LETTER RLYCIAN" +
" LETTER SLYCIAN LETTER TLYCIAN LETTER TTLYCIAN LETTER ANLYCIAN LETTER EN" +
"LYCIAN LETTER HLYCIAN LETTER XCARIAN LETTER ACARIAN LETTER P2CARIAN LETT" +
"ER DCARIAN LETTER LCARIAN LETTER UUUCARIAN LETTER RCARIAN LETTER LDCARIA" +
"N LETTER A2CARIAN LETTER QCARIAN LETTER BCARIAN LETTER MCARIAN LETTER OC" +
"ARIAN LETTER D2CARIAN LETTER TCARIAN LETTER SHCARIAN LETTER SH2CARIAN LE" +
"TTER SCARIAN LETTER C-18CARIAN LETTER UCARIAN LETTER NNCARIAN LETTER XCA" +
"RIAN LETTER NCARIAN LETTER TT2CARIAN LETTER PCARIAN LETTER SSCARIAN LETT" +
"ER ICARIAN LETTER ECARIAN LETTER UUUUCARIAN LETTER KCARIAN LETTER K2CARI" +
"AN LETTER NDCARIAN LETTER UUCARIAN LETTER GCARIAN LETTER G2CARIAN LETTER" +
" STCARIAN LETTER ST2CARIAN LETTER NGCARIAN LETTER IICARIAN LETTER C-39CA" +
"RIAN LETTER TTCARIAN LETTER UUU2CARIAN LETTER RRCARIAN LETTER MBCARIAN L" +
"ETTER MB2CARIAN LETTER MB3CARIAN LETTER MB4CARIAN LETTER LD2CARIAN LETTE") + ("" +
"R E2CARIAN LETTER UUU3COPTIC EPACT THOUSANDS MARKCOPTIC EPACT DIGIT ONEC" +
"OPTIC EPACT DIGIT TWOCOPTIC EPACT DIGIT THREECOPTIC EPACT DIGIT FOURCOPT" +
"IC EPACT DIGIT FIVECOPTIC EPACT DIGIT SIXCOPTIC EPACT DIGIT SEVENCOPTIC " +
"EPACT DIGIT EIGHTCOPTIC EPACT DIGIT NINECOPTIC EPACT NUMBER TENCOPTIC EP" +
"ACT NUMBER TWENTYCOPTIC EPACT NUMBER THIRTYCOPTIC EPACT NUMBER FORTYCOPT" +
"IC EPACT NUMBER FIFTYCOPTIC EPACT NUMBER SIXTYCOPTIC EPACT NUMBER SEVENT" +
"YCOPTIC EPACT NUMBER EIGHTYCOPTIC EPACT NUMBER NINETYCOPTIC EPACT NUMBER" +
" ONE HUNDREDCOPTIC EPACT NUMBER TWO HUNDREDCOPTIC EPACT NUMBER THREE HUN" +
"DREDCOPTIC EPACT NUMBER FOUR HUNDREDCOPTIC EPACT NUMBER FIVE HUNDREDCOPT" +
"IC EPACT NUMBER SIX HUNDREDCOPTIC EPACT NUMBER SEVEN HUNDREDCOPTIC EPACT" +
" NUMBER EIGHT HUNDREDCOPTIC EPACT NUMBER NINE HUNDREDOLD ITALIC LETTER A" +
"OLD ITALIC LETTER BEOLD ITALIC LETTER KEOLD ITALIC LETTER DEOLD ITALIC L" +
"ETTER EOLD ITALIC LETTER VEOLD ITALIC LETTER ZEOLD ITALIC LETTER HEOLD I" +
"TALIC LETTER THEOLD ITALIC LETTER IOLD ITALIC LETTER KAOLD ITALIC LETTER" +
" ELOLD ITALIC LETTER EMOLD ITALIC LETTER ENOLD ITALIC LETTER ESHOLD ITAL" +
"IC LETTER OOLD ITALIC LETTER PEOLD ITALIC LETTER SHEOLD ITALIC LETTER KU" +
"OLD ITALIC LETTER EROLD ITALIC LETTER ESOLD ITALIC LETTER TEOLD ITALIC L" +
"ETTER UOLD ITALIC LETTER EKSOLD ITALIC LETTER PHEOLD ITALIC LETTER KHEOL" +
"D ITALIC LETTER EFOLD ITALIC LETTER ERSOLD ITALIC LETTER CHEOLD ITALIC L" +
"ETTER IIOLD ITALIC LETTER UUOLD ITALIC LETTER ESSOLD ITALIC NUMERAL ONEO" +
"LD ITALIC NUMERAL FIVEOLD ITALIC NUMERAL TENOLD ITALIC NUMERAL FIFTYOLD " +
"ITALIC LETTER YEOLD ITALIC LETTER NORTHERN TSEOLD ITALIC LETTER SOUTHERN" +
" TSEGOTHIC LETTER AHSAGOTHIC LETTER BAIRKANGOTHIC LETTER GIBAGOTHIC LETT" +
"ER DAGSGOTHIC LETTER AIHVUSGOTHIC LETTER QAIRTHRAGOTHIC LETTER IUJAGOTHI" +
"C LETTER HAGLGOTHIC LETTER THIUTHGOTHIC LETTER EISGOTHIC LETTER KUSMAGOT" +
"HIC LETTER LAGUSGOTHIC LETTER MANNAGOTHIC LETTER NAUTHSGOTHIC LETTER JER" +
"GOTHIC LETTER URUSGOTHIC LETTER PAIRTHRAGOTHIC LETTER NINETYGOTHIC LETTE" +
"R RAIDAGOTHIC LETTER SAUILGOTHIC LETTER TEIWSGOTHIC LETTER WINJAGOTHIC L" +
"ETTER FAIHUGOTHIC LETTER IGGWSGOTHIC LETTER HWAIRGOTHIC LETTER OTHALGOTH" +
"IC LETTER NINE HUNDREDOLD PERMIC LETTER ANOLD PERMIC LETTER BUROLD PERMI" +
"C LETTER GAIOLD PERMIC LETTER DOIOLD PERMIC LETTER EOLD PERMIC LETTER ZH" +
"OIOLD PERMIC LETTER DZHOIOLD PERMIC LETTER ZATAOLD PERMIC LETTER DZITAOL" +
"D PERMIC LETTER IOLD PERMIC LETTER KOKEOLD PERMIC LETTER LEIOLD PERMIC L" +
"ETTER MENOEOLD PERMIC LETTER NENOEOLD PERMIC LETTER VOOIOLD PERMIC LETTE" +
"R PEEIOLD PERMIC LETTER REIOLD PERMIC LETTER SIIOLD PERMIC LETTER TAIOLD" +
" PERMIC LETTER UOLD PERMIC LETTER CHERYOLD PERMIC LETTER SHOOIOLD PERMIC" +
" LETTER SHCHOOIOLD PERMIC LETTER YRYOLD PERMIC LETTER YERUOLD PERMIC LET" +
"TER OOLD PERMIC LETTER OOOLD PERMIC LETTER EFOLD PERMIC LETTER HAOLD PER" +
"MIC LETTER TSIUOLD PERMIC LETTER VEROLD PERMIC LETTER YEROLD PERMIC LETT" +
"ER YERIOLD PERMIC LETTER YATOLD PERMIC LETTER IEOLD PERMIC LETTER YUOLD " +
"PERMIC LETTER YAOLD PERMIC LETTER IACOMBINING OLD PERMIC LETTER ANCOMBIN" +
"ING OLD PERMIC LETTER DOICOMBINING OLD PERMIC LETTER ZATACOMBINING OLD P" +
"ERMIC LETTER NENOECOMBINING OLD PERMIC LETTER SIIUGARITIC LETTER ALPAUGA" +
"RITIC LETTER BETAUGARITIC LETTER GAMLAUGARITIC LETTER KHAUGARITIC LETTER" +
" DELTAUGARITIC LETTER HOUGARITIC LETTER WOUGARITIC LETTER ZETAUGARITIC L" +
"ETTER HOTAUGARITIC LETTER TETUGARITIC LETTER YODUGARITIC LETTER KAFUGARI" +
"TIC LETTER SHINUGARITIC LETTER LAMDAUGARITIC LETTER MEMUGARITIC LETTER D" +
"HALUGARITIC LETTER NUNUGARITIC LETTER ZUUGARITIC LETTER SAMKAUGARITIC LE" +
"TTER AINUGARITIC LETTER PUUGARITIC LETTER SADEUGARITIC LETTER QOPAUGARIT" +
"IC LETTER RASHAUGARITIC LETTER THANNAUGARITIC LETTER GHAINUGARITIC LETTE" +
"R TOUGARITIC LETTER IUGARITIC LETTER UUGARITIC LETTER SSUUGARITIC WORD D" +
"IVIDEROLD PERSIAN SIGN AOLD PERSIAN SIGN IOLD PERSIAN SIGN UOLD PERSIAN " +
"SIGN KAOLD PERSIAN SIGN KUOLD PERSIAN SIGN GAOLD PERSIAN SIGN GUOLD PERS" +
"IAN SIGN XAOLD PERSIAN SIGN CAOLD PERSIAN SIGN JAOLD PERSIAN SIGN JIOLD " +
"PERSIAN SIGN TAOLD PERSIAN SIGN TUOLD PERSIAN SIGN DAOLD PERSIAN SIGN DI" +
"OLD PERSIAN SIGN DUOLD PERSIAN SIGN THAOLD PERSIAN SIGN PAOLD PERSIAN SI" +
"GN BAOLD PERSIAN SIGN FAOLD PERSIAN SIGN NAOLD PERSIAN SIGN NUOLD PERSIA" +
"N SIGN MAOLD PERSIAN SIGN MIOLD PERSIAN SIGN MUOLD PERSIAN SIGN YAOLD PE" +
"RSIAN SIGN VAOLD PERSIAN SIGN VIOLD PERSIAN SIGN RAOLD PERSIAN SIGN RUOL" +
"D PERSIAN SIGN LAOLD PERSIAN SIGN SAOLD PERSIAN SIGN ZAOLD PERSIAN SIGN " +
"SHAOLD PERSIAN SIGN SSAOLD PERSIAN SIGN HAOLD PERSIAN SIGN AURAMAZDAAOLD" +
" PERSIAN SIGN AURAMAZDAA-2OLD PERSIAN SIGN AURAMAZDAAHAOLD PERSIAN SIGN " +
"XSHAAYATHIYAOLD PERSIAN SIGN DAHYAAUSHOLD PERSIAN SIGN DAHYAAUSH-2OLD PE" +
"RSIAN SIGN BAGAOLD PERSIAN SIGN BUUMISHOLD PERSIAN WORD DIVIDEROLD PERSI") + ("" +
"AN NUMBER ONEOLD PERSIAN NUMBER TWOOLD PERSIAN NUMBER TENOLD PERSIAN NUM" +
"BER TWENTYOLD PERSIAN NUMBER HUNDREDDESERET CAPITAL LETTER LONG IDESERET" +
" CAPITAL LETTER LONG EDESERET CAPITAL LETTER LONG ADESERET CAPITAL LETTE" +
"R LONG AHDESERET CAPITAL LETTER LONG ODESERET CAPITAL LETTER LONG OODESE" +
"RET CAPITAL LETTER SHORT IDESERET CAPITAL LETTER SHORT EDESERET CAPITAL " +
"LETTER SHORT ADESERET CAPITAL LETTER SHORT AHDESERET CAPITAL LETTER SHOR" +
"T ODESERET CAPITAL LETTER SHORT OODESERET CAPITAL LETTER AYDESERET CAPIT" +
"AL LETTER OWDESERET CAPITAL LETTER WUDESERET CAPITAL LETTER YEEDESERET C" +
"APITAL LETTER HDESERET CAPITAL LETTER PEEDESERET CAPITAL LETTER BEEDESER" +
"ET CAPITAL LETTER TEEDESERET CAPITAL LETTER DEEDESERET CAPITAL LETTER CH" +
"EEDESERET CAPITAL LETTER JEEDESERET CAPITAL LETTER KAYDESERET CAPITAL LE" +
"TTER GAYDESERET CAPITAL LETTER EFDESERET CAPITAL LETTER VEEDESERET CAPIT" +
"AL LETTER ETHDESERET CAPITAL LETTER THEEDESERET CAPITAL LETTER ESDESERET" +
" CAPITAL LETTER ZEEDESERET CAPITAL LETTER ESHDESERET CAPITAL LETTER ZHEE" +
"DESERET CAPITAL LETTER ERDESERET CAPITAL LETTER ELDESERET CAPITAL LETTER" +
" EMDESERET CAPITAL LETTER ENDESERET CAPITAL LETTER ENGDESERET CAPITAL LE" +
"TTER OIDESERET CAPITAL LETTER EWDESERET SMALL LETTER LONG IDESERET SMALL" +
" LETTER LONG EDESERET SMALL LETTER LONG ADESERET SMALL LETTER LONG AHDES" +
"ERET SMALL LETTER LONG ODESERET SMALL LETTER LONG OODESERET SMALL LETTER" +
" SHORT IDESERET SMALL LETTER SHORT EDESERET SMALL LETTER SHORT ADESERET " +
"SMALL LETTER SHORT AHDESERET SMALL LETTER SHORT ODESERET SMALL LETTER SH" +
"ORT OODESERET SMALL LETTER AYDESERET SMALL LETTER OWDESERET SMALL LETTER" +
" WUDESERET SMALL LETTER YEEDESERET SMALL LETTER HDESERET SMALL LETTER PE" +
"EDESERET SMALL LETTER BEEDESERET SMALL LETTER TEEDESERET SMALL LETTER DE" +
"EDESERET SMALL LETTER CHEEDESERET SMALL LETTER JEEDESERET SMALL LETTER K" +
"AYDESERET SMALL LETTER GAYDESERET SMALL LETTER EFDESERET SMALL LETTER VE" +
"EDESERET SMALL LETTER ETHDESERET SMALL LETTER THEEDESERET SMALL LETTER E" +
"SDESERET SMALL LETTER ZEEDESERET SMALL LETTER ESHDESERET SMALL LETTER ZH" +
"EEDESERET SMALL LETTER ERDESERET SMALL LETTER ELDESERET SMALL LETTER EMD" +
"ESERET SMALL LETTER ENDESERET SMALL LETTER ENGDESERET SMALL LETTER OIDES" +
"ERET SMALL LETTER EWSHAVIAN LETTER PEEPSHAVIAN LETTER TOTSHAVIAN LETTER " +
"KICKSHAVIAN LETTER FEESHAVIAN LETTER THIGHSHAVIAN LETTER SOSHAVIAN LETTE" +
"R SURESHAVIAN LETTER CHURCHSHAVIAN LETTER YEASHAVIAN LETTER HUNGSHAVIAN " +
"LETTER BIBSHAVIAN LETTER DEADSHAVIAN LETTER GAGSHAVIAN LETTER VOWSHAVIAN" +
" LETTER THEYSHAVIAN LETTER ZOOSHAVIAN LETTER MEASURESHAVIAN LETTER JUDGE" +
"SHAVIAN LETTER WOESHAVIAN LETTER HA-HASHAVIAN LETTER LOLLSHAVIAN LETTER " +
"MIMESHAVIAN LETTER IFSHAVIAN LETTER EGGSHAVIAN LETTER ASHSHAVIAN LETTER " +
"ADOSHAVIAN LETTER ONSHAVIAN LETTER WOOLSHAVIAN LETTER OUTSHAVIAN LETTER " +
"AHSHAVIAN LETTER ROARSHAVIAN LETTER NUNSHAVIAN LETTER EATSHAVIAN LETTER " +
"AGESHAVIAN LETTER ICESHAVIAN LETTER UPSHAVIAN LETTER OAKSHAVIAN LETTER O" +
"OZESHAVIAN LETTER OILSHAVIAN LETTER AWESHAVIAN LETTER ARESHAVIAN LETTER " +
"ORSHAVIAN LETTER AIRSHAVIAN LETTER ERRSHAVIAN LETTER ARRAYSHAVIAN LETTER" +
" EARSHAVIAN LETTER IANSHAVIAN LETTER YEWOSMANYA LETTER ALEFOSMANYA LETTE" +
"R BAOSMANYA LETTER TAOSMANYA LETTER JAOSMANYA LETTER XAOSMANYA LETTER KH" +
"AOSMANYA LETTER DEELOSMANYA LETTER RAOSMANYA LETTER SAOSMANYA LETTER SHI" +
"INOSMANYA LETTER DHAOSMANYA LETTER CAYNOSMANYA LETTER GAOSMANYA LETTER F" +
"AOSMANYA LETTER QAAFOSMANYA LETTER KAAFOSMANYA LETTER LAANOSMANYA LETTER" +
" MIINOSMANYA LETTER NUUNOSMANYA LETTER WAWOSMANYA LETTER HAOSMANYA LETTE" +
"R YAOSMANYA LETTER AOSMANYA LETTER EOSMANYA LETTER IOSMANYA LETTER OOSMA" +
"NYA LETTER UOSMANYA LETTER AAOSMANYA LETTER EEOSMANYA LETTER OOOSMANYA D" +
"IGIT ZEROOSMANYA DIGIT ONEOSMANYA DIGIT TWOOSMANYA DIGIT THREEOSMANYA DI" +
"GIT FOUROSMANYA DIGIT FIVEOSMANYA DIGIT SIXOSMANYA DIGIT SEVENOSMANYA DI" +
"GIT EIGHTOSMANYA DIGIT NINEOSAGE CAPITAL LETTER AOSAGE CAPITAL LETTER AI" +
"OSAGE CAPITAL LETTER AINOSAGE CAPITAL LETTER AHOSAGE CAPITAL LETTER BRAO" +
"SAGE CAPITAL LETTER CHAOSAGE CAPITAL LETTER EHCHAOSAGE CAPITAL LETTER EO" +
"SAGE CAPITAL LETTER EINOSAGE CAPITAL LETTER HAOSAGE CAPITAL LETTER HYAOS" +
"AGE CAPITAL LETTER IOSAGE CAPITAL LETTER KAOSAGE CAPITAL LETTER EHKAOSAG" +
"E CAPITAL LETTER KYAOSAGE CAPITAL LETTER LAOSAGE CAPITAL LETTER MAOSAGE " +
"CAPITAL LETTER NAOSAGE CAPITAL LETTER OOSAGE CAPITAL LETTER OINOSAGE CAP" +
"ITAL LETTER PAOSAGE CAPITAL LETTER EHPAOSAGE CAPITAL LETTER SAOSAGE CAPI" +
"TAL LETTER SHAOSAGE CAPITAL LETTER TAOSAGE CAPITAL LETTER EHTAOSAGE CAPI" +
"TAL LETTER TSAOSAGE CAPITAL LETTER EHTSAOSAGE CAPITAL LETTER TSHAOSAGE C" +
"APITAL LETTER DHAOSAGE CAPITAL LETTER UOSAGE CAPITAL LETTER WAOSAGE CAPI" +
"TAL LETTER KHAOSAGE CAPITAL LETTER GHAOSAGE CAPITAL LETTER ZAOSAGE CAPIT") + ("" +
"AL LETTER ZHAOSAGE SMALL LETTER AOSAGE SMALL LETTER AIOSAGE SMALL LETTER" +
" AINOSAGE SMALL LETTER AHOSAGE SMALL LETTER BRAOSAGE SMALL LETTER CHAOSA" +
"GE SMALL LETTER EHCHAOSAGE SMALL LETTER EOSAGE SMALL LETTER EINOSAGE SMA" +
"LL LETTER HAOSAGE SMALL LETTER HYAOSAGE SMALL LETTER IOSAGE SMALL LETTER" +
" KAOSAGE SMALL LETTER EHKAOSAGE SMALL LETTER KYAOSAGE SMALL LETTER LAOSA" +
"GE SMALL LETTER MAOSAGE SMALL LETTER NAOSAGE SMALL LETTER OOSAGE SMALL L" +
"ETTER OINOSAGE SMALL LETTER PAOSAGE SMALL LETTER EHPAOSAGE SMALL LETTER " +
"SAOSAGE SMALL LETTER SHAOSAGE SMALL LETTER TAOSAGE SMALL LETTER EHTAOSAG" +
"E SMALL LETTER TSAOSAGE SMALL LETTER EHTSAOSAGE SMALL LETTER TSHAOSAGE S" +
"MALL LETTER DHAOSAGE SMALL LETTER UOSAGE SMALL LETTER WAOSAGE SMALL LETT" +
"ER KHAOSAGE SMALL LETTER GHAOSAGE SMALL LETTER ZAOSAGE SMALL LETTER ZHAE" +
"LBASAN LETTER AELBASAN LETTER BEELBASAN LETTER CEELBASAN LETTER CHEELBAS" +
"AN LETTER DEELBASAN LETTER NDEELBASAN LETTER DHEELBASAN LETTER EIELBASAN" +
" LETTER EELBASAN LETTER FEELBASAN LETTER GEELBASAN LETTER GJEELBASAN LET" +
"TER HEELBASAN LETTER IELBASAN LETTER JEELBASAN LETTER KEELBASAN LETTER L" +
"EELBASAN LETTER LLEELBASAN LETTER MEELBASAN LETTER NEELBASAN LETTER NAEL" +
"BASAN LETTER NJEELBASAN LETTER OELBASAN LETTER PEELBASAN LETTER QEELBASA" +
"N LETTER REELBASAN LETTER RREELBASAN LETTER SEELBASAN LETTER SHEELBASAN " +
"LETTER TEELBASAN LETTER THEELBASAN LETTER UELBASAN LETTER VEELBASAN LETT" +
"ER XEELBASAN LETTER YELBASAN LETTER ZEELBASAN LETTER ZHEELBASAN LETTER G" +
"HEELBASAN LETTER GHAMMAELBASAN LETTER KHECAUCASIAN ALBANIAN LETTER ALTCA" +
"UCASIAN ALBANIAN LETTER BETCAUCASIAN ALBANIAN LETTER GIMCAUCASIAN ALBANI" +
"AN LETTER DATCAUCASIAN ALBANIAN LETTER EBCAUCASIAN ALBANIAN LETTER ZARLC" +
"AUCASIAN ALBANIAN LETTER EYNCAUCASIAN ALBANIAN LETTER ZHILCAUCASIAN ALBA" +
"NIAN LETTER TASCAUCASIAN ALBANIAN LETTER CHACAUCASIAN ALBANIAN LETTER YO" +
"WDCAUCASIAN ALBANIAN LETTER ZHACAUCASIAN ALBANIAN LETTER IRBCAUCASIAN AL" +
"BANIAN LETTER SHACAUCASIAN ALBANIAN LETTER LANCAUCASIAN ALBANIAN LETTER " +
"INYACAUCASIAN ALBANIAN LETTER XEYNCAUCASIAN ALBANIAN LETTER DYANCAUCASIA" +
"N ALBANIAN LETTER CARCAUCASIAN ALBANIAN LETTER JHOXCAUCASIAN ALBANIAN LE" +
"TTER KARCAUCASIAN ALBANIAN LETTER LYITCAUCASIAN ALBANIAN LETTER HEYTCAUC" +
"ASIAN ALBANIAN LETTER QAYCAUCASIAN ALBANIAN LETTER AORCAUCASIAN ALBANIAN" +
" LETTER CHOYCAUCASIAN ALBANIAN LETTER CHICAUCASIAN ALBANIAN LETTER CYAYC" +
"AUCASIAN ALBANIAN LETTER MAQCAUCASIAN ALBANIAN LETTER QARCAUCASIAN ALBAN" +
"IAN LETTER NOWCCAUCASIAN ALBANIAN LETTER DZYAYCAUCASIAN ALBANIAN LETTER " +
"SHAKCAUCASIAN ALBANIAN LETTER JAYNCAUCASIAN ALBANIAN LETTER ONCAUCASIAN " +
"ALBANIAN LETTER TYAYCAUCASIAN ALBANIAN LETTER FAMCAUCASIAN ALBANIAN LETT" +
"ER DZAYCAUCASIAN ALBANIAN LETTER CHATCAUCASIAN ALBANIAN LETTER PENCAUCAS" +
"IAN ALBANIAN LETTER GHEYSCAUCASIAN ALBANIAN LETTER RATCAUCASIAN ALBANIAN" +
" LETTER SEYKCAUCASIAN ALBANIAN LETTER VEYZCAUCASIAN ALBANIAN LETTER TIWR" +
"CAUCASIAN ALBANIAN LETTER SHOYCAUCASIAN ALBANIAN LETTER IWNCAUCASIAN ALB" +
"ANIAN LETTER CYAWCAUCASIAN ALBANIAN LETTER CAYNCAUCASIAN ALBANIAN LETTER" +
" YAYDCAUCASIAN ALBANIAN LETTER PIWRCAUCASIAN ALBANIAN LETTER KIWCAUCASIA" +
"N ALBANIAN CITATION MARKVITHKUQI CAPITAL LETTER AVITHKUQI CAPITAL LETTER" +
" BBEVITHKUQI CAPITAL LETTER BEVITHKUQI CAPITAL LETTER CEVITHKUQI CAPITAL" +
" LETTER CHEVITHKUQI CAPITAL LETTER DEVITHKUQI CAPITAL LETTER DHEVITHKUQI" +
" CAPITAL LETTER EIVITHKUQI CAPITAL LETTER EVITHKUQI CAPITAL LETTER FEVIT" +
"HKUQI CAPITAL LETTER GAVITHKUQI CAPITAL LETTER HAVITHKUQI CAPITAL LETTER" +
" HHAVITHKUQI CAPITAL LETTER IVITHKUQI CAPITAL LETTER IJEVITHKUQI CAPITAL" +
" LETTER JEVITHKUQI CAPITAL LETTER KAVITHKUQI CAPITAL LETTER LAVITHKUQI C" +
"APITAL LETTER LLAVITHKUQI CAPITAL LETTER MEVITHKUQI CAPITAL LETTER NEVIT" +
"HKUQI CAPITAL LETTER NJEVITHKUQI CAPITAL LETTER OVITHKUQI CAPITAL LETTER" +
" PEVITHKUQI CAPITAL LETTER QAVITHKUQI CAPITAL LETTER REVITHKUQI CAPITAL " +
"LETTER SEVITHKUQI CAPITAL LETTER SHEVITHKUQI CAPITAL LETTER TEVITHKUQI C" +
"APITAL LETTER THEVITHKUQI CAPITAL LETTER UVITHKUQI CAPITAL LETTER VEVITH" +
"KUQI CAPITAL LETTER XEVITHKUQI CAPITAL LETTER YVITHKUQI CAPITAL LETTER Z" +
"EVITHKUQI SMALL LETTER AVITHKUQI SMALL LETTER BBEVITHKUQI SMALL LETTER B" +
"EVITHKUQI SMALL LETTER CEVITHKUQI SMALL LETTER CHEVITHKUQI SMALL LETTER " +
"DEVITHKUQI SMALL LETTER DHEVITHKUQI SMALL LETTER EIVITHKUQI SMALL LETTER" +
" EVITHKUQI SMALL LETTER FEVITHKUQI SMALL LETTER GAVITHKUQI SMALL LETTER " +
"HAVITHKUQI SMALL LETTER HHAVITHKUQI SMALL LETTER IVITHKUQI SMALL LETTER " +
"IJEVITHKUQI SMALL LETTER JEVITHKUQI SMALL LETTER KAVITHKUQI SMALL LETTER" +
" LAVITHKUQI SMALL LETTER LLAVITHKUQI SMALL LETTER MEVITHKUQI SMALL LETTE" +
"R NEVITHKUQI SMALL LETTER NJEVITHKUQI SMALL LETTER OVITHKUQI SMALL LETTE" +
"R PEVITHKUQI SMALL LETTER QAVITHKUQI SMALL LETTER REVITHKUQI SMALL LETTE") + ("" +
"R SEVITHKUQI SMALL LETTER SHEVITHKUQI SMALL LETTER TEVITHKUQI SMALL LETT" +
"ER THEVITHKUQI SMALL LETTER UVITHKUQI SMALL LETTER VEVITHKUQI SMALL LETT" +
"ER XEVITHKUQI SMALL LETTER YVITHKUQI SMALL LETTER ZETODHRI LETTER ATODHR" +
"I LETTER ASTODHRI LETTER BATODHRI LETTER MBATODHRI LETTER CATODHRI LETTE" +
"R CHATODHRI LETTER DATODHRI LETTER NDATODHRI LETTER DHATODHRI LETTER EIT" +
"ODHRI LETTER ETODHRI LETTER FATODHRI LETTER GATODHRI LETTER NGATODHRI LE" +
"TTER GJATODHRI LETTER NGJATODHRI LETTER HATODHRI LETTER HJATODHRI LETTER" +
" ITODHRI LETTER JATODHRI LETTER KATODHRI LETTER LATODHRI LETTER LLATODHR" +
"I LETTER MATODHRI LETTER NATODHRI LETTER NJANTODHRI LETTER OTODHRI LETTE" +
"R PATODHRI LETTER QATODHRI LETTER RATODHRI LETTER RRATODHRI LETTER SATOD" +
"HRI LETTER SHATODHRI LETTER SHTATODHRI LETTER TATODHRI LETTER THATODHRI " +
"LETTER UTODHRI LETTER VATODHRI LETTER XATODHRI LETTER NXATODHRI LETTER X" +
"HATODHRI LETTER NXHATODHRI LETTER YTODHRI LETTER JYTODHRI LETTER ZATODHR" +
"I LETTER ZHATODHRI LETTER GHATODHRI LETTER STATODHRI LETTER SKANTODHRI L" +
"ETTER KHATODHRI LETTER PSATODHRI LETTER OOLINEAR A SIGN AB001LINEAR A SI" +
"GN AB002LINEAR A SIGN AB003LINEAR A SIGN AB004LINEAR A SIGN AB005LINEAR " +
"A SIGN AB006LINEAR A SIGN AB007LINEAR A SIGN AB008LINEAR A SIGN AB009LIN" +
"EAR A SIGN AB010LINEAR A SIGN AB011LINEAR A SIGN AB013LINEAR A SIGN AB01" +
"6LINEAR A SIGN AB017LINEAR A SIGN AB020LINEAR A SIGN AB021LINEAR A SIGN " +
"AB021FLINEAR A SIGN AB021MLINEAR A SIGN AB022LINEAR A SIGN AB022FLINEAR " +
"A SIGN AB022MLINEAR A SIGN AB023LINEAR A SIGN AB023MLINEAR A SIGN AB024L" +
"INEAR A SIGN AB026LINEAR A SIGN AB027LINEAR A SIGN AB028LINEAR A SIGN A0" +
"28BLINEAR A SIGN AB029LINEAR A SIGN AB030LINEAR A SIGN AB031LINEAR A SIG" +
"N AB034LINEAR A SIGN AB037LINEAR A SIGN AB038LINEAR A SIGN AB039LINEAR A" +
" SIGN AB040LINEAR A SIGN AB041LINEAR A SIGN AB044LINEAR A SIGN AB045LINE" +
"AR A SIGN AB046LINEAR A SIGN AB047LINEAR A SIGN AB048LINEAR A SIGN AB049" +
"LINEAR A SIGN AB050LINEAR A SIGN AB051LINEAR A SIGN AB053LINEAR A SIGN A" +
"B054LINEAR A SIGN AB055LINEAR A SIGN AB056LINEAR A SIGN AB057LINEAR A SI" +
"GN AB058LINEAR A SIGN AB059LINEAR A SIGN AB060LINEAR A SIGN AB061LINEAR " +
"A SIGN AB065LINEAR A SIGN AB066LINEAR A SIGN AB067LINEAR A SIGN AB069LIN" +
"EAR A SIGN AB070LINEAR A SIGN AB073LINEAR A SIGN AB074LINEAR A SIGN AB07" +
"6LINEAR A SIGN AB077LINEAR A SIGN AB078LINEAR A SIGN AB079LINEAR A SIGN " +
"AB080LINEAR A SIGN AB081LINEAR A SIGN AB082LINEAR A SIGN AB085LINEAR A S" +
"IGN AB086LINEAR A SIGN AB087LINEAR A SIGN A100-102LINEAR A SIGN AB118LIN" +
"EAR A SIGN AB120LINEAR A SIGN A120BLINEAR A SIGN AB122LINEAR A SIGN AB12" +
"3LINEAR A SIGN AB131ALINEAR A SIGN AB131BLINEAR A SIGN A131CLINEAR A SIG" +
"N AB164LINEAR A SIGN AB171LINEAR A SIGN AB180LINEAR 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 SIGN A309BLINEAR A SIGN A309CLINE" +
"AR A SIGN A310LINEAR A SIGN A311LINEAR A SIGN A312LINEAR A SIGN A313ALIN" +
"EAR A SIGN A313BLINEAR A SIGN A313CLINEAR A SIGN A314LINEAR A SIGN A315L" +
"INEAR A SIGN A316LINEAR A SIGN A317LINEAR A SIGN A318LINEAR A SIGN A319L" +
"INEAR A SIGN A320LINEAR A SIGN A321LINEAR A SIGN A322LINEAR A SIGN A323L" +
"INEAR A SIGN A324LINEAR A SIGN A325LINEAR A SIGN A326LINEAR A SIGN A327L" +
"INEAR A SIGN A328LINEAR A SIGN A329LINEAR A SIGN A330LINEAR A SIGN A331L" +
"INEAR A SIGN A332LINEAR A SIGN A333LINEAR A SIGN A334LINEAR A SIGN A335L" +
"INEAR A SIGN A336LINEAR A SIGN A337LINEAR A SIGN A338LINEAR A SIGN A339L" +
"INEAR A SIGN A340LINEAR A SIGN A341LINEAR A SIGN A342LINEAR A SIGN A343L" +
"INEAR A SIGN A344LINEAR A SIGN A345LINEAR A SIGN A346LINEAR A SIGN A347L" +
"INEAR A SIGN A348LINEAR A SIGN A349LINEAR A SIGN A350LINEAR A SIGN A351L" +
"INEAR A SIGN A352LINEAR A SIGN A353LINEAR A SIGN A354LINEAR A SIGN A355L" +
"INEAR A SIGN A356LINEAR A SIGN A357LINEAR A SIGN A358LINEAR A SIGN A359L" +
"INEAR A SIGN A360LINEAR A SIGN A361LINEAR A SIGN A362LINEAR A SIGN A363L" +
"INEAR A SIGN A364LINEAR A SIGN A365LINEAR A SIGN A366LINEAR A SIGN A367L" +
"INEAR A SIGN A368LINEAR A SIGN A369LINEAR A SIGN A370LINEAR A SIGN A371L" +
"INEAR A SIGN A400-VASLINEAR A SIGN A401-VASLINEAR A SIGN A402-VASLINEAR " +
"A SIGN A403-VASLINEAR A SIGN A404-VASLINEAR A SIGN A405-VASLINEAR A SIGN" +
" A406-VASLINEAR A SIGN A407-VASLINEAR A SIGN A408-VASLINEAR A SIGN A409-" +
"VASLINEAR A SIGN A410-VASLINEAR A SIGN A411-VASLINEAR A SIGN A412-VASLIN" +
"EAR A SIGN A413-VASLINEAR A SIGN A414-VASLINEAR A SIGN A415-VASLINEAR A " +
"SIGN A416-VASLINEAR A SIGN A417-VASLINEAR A SIGN A418-VASLINEAR A SIGN A" +
"501LINEAR A SIGN A502LINEAR A SIGN A503LINEAR A SIGN A504LINEAR A SIGN A" +
"505LINEAR A SIGN A506LINEAR A SIGN A508LINEAR A SIGN A509LINEAR A SIGN A") + ("" +
"510LINEAR A SIGN A511LINEAR A SIGN A512LINEAR A SIGN A513LINEAR A SIGN A" +
"515LINEAR A SIGN A516LINEAR A SIGN A520LINEAR A SIGN A521LINEAR A SIGN A" +
"523LINEAR A SIGN A524LINEAR A SIGN A525LINEAR A SIGN A526LINEAR A SIGN A" +
"527LINEAR A SIGN A528LINEAR A SIGN A529LINEAR A SIGN A530LINEAR A SIGN A" +
"531LINEAR A SIGN A532LINEAR A SIGN A534LINEAR A SIGN A535LINEAR A SIGN A" +
"536LINEAR A SIGN A537LINEAR A SIGN A538LINEAR A SIGN A539LINEAR A SIGN A" +
"540LINEAR A SIGN A541LINEAR A SIGN A542LINEAR A SIGN A545LINEAR A SIGN A" +
"547LINEAR A SIGN A548LINEAR A SIGN A549LINEAR A SIGN A550LINEAR A SIGN A" +
"551LINEAR A SIGN A552LINEAR A SIGN A553LINEAR A SIGN A554LINEAR A SIGN A" +
"555LINEAR A SIGN A556LINEAR A SIGN A557LINEAR A SIGN A559LINEAR A SIGN A" +
"563LINEAR A SIGN A564LINEAR A SIGN A565LINEAR A SIGN A566LINEAR A SIGN A" +
"568LINEAR A SIGN A569LINEAR A SIGN A570LINEAR A SIGN A571LINEAR A SIGN A" +
"572LINEAR A SIGN A573LINEAR A SIGN A574LINEAR A SIGN A575LINEAR A SIGN A" +
"576LINEAR A SIGN A577LINEAR A SIGN A578LINEAR A SIGN A579LINEAR A SIGN A" +
"580LINEAR A SIGN A581LINEAR A SIGN A582LINEAR A SIGN A583LINEAR A SIGN A" +
"584LINEAR A SIGN A585LINEAR A SIGN A586LINEAR A SIGN A587LINEAR A SIGN A" +
"588LINEAR A SIGN A589LINEAR A SIGN A591LINEAR A SIGN A592LINEAR A SIGN A" +
"594LINEAR A SIGN A595LINEAR A SIGN A596LINEAR A SIGN A598LINEAR A SIGN A" +
"600LINEAR A SIGN A601LINEAR A SIGN A602LINEAR A SIGN A603LINEAR A SIGN A" +
"604LINEAR A SIGN A606LINEAR A SIGN A608LINEAR A SIGN A609LINEAR A SIGN A" +
"610LINEAR A SIGN A611LINEAR A SIGN A612LINEAR A SIGN A613LINEAR A SIGN A" +
"614LINEAR A SIGN A615LINEAR A SIGN A616LINEAR A SIGN A617LINEAR A SIGN A" +
"618LINEAR A SIGN A619LINEAR A SIGN A620LINEAR A SIGN A621LINEAR A SIGN A" +
"622LINEAR A SIGN A623LINEAR A SIGN A624LINEAR A SIGN A626LINEAR A SIGN A" +
"627LINEAR A SIGN A628LINEAR A SIGN A629LINEAR A SIGN A634LINEAR A SIGN A" +
"637LINEAR A SIGN A638LINEAR A SIGN A640LINEAR A SIGN A642LINEAR A SIGN A" +
"643LINEAR A SIGN A644LINEAR A SIGN A645LINEAR A SIGN A646LINEAR A SIGN A" +
"648LINEAR A SIGN A649LINEAR A SIGN A651LINEAR A SIGN A652LINEAR A SIGN A" +
"653LINEAR A SIGN A654LINEAR A SIGN A655LINEAR A SIGN A656LINEAR A SIGN A" +
"657LINEAR A SIGN A658LINEAR A SIGN A659LINEAR A SIGN A660LINEAR A SIGN A" +
"661LINEAR A SIGN A662LINEAR A SIGN A663LINEAR A SIGN A664LINEAR A SIGN A" +
"701 ALINEAR A SIGN A702 BLINEAR A SIGN A703 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 L3LINEA" +
"R A SIGN A709-4 L4LINEAR A SIGN A709-6 L6LINEAR A SIGN A710 WLINEAR A SI" +
"GN 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 EYYYLINE" +
"AR A SIGN A732 JELINEAR A SIGN A800LINEAR A SIGN A801LINEAR A SIGN A802L" +
"INEAR A SIGN A803LINEAR A SIGN A804LINEAR A SIGN A805LINEAR A SIGN A806L" +
"INEAR A SIGN A807MODIFIER LETTER SMALL CAPITAL AAMODIFIER LETTER SUPERSC" +
"RIPT TRIANGULAR COLONMODIFIER LETTER SUPERSCRIPT HALF TRIANGULAR COLONMO" +
"DIFIER LETTER SMALL AEMODIFIER LETTER SMALL CAPITAL BMODIFIER LETTER SMA" +
"LL B WITH HOOKMODIFIER LETTER SMALL DZ DIGRAPHMODIFIER LETTER SMALL DZ D" +
"IGRAPH WITH RETROFLEX HOOKMODIFIER LETTER SMALL DZ DIGRAPH WITH CURLMODI" +
"FIER LETTER SMALL DEZH DIGRAPHMODIFIER LETTER SMALL D WITH TAILMODIFIER " +
"LETTER SMALL D WITH HOOKMODIFIER LETTER SMALL D WITH HOOK AND TAILMODIFI" +
"ER LETTER SMALL REVERSED EMODIFIER LETTER SMALL CLOSED REVERSED OPEN EMO" +
"DIFIER LETTER SMALL FENG DIGRAPHMODIFIER LETTER SMALL RAMS HORNMODIFIER " +
"LETTER SMALL CAPITAL GMODIFIER LETTER SMALL G WITH HOOKMODIFIER LETTER S" +
"MALL CAPITAL G WITH HOOKMODIFIER LETTER SMALL H WITH STROKEMODIFIER LETT" +
"ER SMALL CAPITAL HMODIFIER LETTER SMALL HENG WITH HOOKMODIFIER LETTER SM" +
"ALL DOTLESS J WITH STROKE AND HOOKMODIFIER LETTER SMALL LS DIGRAPHMODIFI" +
"ER LETTER SMALL LZ DIGRAPHMODIFIER LETTER SMALL L WITH BELTMODIFIER LETT" +
"ER SMALL CAPITAL L WITH BELTMODIFIER LETTER SMALL L WITH RETROFLEX HOOK " +
"AND BELTMODIFIER LETTER SMALL LEZHMODIFIER LETTER SMALL LEZH WITH RETROF" +
"LEX HOOKMODIFIER LETTER SMALL TURNED YMODIFIER LETTER SMALL TURNED Y WIT" +
"H BELTMODIFIER LETTER SMALL O WITH STROKEMODIFIER LETTER SMALL CAPITAL O" +
"EMODIFIER LETTER SMALL CLOSED OMEGAMODIFIER LETTER SMALL QMODIFIER LETTE" +
"R SMALL TURNED R WITH LONG LEGMODIFIER LETTER SMALL TURNED R WITH LONG L" +
"EG AND RETROFLEX HOOKMODIFIER LETTER SMALL R WITH TAILMODIFIER LETTER SM" +
"ALL R WITH FISHHOOKMODIFIER LETTER SMALL CAPITAL RMODIFIER LETTER SMALL " +
"TC DIGRAPH WITH CURLMODIFIER LETTER SMALL TS DIGRAPHMODIFIER LETTER SMAL" +
"L TS DIGRAPH WITH RETROFLEX HOOKMODIFIER LETTER SMALL TESH DIGRAPHMODIFI" +
"ER LETTER SMALL T WITH RETROFLEX HOOKMODIFIER LETTER SMALL V WITH RIGHT ") + ("" +
"HOOKMODIFIER LETTER SMALL CAPITAL YMODIFIER LETTER GLOTTAL STOP WITH STR" +
"OKEMODIFIER LETTER REVERSED GLOTTAL STOP WITH STROKEMODIFIER LETTER BILA" +
"BIAL CLICKMODIFIER LETTER DENTAL CLICKMODIFIER LETTER LATERAL CLICKMODIF" +
"IER LETTER ALVEOLAR CLICKMODIFIER LETTER RETROFLEX CLICK WITH RETROFLEX " +
"HOOKMODIFIER LETTER SMALL S WITH CURLCYPRIOT SYLLABLE ACYPRIOT SYLLABLE " +
"ECYPRIOT SYLLABLE ICYPRIOT SYLLABLE OCYPRIOT SYLLABLE UCYPRIOT SYLLABLE " +
"JACYPRIOT SYLLABLE JOCYPRIOT SYLLABLE KACYPRIOT SYLLABLE KECYPRIOT SYLLA" +
"BLE KICYPRIOT SYLLABLE KOCYPRIOT SYLLABLE KUCYPRIOT SYLLABLE LACYPRIOT S" +
"YLLABLE LECYPRIOT SYLLABLE LICYPRIOT SYLLABLE LOCYPRIOT SYLLABLE LUCYPRI" +
"OT SYLLABLE MACYPRIOT SYLLABLE MECYPRIOT SYLLABLE MICYPRIOT SYLLABLE MOC" +
"YPRIOT SYLLABLE MUCYPRIOT SYLLABLE NACYPRIOT SYLLABLE NECYPRIOT SYLLABLE" +
" NICYPRIOT SYLLABLE NOCYPRIOT SYLLABLE NUCYPRIOT SYLLABLE PACYPRIOT SYLL" +
"ABLE PECYPRIOT SYLLABLE PICYPRIOT SYLLABLE POCYPRIOT SYLLABLE PUCYPRIOT " +
"SYLLABLE RACYPRIOT SYLLABLE RECYPRIOT SYLLABLE RICYPRIOT SYLLABLE ROCYPR" +
"IOT SYLLABLE RUCYPRIOT SYLLABLE SACYPRIOT SYLLABLE SECYPRIOT SYLLABLE SI" +
"CYPRIOT SYLLABLE SOCYPRIOT SYLLABLE SUCYPRIOT SYLLABLE TACYPRIOT SYLLABL" +
"E TECYPRIOT SYLLABLE TICYPRIOT SYLLABLE TOCYPRIOT SYLLABLE TUCYPRIOT SYL" +
"LABLE WACYPRIOT SYLLABLE WECYPRIOT SYLLABLE WICYPRIOT SYLLABLE WOCYPRIOT" +
" SYLLABLE XACYPRIOT SYLLABLE XECYPRIOT SYLLABLE ZACYPRIOT SYLLABLE ZOIMP" +
"ERIAL ARAMAIC LETTER ALEPHIMPERIAL ARAMAIC LETTER BETHIMPERIAL ARAMAIC L" +
"ETTER GIMELIMPERIAL ARAMAIC LETTER DALETHIMPERIAL ARAMAIC LETTER HEIMPER" +
"IAL ARAMAIC LETTER WAWIMPERIAL ARAMAIC LETTER ZAYINIMPERIAL ARAMAIC LETT" +
"ER HETHIMPERIAL ARAMAIC LETTER TETHIMPERIAL ARAMAIC LETTER YODHIMPERIAL " +
"ARAMAIC LETTER KAPHIMPERIAL ARAMAIC LETTER LAMEDHIMPERIAL ARAMAIC LETTER" +
" MEMIMPERIAL ARAMAIC LETTER NUNIMPERIAL ARAMAIC LETTER SAMEKHIMPERIAL AR" +
"AMAIC LETTER AYINIMPERIAL ARAMAIC LETTER PEIMPERIAL ARAMAIC LETTER SADHE" +
"IMPERIAL ARAMAIC LETTER QOPHIMPERIAL ARAMAIC LETTER RESHIMPERIAL ARAMAIC" +
" LETTER SHINIMPERIAL ARAMAIC LETTER TAWIMPERIAL ARAMAIC SECTION SIGNIMPE" +
"RIAL ARAMAIC NUMBER ONEIMPERIAL ARAMAIC NUMBER TWOIMPERIAL ARAMAIC NUMBE" +
"R THREEIMPERIAL ARAMAIC NUMBER TENIMPERIAL ARAMAIC NUMBER TWENTYIMPERIAL" +
" ARAMAIC NUMBER ONE HUNDREDIMPERIAL ARAMAIC NUMBER ONE THOUSANDIMPERIAL " +
"ARAMAIC NUMBER TEN THOUSANDPALMYRENE LETTER ALEPHPALMYRENE LETTER BETHPA" +
"LMYRENE LETTER GIMELPALMYRENE LETTER DALETHPALMYRENE LETTER HEPALMYRENE " +
"LETTER WAWPALMYRENE LETTER ZAYINPALMYRENE LETTER HETHPALMYRENE LETTER TE" +
"THPALMYRENE LETTER YODHPALMYRENE LETTER KAPHPALMYRENE LETTER LAMEDHPALMY" +
"RENE LETTER MEMPALMYRENE LETTER FINAL NUNPALMYRENE LETTER NUNPALMYRENE L" +
"ETTER SAMEKHPALMYRENE LETTER AYINPALMYRENE LETTER PEPALMYRENE LETTER SAD" +
"HEPALMYRENE LETTER QOPHPALMYRENE LETTER RESHPALMYRENE LETTER SHINPALMYRE" +
"NE LETTER TAWPALMYRENE LEFT-POINTING FLEURONPALMYRENE RIGHT-POINTING FLE" +
"URONPALMYRENE NUMBER ONEPALMYRENE NUMBER TWOPALMYRENE NUMBER THREEPALMYR" +
"ENE NUMBER FOURPALMYRENE NUMBER FIVEPALMYRENE NUMBER TENPALMYRENE NUMBER" +
" TWENTYNABATAEAN LETTER FINAL ALEPHNABATAEAN LETTER ALEPHNABATAEAN LETTE" +
"R FINAL BETHNABATAEAN LETTER BETHNABATAEAN LETTER GIMELNABATAEAN LETTER " +
"DALETHNABATAEAN LETTER FINAL HENABATAEAN LETTER HENABATAEAN LETTER WAWNA" +
"BATAEAN LETTER ZAYINNABATAEAN LETTER HETHNABATAEAN LETTER TETHNABATAEAN " +
"LETTER FINAL YODHNABATAEAN LETTER YODHNABATAEAN LETTER FINAL KAPHNABATAE" +
"AN LETTER KAPHNABATAEAN LETTER FINAL LAMEDHNABATAEAN LETTER LAMEDHNABATA" +
"EAN LETTER FINAL MEMNABATAEAN LETTER MEMNABATAEAN LETTER FINAL NUNNABATA" +
"EAN LETTER NUNNABATAEAN LETTER SAMEKHNABATAEAN LETTER AYINNABATAEAN LETT" +
"ER PENABATAEAN LETTER SADHENABATAEAN LETTER QOPHNABATAEAN LETTER RESHNAB" +
"ATAEAN LETTER FINAL SHINNABATAEAN LETTER SHINNABATAEAN LETTER TAWNABATAE" +
"AN NUMBER ONENABATAEAN NUMBER TWONABATAEAN NUMBER THREENABATAEAN NUMBER " +
"FOURNABATAEAN CRUCIFORM NUMBER FOURNABATAEAN NUMBER FIVENABATAEAN NUMBER" +
" TENNABATAEAN NUMBER TWENTYNABATAEAN NUMBER ONE HUNDREDHATRAN LETTER ALE" +
"PHHATRAN LETTER BETHHATRAN LETTER GIMELHATRAN LETTER DALETH-RESHHATRAN L" +
"ETTER HEHATRAN LETTER WAWHATRAN LETTER ZAYNHATRAN LETTER HETHHATRAN LETT" +
"ER TETHHATRAN LETTER YODHHATRAN LETTER KAPHHATRAN LETTER LAMEDHHATRAN LE" +
"TTER MEMHATRAN LETTER NUNHATRAN LETTER SAMEKHHATRAN LETTER AYNHATRAN LET" +
"TER PEHATRAN LETTER SADHEHATRAN LETTER QOPHHATRAN LETTER SHINHATRAN LETT" +
"ER TAWHATRAN NUMBER ONEHATRAN NUMBER FIVEHATRAN NUMBER TENHATRAN NUMBER " +
"TWENTYHATRAN NUMBER ONE HUNDREDPHOENICIAN LETTER ALFPHOENICIAN LETTER BE" +
"TPHOENICIAN LETTER GAMLPHOENICIAN LETTER DELTPHOENICIAN LETTER HEPHOENIC" +
"IAN LETTER WAUPHOENICIAN LETTER ZAIPHOENICIAN LETTER HETPHOENICIAN LETTE" +
"R TETPHOENICIAN LETTER YODPHOENICIAN LETTER KAFPHOENICIAN LETTER LAMDPHO") + ("" +
"ENICIAN LETTER MEMPHOENICIAN LETTER NUNPHOENICIAN LETTER SEMKPHOENICIAN " +
"LETTER AINPHOENICIAN LETTER PEPHOENICIAN LETTER SADEPHOENICIAN LETTER QO" +
"FPHOENICIAN LETTER ROSHPHOENICIAN LETTER SHINPHOENICIAN LETTER TAUPHOENI" +
"CIAN NUMBER ONEPHOENICIAN NUMBER TENPHOENICIAN NUMBER TWENTYPHOENICIAN N" +
"UMBER ONE HUNDREDPHOENICIAN NUMBER TWOPHOENICIAN NUMBER THREEPHOENICIAN " +
"WORD SEPARATORLYDIAN LETTER ALYDIAN LETTER BLYDIAN LETTER GLYDIAN LETTER" +
" DLYDIAN LETTER ELYDIAN LETTER VLYDIAN LETTER ILYDIAN LETTER YLYDIAN LET" +
"TER KLYDIAN LETTER LLYDIAN LETTER MLYDIAN LETTER NLYDIAN LETTER OLYDIAN " +
"LETTER RLYDIAN LETTER SSLYDIAN LETTER TLYDIAN LETTER ULYDIAN LETTER FLYD" +
"IAN LETTER QLYDIAN LETTER SLYDIAN LETTER TTLYDIAN LETTER ANLYDIAN LETTER" +
" ENLYDIAN LETTER LYLYDIAN LETTER NNLYDIAN LETTER CLYDIAN TRIANGULAR MARK" +
"SIDETIC LETTER N01SIDETIC LETTER N02SIDETIC LETTER N03SIDETIC LETTER N04" +
"SIDETIC LETTER N05SIDETIC LETTER N06SIDETIC LETTER N07SIDETIC LETTER N08" +
"SIDETIC LETTER N09SIDETIC LETTER N10SIDETIC LETTER N11SIDETIC LETTER N12" +
"SIDETIC LETTER N13SIDETIC LETTER N14SIDETIC LETTER N15SIDETIC LETTER N16" +
"SIDETIC LETTER N17SIDETIC LETTER N18SIDETIC LETTER N19SIDETIC LETTER N20" +
"SIDETIC LETTER N21SIDETIC LETTER N22SIDETIC LETTER N23SIDETIC LETTER N24" +
"SIDETIC LETTER N25SIDETIC LETTER N26MEROITIC HIEROGLYPHIC LETTER AMEROIT" +
"IC HIEROGLYPHIC LETTER EMEROITIC HIEROGLYPHIC LETTER IMEROITIC HIEROGLYP" +
"HIC LETTER OMEROITIC HIEROGLYPHIC LETTER YAMEROITIC HIEROGLYPHIC LETTER " +
"WAMEROITIC HIEROGLYPHIC LETTER BAMEROITIC HIEROGLYPHIC LETTER BA-2MEROIT" +
"IC HIEROGLYPHIC LETTER PAMEROITIC HIEROGLYPHIC LETTER MAMEROITIC HIEROGL" +
"YPHIC LETTER NAMEROITIC HIEROGLYPHIC LETTER NA-2MEROITIC HIEROGLYPHIC LE" +
"TTER NEMEROITIC HIEROGLYPHIC LETTER NE-2MEROITIC HIEROGLYPHIC LETTER RAM" +
"EROITIC HIEROGLYPHIC LETTER RA-2MEROITIC HIEROGLYPHIC LETTER LAMEROITIC " +
"HIEROGLYPHIC LETTER KHAMEROITIC HIEROGLYPHIC LETTER HHAMEROITIC HIEROGLY" +
"PHIC LETTER SAMEROITIC HIEROGLYPHIC LETTER SA-2MEROITIC HIEROGLYPHIC LET" +
"TER SEMEROITIC HIEROGLYPHIC LETTER KAMEROITIC HIEROGLYPHIC LETTER QAMERO" +
"ITIC HIEROGLYPHIC LETTER TAMEROITIC HIEROGLYPHIC LETTER TA-2MEROITIC HIE" +
"ROGLYPHIC LETTER TEMEROITIC HIEROGLYPHIC LETTER TE-2MEROITIC HIEROGLYPHI" +
"C LETTER TOMEROITIC HIEROGLYPHIC LETTER DAMEROITIC HIEROGLYPHIC SYMBOL V" +
"IDJMEROITIC HIEROGLYPHIC SYMBOL VIDJ-2MEROITIC CURSIVE LETTER AMEROITIC " +
"CURSIVE LETTER EMEROITIC CURSIVE LETTER IMEROITIC CURSIVE LETTER OMEROIT" +
"IC CURSIVE LETTER YAMEROITIC CURSIVE LETTER WAMEROITIC CURSIVE LETTER BA" +
"MEROITIC CURSIVE LETTER PAMEROITIC CURSIVE LETTER MAMEROITIC CURSIVE LET" +
"TER NAMEROITIC CURSIVE LETTER NEMEROITIC CURSIVE LETTER RAMEROITIC CURSI" +
"VE LETTER LAMEROITIC CURSIVE LETTER KHAMEROITIC CURSIVE LETTER HHAMEROIT" +
"IC CURSIVE LETTER SAMEROITIC CURSIVE LETTER ARCHAIC SAMEROITIC CURSIVE L" +
"ETTER SEMEROITIC CURSIVE LETTER KAMEROITIC CURSIVE LETTER QAMEROITIC CUR" +
"SIVE LETTER TAMEROITIC CURSIVE LETTER TEMEROITIC CURSIVE LETTER TOMEROIT" +
"IC CURSIVE LETTER DAMEROITIC CURSIVE FRACTION ELEVEN TWELFTHSMEROITIC CU" +
"RSIVE FRACTION ONE HALFMEROITIC CURSIVE LOGOGRAM RMTMEROITIC CURSIVE LOG" +
"OGRAM IMNMEROITIC CURSIVE NUMBER ONEMEROITIC CURSIVE NUMBER TWOMEROITIC " +
"CURSIVE NUMBER THREEMEROITIC CURSIVE NUMBER FOURMEROITIC CURSIVE NUMBER " +
"FIVEMEROITIC CURSIVE NUMBER SIXMEROITIC CURSIVE NUMBER SEVENMEROITIC CUR" +
"SIVE NUMBER EIGHTMEROITIC CURSIVE NUMBER NINEMEROITIC CURSIVE NUMBER TEN" +
"MEROITIC CURSIVE NUMBER TWENTYMEROITIC CURSIVE NUMBER THIRTYMEROITIC CUR" +
"SIVE NUMBER FORTYMEROITIC CURSIVE NUMBER FIFTYMEROITIC CURSIVE NUMBER SI" +
"XTYMEROITIC CURSIVE NUMBER SEVENTYMEROITIC CURSIVE NUMBER ONE HUNDREDMER" +
"OITIC CURSIVE NUMBER TWO HUNDREDMEROITIC CURSIVE NUMBER THREE HUNDREDMER" +
"OITIC CURSIVE NUMBER FOUR HUNDREDMEROITIC CURSIVE NUMBER FIVE HUNDREDMER" +
"OITIC CURSIVE NUMBER SIX HUNDREDMEROITIC CURSIVE NUMBER SEVEN HUNDREDMER" +
"OITIC CURSIVE NUMBER EIGHT HUNDREDMEROITIC CURSIVE NUMBER NINE HUNDREDME" +
"ROITIC CURSIVE NUMBER ONE THOUSANDMEROITIC CURSIVE NUMBER TWO THOUSANDME" +
"ROITIC CURSIVE NUMBER THREE THOUSANDMEROITIC CURSIVE NUMBER FOUR THOUSAN" +
"DMEROITIC CURSIVE NUMBER FIVE THOUSANDMEROITIC CURSIVE NUMBER SIX THOUSA" +
"NDMEROITIC CURSIVE NUMBER SEVEN THOUSANDMEROITIC CURSIVE NUMBER EIGHT TH" +
"OUSANDMEROITIC CURSIVE NUMBER NINE THOUSANDMEROITIC CURSIVE NUMBER TEN T" +
"HOUSANDMEROITIC CURSIVE NUMBER TWENTY THOUSANDMEROITIC CURSIVE NUMBER TH" +
"IRTY THOUSANDMEROITIC CURSIVE NUMBER FORTY THOUSANDMEROITIC CURSIVE NUMB" +
"ER FIFTY THOUSANDMEROITIC CURSIVE NUMBER SIXTY THOUSANDMEROITIC CURSIVE " +
"NUMBER SEVENTY THOUSANDMEROITIC CURSIVE NUMBER EIGHTY THOUSANDMEROITIC C" +
"URSIVE NUMBER NINETY THOUSANDMEROITIC CURSIVE NUMBER ONE HUNDRED THOUSAN" +
"DMEROITIC CURSIVE NUMBER TWO HUNDRED THOUSANDMEROITIC CURSIVE NUMBER THR") + ("" +
"EE HUNDRED THOUSANDMEROITIC CURSIVE NUMBER FOUR HUNDRED THOUSANDMEROITIC" +
" CURSIVE NUMBER FIVE HUNDRED THOUSANDMEROITIC CURSIVE NUMBER SIX HUNDRED" +
" THOUSANDMEROITIC CURSIVE NUMBER SEVEN HUNDRED THOUSANDMEROITIC CURSIVE " +
"NUMBER EIGHT HUNDRED THOUSANDMEROITIC CURSIVE NUMBER NINE HUNDRED THOUSA" +
"NDMEROITIC CURSIVE FRACTION ONE TWELFTHMEROITIC CURSIVE FRACTION TWO TWE" +
"LFTHSMEROITIC CURSIVE FRACTION THREE TWELFTHSMEROITIC CURSIVE FRACTION F" +
"OUR TWELFTHSMEROITIC CURSIVE FRACTION FIVE TWELFTHSMEROITIC CURSIVE FRAC" +
"TION SIX TWELFTHSMEROITIC CURSIVE FRACTION SEVEN TWELFTHSMEROITIC CURSIV" +
"E FRACTION EIGHT TWELFTHSMEROITIC CURSIVE FRACTION NINE TWELFTHSMEROITIC" +
" CURSIVE FRACTION TEN TWELFTHSKHAROSHTHI LETTER AKHAROSHTHI VOWEL SIGN I" +
"KHAROSHTHI VOWEL SIGN UKHAROSHTHI VOWEL SIGN VOCALIC RKHAROSHTHI VOWEL S" +
"IGN EKHAROSHTHI VOWEL SIGN OKHAROSHTHI VOWEL LENGTH MARKKHAROSHTHI SIGN " +
"DOUBLE RING BELOWKHAROSHTHI SIGN ANUSVARAKHAROSHTHI SIGN VISARGAKHAROSHT" +
"HI LETTER KAKHAROSHTHI LETTER KHAKHAROSHTHI LETTER GAKHAROSHTHI LETTER G" +
"HAKHAROSHTHI LETTER CAKHAROSHTHI LETTER CHAKHAROSHTHI LETTER JAKHAROSHTH" +
"I LETTER NYAKHAROSHTHI LETTER TTAKHAROSHTHI LETTER TTHAKHAROSHTHI LETTER" +
" DDAKHAROSHTHI LETTER DDHAKHAROSHTHI LETTER NNAKHAROSHTHI LETTER TAKHARO" +
"SHTHI LETTER THAKHAROSHTHI LETTER DAKHAROSHTHI LETTER DHAKHAROSHTHI LETT" +
"ER NAKHAROSHTHI LETTER PAKHAROSHTHI LETTER PHAKHAROSHTHI LETTER BAKHAROS" +
"HTHI LETTER BHAKHAROSHTHI LETTER MAKHAROSHTHI LETTER YAKHAROSHTHI LETTER" +
" RAKHAROSHTHI LETTER LAKHAROSHTHI LETTER VAKHAROSHTHI LETTER SHAKHAROSHT" +
"HI LETTER SSAKHAROSHTHI LETTER SAKHAROSHTHI LETTER ZAKHAROSHTHI LETTER H" +
"AKHAROSHTHI LETTER KKAKHAROSHTHI LETTER TTTHAKHAROSHTHI LETTER TTTAKHARO" +
"SHTHI LETTER VHAKHAROSHTHI SIGN BAR ABOVEKHAROSHTHI SIGN CAUDAKHAROSHTHI" +
" SIGN DOT BELOWKHAROSHTHI VIRAMAKHAROSHTHI DIGIT ONEKHAROSHTHI DIGIT TWO" +
"KHAROSHTHI DIGIT THREEKHAROSHTHI DIGIT FOURKHAROSHTHI NUMBER TENKHAROSHT" +
"HI NUMBER TWENTYKHAROSHTHI NUMBER ONE HUNDREDKHAROSHTHI NUMBER ONE THOUS" +
"ANDKHAROSHTHI FRACTION ONE HALFKHAROSHTHI PUNCTUATION DOTKHAROSHTHI PUNC" +
"TUATION SMALL CIRCLEKHAROSHTHI PUNCTUATION CIRCLEKHAROSHTHI PUNCTUATION " +
"CRESCENT BARKHAROSHTHI PUNCTUATION MANGALAMKHAROSHTHI PUNCTUATION LOTUSK" +
"HAROSHTHI PUNCTUATION DANDAKHAROSHTHI PUNCTUATION DOUBLE DANDAKHAROSHTHI" +
" PUNCTUATION LINESOLD SOUTH ARABIAN LETTER HEOLD SOUTH ARABIAN LETTER LA" +
"MEDHOLD SOUTH ARABIAN LETTER HETHOLD SOUTH ARABIAN LETTER MEMOLD SOUTH A" +
"RABIAN LETTER QOPHOLD SOUTH ARABIAN LETTER WAWOLD SOUTH ARABIAN LETTER S" +
"HINOLD SOUTH ARABIAN LETTER RESHOLD SOUTH ARABIAN LETTER BETHOLD SOUTH A" +
"RABIAN LETTER TAWOLD SOUTH ARABIAN LETTER SATOLD SOUTH ARABIAN LETTER KA" +
"PHOLD SOUTH ARABIAN LETTER NUNOLD SOUTH ARABIAN LETTER KHETHOLD SOUTH AR" +
"ABIAN LETTER SADHEOLD SOUTH ARABIAN LETTER SAMEKHOLD SOUTH ARABIAN LETTE" +
"R FEOLD SOUTH ARABIAN LETTER ALEFOLD SOUTH ARABIAN LETTER AYNOLD SOUTH A" +
"RABIAN LETTER DHADHEOLD SOUTH ARABIAN LETTER GIMELOLD SOUTH ARABIAN LETT" +
"ER DALETHOLD SOUTH ARABIAN LETTER GHAYNOLD SOUTH ARABIAN LETTER TETHOLD " +
"SOUTH ARABIAN LETTER ZAYNOLD SOUTH ARABIAN LETTER DHALETHOLD SOUTH ARABI" +
"AN LETTER YODHOLD SOUTH ARABIAN LETTER THAWOLD SOUTH ARABIAN LETTER THET" +
"HOLD SOUTH ARABIAN NUMBER ONEOLD SOUTH ARABIAN NUMBER FIFTYOLD SOUTH ARA" +
"BIAN NUMERIC INDICATOROLD NORTH ARABIAN LETTER HEHOLD NORTH ARABIAN LETT" +
"ER LAMOLD NORTH ARABIAN LETTER HAHOLD NORTH ARABIAN LETTER MEEMOLD NORTH" +
" ARABIAN LETTER QAFOLD NORTH ARABIAN LETTER WAWOLD NORTH ARABIAN LETTER " +
"ES-2OLD NORTH ARABIAN LETTER REHOLD NORTH ARABIAN LETTER BEHOLD NORTH AR" +
"ABIAN LETTER TEHOLD NORTH ARABIAN LETTER ES-1OLD NORTH ARABIAN LETTER KA" +
"FOLD NORTH ARABIAN LETTER NOONOLD NORTH ARABIAN LETTER KHAHOLD NORTH ARA" +
"BIAN LETTER SADOLD NORTH ARABIAN LETTER ES-3OLD NORTH ARABIAN LETTER FEH" +
"OLD NORTH ARABIAN LETTER ALEFOLD NORTH ARABIAN LETTER AINOLD NORTH ARABI" +
"AN LETTER DADOLD NORTH ARABIAN LETTER GEEMOLD NORTH ARABIAN LETTER DALOL" +
"D NORTH ARABIAN LETTER GHAINOLD NORTH ARABIAN LETTER TAHOLD NORTH ARABIA" +
"N LETTER ZAINOLD NORTH ARABIAN LETTER THALOLD NORTH ARABIAN LETTER YEHOL" +
"D NORTH ARABIAN LETTER THEHOLD NORTH ARABIAN LETTER ZAHOLD NORTH ARABIAN" +
" NUMBER ONEOLD NORTH ARABIAN NUMBER TENOLD NORTH ARABIAN NUMBER TWENTYMA" +
"NICHAEAN LETTER ALEPHMANICHAEAN LETTER BETHMANICHAEAN LETTER BHETHMANICH" +
"AEAN LETTER GIMELMANICHAEAN LETTER GHIMELMANICHAEAN LETTER DALETHMANICHA" +
"EAN LETTER HEMANICHAEAN LETTER WAWMANICHAEAN SIGN UDMANICHAEAN LETTER ZA" +
"YINMANICHAEAN LETTER ZHAYINMANICHAEAN LETTER JAYINMANICHAEAN LETTER JHAY" +
"INMANICHAEAN LETTER HETHMANICHAEAN LETTER TETHMANICHAEAN LETTER YODHMANI" +
"CHAEAN LETTER KAPHMANICHAEAN LETTER XAPHMANICHAEAN LETTER KHAPHMANICHAEA" +
"N LETTER LAMEDHMANICHAEAN LETTER DHAMEDHMANICHAEAN LETTER THAMEDHMANICHA") + ("" +
"EAN LETTER MEMMANICHAEAN LETTER NUNMANICHAEAN LETTER SAMEKHMANICHAEAN LE" +
"TTER AYINMANICHAEAN LETTER AAYINMANICHAEAN LETTER PEMANICHAEAN LETTER FE" +
"MANICHAEAN LETTER SADHEMANICHAEAN LETTER QOPHMANICHAEAN LETTER XOPHMANIC" +
"HAEAN LETTER QHOPHMANICHAEAN LETTER RESHMANICHAEAN LETTER SHINMANICHAEAN" +
" LETTER SSHINMANICHAEAN LETTER TAWMANICHAEAN ABBREVIATION MARK ABOVEMANI" +
"CHAEAN ABBREVIATION MARK BELOWMANICHAEAN NUMBER ONEMANICHAEAN NUMBER FIV" +
"EMANICHAEAN NUMBER TENMANICHAEAN NUMBER TWENTYMANICHAEAN NUMBER ONE HUND" +
"REDMANICHAEAN PUNCTUATION STARMANICHAEAN PUNCTUATION FLEURONMANICHAEAN P" +
"UNCTUATION DOUBLE DOT WITHIN DOTMANICHAEAN PUNCTUATION DOT WITHIN DOTMAN" +
"ICHAEAN PUNCTUATION DOTMANICHAEAN PUNCTUATION TWO DOTSMANICHAEAN PUNCTUA" +
"TION LINE FILLERAVESTAN LETTER AAVESTAN LETTER AAAVESTAN LETTER AOAVESTA" +
"N LETTER AAOAVESTAN LETTER ANAVESTAN LETTER AANAVESTAN LETTER AEAVESTAN " +
"LETTER AEEAVESTAN LETTER EAVESTAN LETTER EEAVESTAN LETTER OAVESTAN LETTE" +
"R OOAVESTAN LETTER IAVESTAN LETTER IIAVESTAN LETTER UAVESTAN LETTER UUAV" +
"ESTAN LETTER KEAVESTAN LETTER XEAVESTAN LETTER XYEAVESTAN LETTER XVEAVES" +
"TAN LETTER GEAVESTAN LETTER GGEAVESTAN LETTER GHEAVESTAN LETTER CEAVESTA" +
"N LETTER JEAVESTAN LETTER TEAVESTAN LETTER THEAVESTAN LETTER DEAVESTAN L" +
"ETTER DHEAVESTAN LETTER TTEAVESTAN LETTER PEAVESTAN LETTER FEAVESTAN LET" +
"TER BEAVESTAN LETTER BHEAVESTAN LETTER NGEAVESTAN LETTER NGYEAVESTAN LET" +
"TER NGVEAVESTAN LETTER NEAVESTAN LETTER NYEAVESTAN LETTER NNEAVESTAN LET" +
"TER MEAVESTAN LETTER HMEAVESTAN LETTER YYEAVESTAN LETTER YEAVESTAN LETTE" +
"R VEAVESTAN LETTER REAVESTAN LETTER LEAVESTAN LETTER SEAVESTAN LETTER ZE" +
"AVESTAN LETTER SHEAVESTAN LETTER ZHEAVESTAN LETTER SHYEAVESTAN LETTER SS" +
"HEAVESTAN LETTER HEAVESTAN ABBREVIATION MARKTINY TWO DOTS OVER ONE DOT P" +
"UNCTUATIONSMALL TWO DOTS OVER ONE DOT PUNCTUATIONLARGE TWO DOTS OVER ONE" +
" DOT PUNCTUATIONLARGE ONE DOT OVER TWO DOTS PUNCTUATIONLARGE TWO RINGS O" +
"VER ONE RING PUNCTUATIONLARGE ONE RING OVER TWO RINGS PUNCTUATIONINSCRIP" +
"TIONAL PARTHIAN LETTER ALEPHINSCRIPTIONAL PARTHIAN LETTER BETHINSCRIPTIO" +
"NAL PARTHIAN LETTER GIMELINSCRIPTIONAL PARTHIAN LETTER DALETHINSCRIPTION" +
"AL PARTHIAN LETTER HEINSCRIPTIONAL PARTHIAN LETTER WAWINSCRIPTIONAL PART" +
"HIAN LETTER ZAYININSCRIPTIONAL PARTHIAN LETTER HETHINSCRIPTIONAL PARTHIA" +
"N LETTER TETHINSCRIPTIONAL PARTHIAN LETTER YODHINSCRIPTIONAL PARTHIAN LE" +
"TTER KAPHINSCRIPTIONAL PARTHIAN LETTER LAMEDHINSCRIPTIONAL PARTHIAN LETT" +
"ER MEMINSCRIPTIONAL PARTHIAN LETTER NUNINSCRIPTIONAL PARTHIAN LETTER SAM" +
"EKHINSCRIPTIONAL PARTHIAN LETTER AYININSCRIPTIONAL PARTHIAN LETTER PEINS" +
"CRIPTIONAL PARTHIAN LETTER SADHEINSCRIPTIONAL PARTHIAN LETTER QOPHINSCRI" +
"PTIONAL PARTHIAN LETTER RESHINSCRIPTIONAL PARTHIAN LETTER SHININSCRIPTIO" +
"NAL PARTHIAN LETTER TAWINSCRIPTIONAL PARTHIAN NUMBER ONEINSCRIPTIONAL PA" +
"RTHIAN NUMBER TWOINSCRIPTIONAL PARTHIAN NUMBER THREEINSCRIPTIONAL PARTHI" +
"AN NUMBER FOURINSCRIPTIONAL PARTHIAN NUMBER TENINSCRIPTIONAL PARTHIAN NU" +
"MBER TWENTYINSCRIPTIONAL PARTHIAN NUMBER ONE HUNDREDINSCRIPTIONAL PARTHI" +
"AN NUMBER ONE THOUSANDINSCRIPTIONAL PAHLAVI LETTER ALEPHINSCRIPTIONAL PA" +
"HLAVI LETTER BETHINSCRIPTIONAL PAHLAVI LETTER GIMELINSCRIPTIONAL PAHLAVI" +
" LETTER DALETHINSCRIPTIONAL PAHLAVI LETTER HEINSCRIPTIONAL PAHLAVI LETTE" +
"R WAW-AYIN-RESHINSCRIPTIONAL PAHLAVI LETTER ZAYININSCRIPTIONAL PAHLAVI L" +
"ETTER HETHINSCRIPTIONAL PAHLAVI LETTER TETHINSCRIPTIONAL PAHLAVI LETTER " +
"YODHINSCRIPTIONAL PAHLAVI LETTER KAPHINSCRIPTIONAL PAHLAVI LETTER LAMEDH" +
"INSCRIPTIONAL PAHLAVI LETTER MEM-QOPHINSCRIPTIONAL PAHLAVI LETTER NUNINS" +
"CRIPTIONAL PAHLAVI LETTER SAMEKHINSCRIPTIONAL PAHLAVI LETTER PEINSCRIPTI" +
"ONAL PAHLAVI LETTER SADHEINSCRIPTIONAL PAHLAVI LETTER SHININSCRIPTIONAL " +
"PAHLAVI LETTER TAWINSCRIPTIONAL PAHLAVI NUMBER ONEINSCRIPTIONAL PAHLAVI " +
"NUMBER TWOINSCRIPTIONAL PAHLAVI NUMBER THREEINSCRIPTIONAL PAHLAVI NUMBER" +
" FOURINSCRIPTIONAL PAHLAVI NUMBER TENINSCRIPTIONAL PAHLAVI NUMBER TWENTY" +
"INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDREDINSCRIPTIONAL PAHLAVI NUMBER ONE" +
" THOUSANDPSALTER PAHLAVI LETTER ALEPHPSALTER PAHLAVI LETTER BETHPSALTER " +
"PAHLAVI LETTER GIMELPSALTER PAHLAVI LETTER DALETHPSALTER PAHLAVI LETTER " +
"HEPSALTER PAHLAVI LETTER WAW-AYIN-RESHPSALTER PAHLAVI LETTER ZAYINPSALTE" +
"R PAHLAVI LETTER HETHPSALTER PAHLAVI LETTER YODHPSALTER PAHLAVI LETTER K" +
"APHPSALTER PAHLAVI LETTER LAMEDHPSALTER PAHLAVI LETTER MEM-QOPHPSALTER P" +
"AHLAVI LETTER NUNPSALTER PAHLAVI LETTER SAMEKHPSALTER PAHLAVI LETTER PEP" +
"SALTER PAHLAVI LETTER SADHEPSALTER PAHLAVI LETTER SHINPSALTER PAHLAVI LE" +
"TTER TAWPSALTER PAHLAVI SECTION MARKPSALTER PAHLAVI TURNED SECTION MARKP" +
"SALTER PAHLAVI FOUR DOTS WITH CROSSPSALTER PAHLAVI FOUR DOTS WITH DOTPSA" +
"LTER PAHLAVI NUMBER ONEPSALTER PAHLAVI NUMBER TWOPSALTER PAHLAVI NUMBER ") + ("" +
"THREEPSALTER PAHLAVI NUMBER FOURPSALTER PAHLAVI NUMBER TENPSALTER PAHLAV" +
"I NUMBER TWENTYPSALTER PAHLAVI NUMBER ONE HUNDREDOLD TURKIC LETTER ORKHO" +
"N AOLD TURKIC LETTER YENISEI AOLD TURKIC LETTER YENISEI AEOLD TURKIC LET" +
"TER ORKHON IOLD TURKIC LETTER YENISEI IOLD TURKIC LETTER YENISEI EOLD TU" +
"RKIC LETTER ORKHON OOLD TURKIC LETTER ORKHON OEOLD TURKIC LETTER YENISEI" +
" OEOLD TURKIC LETTER ORKHON ABOLD TURKIC LETTER YENISEI ABOLD TURKIC LET" +
"TER ORKHON AEBOLD TURKIC LETTER YENISEI AEBOLD TURKIC LETTER ORKHON AGOL" +
"D TURKIC LETTER YENISEI AGOLD TURKIC LETTER ORKHON AEGOLD TURKIC LETTER " +
"YENISEI AEGOLD TURKIC LETTER ORKHON ADOLD TURKIC LETTER YENISEI ADOLD TU" +
"RKIC LETTER ORKHON AEDOLD TURKIC LETTER ORKHON EZOLD TURKIC LETTER YENIS" +
"EI EZOLD TURKIC LETTER ORKHON AYOLD TURKIC LETTER YENISEI AYOLD TURKIC L" +
"ETTER ORKHON AEYOLD TURKIC LETTER YENISEI AEYOLD TURKIC LETTER ORKHON AE" +
"KOLD TURKIC LETTER YENISEI AEKOLD TURKIC LETTER ORKHON OEKOLD TURKIC LET" +
"TER YENISEI OEKOLD TURKIC LETTER ORKHON ALOLD TURKIC LETTER YENISEI ALOL" +
"D TURKIC LETTER ORKHON AELOLD TURKIC LETTER ORKHON ELTOLD TURKIC LETTER " +
"ORKHON EMOLD TURKIC LETTER ORKHON ANOLD TURKIC LETTER ORKHON AENOLD TURK" +
"IC LETTER YENISEI AENOLD TURKIC LETTER ORKHON ENTOLD TURKIC LETTER YENIS" +
"EI ENTOLD TURKIC LETTER ORKHON ENCOLD TURKIC LETTER YENISEI ENCOLD TURKI" +
"C LETTER ORKHON ENYOLD TURKIC LETTER YENISEI ENYOLD TURKIC LETTER YENISE" +
"I ANGOLD TURKIC LETTER ORKHON ENGOLD TURKIC LETTER YENISEI AENGOLD TURKI" +
"C LETTER ORKHON EPOLD TURKIC LETTER ORKHON OPOLD TURKIC LETTER ORKHON IC" +
"OLD TURKIC LETTER ORKHON ECOLD TURKIC LETTER YENISEI ECOLD TURKIC LETTER" +
" ORKHON AQOLD TURKIC LETTER YENISEI AQOLD TURKIC LETTER ORKHON IQOLD TUR" +
"KIC LETTER YENISEI IQOLD TURKIC LETTER ORKHON OQOLD TURKIC LETTER YENISE" +
"I OQOLD TURKIC LETTER ORKHON AROLD TURKIC LETTER YENISEI AROLD TURKIC LE" +
"TTER ORKHON AEROLD TURKIC LETTER ORKHON ASOLD TURKIC LETTER ORKHON AESOL" +
"D TURKIC LETTER ORKHON ASHOLD TURKIC LETTER YENISEI ASHOLD TURKIC LETTER" +
" ORKHON ESHOLD TURKIC LETTER YENISEI ESHOLD TURKIC LETTER ORKHON ATOLD T" +
"URKIC LETTER YENISEI ATOLD TURKIC LETTER ORKHON AETOLD TURKIC LETTER YEN" +
"ISEI AETOLD TURKIC LETTER ORKHON OTOLD TURKIC LETTER ORKHON BASHOLD HUNG" +
"ARIAN CAPITAL LETTER AOLD HUNGARIAN CAPITAL LETTER AAOLD HUNGARIAN CAPIT" +
"AL LETTER EBOLD HUNGARIAN CAPITAL LETTER AMBOLD HUNGARIAN CAPITAL LETTER" +
" ECOLD HUNGARIAN CAPITAL LETTER ENCOLD HUNGARIAN CAPITAL LETTER ECSOLD H" +
"UNGARIAN CAPITAL LETTER EDOLD HUNGARIAN CAPITAL LETTER ANDOLD HUNGARIAN " +
"CAPITAL LETTER EOLD HUNGARIAN CAPITAL LETTER CLOSE EOLD HUNGARIAN CAPITA" +
"L LETTER EEOLD HUNGARIAN CAPITAL LETTER EFOLD HUNGARIAN CAPITAL LETTER E" +
"GOLD HUNGARIAN CAPITAL LETTER EGYOLD HUNGARIAN CAPITAL LETTER EHOLD HUNG" +
"ARIAN CAPITAL LETTER IOLD HUNGARIAN CAPITAL LETTER IIOLD HUNGARIAN CAPIT" +
"AL LETTER EJOLD HUNGARIAN CAPITAL LETTER EKOLD HUNGARIAN CAPITAL LETTER " +
"AKOLD HUNGARIAN CAPITAL LETTER UNKOLD HUNGARIAN CAPITAL LETTER ELOLD HUN" +
"GARIAN CAPITAL LETTER ELYOLD HUNGARIAN CAPITAL LETTER EMOLD HUNGARIAN CA" +
"PITAL LETTER ENOLD HUNGARIAN CAPITAL LETTER ENYOLD HUNGARIAN CAPITAL LET" +
"TER OOLD HUNGARIAN CAPITAL LETTER OOOLD HUNGARIAN CAPITAL LETTER NIKOLSB" +
"URG OEOLD HUNGARIAN CAPITAL LETTER RUDIMENTA OEOLD HUNGARIAN CAPITAL LET" +
"TER OEEOLD HUNGARIAN CAPITAL LETTER EPOLD HUNGARIAN CAPITAL LETTER EMPOL" +
"D HUNGARIAN CAPITAL LETTER EROLD HUNGARIAN CAPITAL LETTER SHORT EROLD HU" +
"NGARIAN CAPITAL LETTER ESOLD HUNGARIAN CAPITAL LETTER ESZOLD HUNGARIAN C" +
"APITAL LETTER ETOLD HUNGARIAN CAPITAL LETTER ENTOLD HUNGARIAN CAPITAL LE" +
"TTER ETYOLD HUNGARIAN CAPITAL LETTER ECHOLD HUNGARIAN CAPITAL LETTER UOL" +
"D HUNGARIAN CAPITAL LETTER UUOLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UEO" +
"LD HUNGARIAN CAPITAL LETTER RUDIMENTA UEOLD HUNGARIAN CAPITAL LETTER EVO" +
"LD HUNGARIAN CAPITAL LETTER EZOLD HUNGARIAN CAPITAL LETTER EZSOLD HUNGAR" +
"IAN CAPITAL LETTER ENT-SHAPED SIGNOLD HUNGARIAN CAPITAL LETTER USOLD HUN" +
"GARIAN SMALL LETTER AOLD HUNGARIAN SMALL LETTER AAOLD HUNGARIAN SMALL LE" +
"TTER EBOLD HUNGARIAN SMALL LETTER AMBOLD HUNGARIAN SMALL LETTER ECOLD HU" +
"NGARIAN SMALL LETTER ENCOLD HUNGARIAN SMALL LETTER ECSOLD HUNGARIAN SMAL" +
"L LETTER EDOLD HUNGARIAN SMALL LETTER ANDOLD HUNGARIAN SMALL LETTER EOLD" +
" HUNGARIAN SMALL LETTER CLOSE EOLD HUNGARIAN SMALL LETTER EEOLD HUNGARIA" +
"N SMALL LETTER EFOLD HUNGARIAN SMALL LETTER EGOLD HUNGARIAN SMALL LETTER" +
" EGYOLD HUNGARIAN SMALL LETTER EHOLD HUNGARIAN SMALL LETTER IOLD HUNGARI" +
"AN SMALL LETTER IIOLD HUNGARIAN SMALL LETTER EJOLD HUNGARIAN SMALL LETTE" +
"R EKOLD HUNGARIAN SMALL LETTER AKOLD HUNGARIAN SMALL LETTER UNKOLD HUNGA" +
"RIAN SMALL LETTER ELOLD HUNGARIAN SMALL LETTER ELYOLD HUNGARIAN SMALL LE" +
"TTER EMOLD HUNGARIAN SMALL LETTER ENOLD HUNGARIAN SMALL LETTER ENYOLD HU") + ("" +
"NGARIAN SMALL LETTER OOLD HUNGARIAN SMALL LETTER OOOLD HUNGARIAN SMALL L" +
"ETTER 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 H" +
"UNGARIAN SMALL LETTER ESOLD HUNGARIAN SMALL LETTER ESZOLD HUNGARIAN SMAL" +
"L LETTER ETOLD HUNGARIAN SMALL LETTER ENTOLD HUNGARIAN SMALL LETTER ETYO" +
"LD HUNGARIAN SMALL LETTER ECHOLD HUNGARIAN SMALL LETTER UOLD HUNGARIAN S" +
"MALL LETTER UUOLD HUNGARIAN SMALL LETTER NIKOLSBURG UEOLD HUNGARIAN SMAL" +
"L LETTER RUDIMENTA UEOLD HUNGARIAN SMALL LETTER EVOLD HUNGARIAN SMALL LE" +
"TTER EZOLD HUNGARIAN SMALL LETTER EZSOLD HUNGARIAN SMALL LETTER ENT-SHAP" +
"ED SIGNOLD HUNGARIAN SMALL LETTER USOLD HUNGARIAN NUMBER ONEOLD HUNGARIA" +
"N NUMBER FIVEOLD HUNGARIAN NUMBER TENOLD HUNGARIAN NUMBER FIFTYOLD HUNGA" +
"RIAN NUMBER ONE HUNDREDOLD HUNGARIAN NUMBER ONE THOUSANDHANIFI ROHINGYA " +
"LETTER AHANIFI ROHINGYA LETTER BAHANIFI ROHINGYA LETTER PAHANIFI ROHINGY" +
"A LETTER TAHANIFI ROHINGYA LETTER TTAHANIFI ROHINGYA LETTER JAHANIFI ROH" +
"INGYA LETTER CAHANIFI ROHINGYA LETTER HAHANIFI ROHINGYA LETTER KHAHANIFI" +
" ROHINGYA LETTER FAHANIFI ROHINGYA LETTER DAHANIFI ROHINGYA LETTER DDAHA" +
"NIFI ROHINGYA LETTER RAHANIFI ROHINGYA LETTER RRAHANIFI ROHINGYA LETTER " +
"ZAHANIFI ROHINGYA LETTER SAHANIFI ROHINGYA LETTER SHAHANIFI ROHINGYA LET" +
"TER KAHANIFI ROHINGYA LETTER GAHANIFI ROHINGYA LETTER LAHANIFI ROHINGYA " +
"LETTER MAHANIFI ROHINGYA LETTER NAHANIFI ROHINGYA LETTER WAHANIFI ROHING" +
"YA LETTER KINNA WAHANIFI ROHINGYA LETTER YAHANIFI ROHINGYA LETTER KINNA " +
"YAHANIFI ROHINGYA LETTER NGAHANIFI ROHINGYA LETTER NYAHANIFI ROHINGYA LE" +
"TTER VAHANIFI ROHINGYA VOWEL AHANIFI ROHINGYA VOWEL IHANIFI ROHINGYA VOW" +
"EL UHANIFI ROHINGYA VOWEL EHANIFI ROHINGYA VOWEL OHANIFI ROHINGYA MARK S" +
"AKINHANIFI ROHINGYA MARK NA KHONNAHANIFI ROHINGYA SIGN HARBAHAYHANIFI RO" +
"HINGYA SIGN TAHALAHANIFI ROHINGYA SIGN TANAHANIFI ROHINGYA SIGN TASSIHAN" +
"IFI ROHINGYA DIGIT ZEROHANIFI ROHINGYA DIGIT ONEHANIFI ROHINGYA DIGIT TW" +
"OHANIFI ROHINGYA DIGIT THREEHANIFI ROHINGYA DIGIT FOURHANIFI ROHINGYA DI" +
"GIT FIVEHANIFI ROHINGYA DIGIT SIXHANIFI ROHINGYA DIGIT SEVENHANIFI ROHIN" +
"GYA DIGIT EIGHTHANIFI ROHINGYA DIGIT NINEGARAY DIGIT ZEROGARAY DIGIT ONE" +
"GARAY DIGIT TWOGARAY DIGIT THREEGARAY DIGIT FOURGARAY DIGIT FIVEGARAY DI" +
"GIT SIXGARAY DIGIT SEVENGARAY DIGIT EIGHTGARAY DIGIT NINEGARAY VOWEL SIG" +
"N AGARAY VOWEL SIGN IGARAY VOWEL SIGN OGARAY VOWEL SIGN EEGARAY VOWEL LE" +
"NGTH MARKGARAY SUKUNGARAY CAPITAL LETTER AGARAY CAPITAL LETTER CAGARAY C" +
"APITAL LETTER MAGARAY CAPITAL LETTER KAGARAY CAPITAL LETTER BAGARAY CAPI" +
"TAL LETTER JAGARAY CAPITAL LETTER SAGARAY CAPITAL LETTER WAGARAY CAPITAL" +
" LETTER LAGARAY CAPITAL LETTER GAGARAY CAPITAL LETTER DAGARAY CAPITAL LE" +
"TTER XAGARAY CAPITAL LETTER YAGARAY CAPITAL LETTER TAGARAY CAPITAL LETTE" +
"R RAGARAY CAPITAL LETTER NYAGARAY CAPITAL LETTER FAGARAY CAPITAL LETTER " +
"NAGARAY CAPITAL LETTER PAGARAY CAPITAL LETTER HAGARAY CAPITAL LETTER OLD" +
" KAGARAY CAPITAL LETTER OLD NAGARAY VOWEL SIGN EGARAY CONSONANT GEMINATI" +
"ON MARKGARAY COMBINING DOT ABOVEGARAY COMBINING DOUBLE DOT ABOVEGARAY CO" +
"NSONANT NASALIZATION MARKGARAY HYPHENGARAY REDUPLICATION MARKGARAY SMALL" +
" LETTER AGARAY SMALL LETTER CAGARAY SMALL LETTER MAGARAY SMALL LETTER KA" +
"GARAY SMALL LETTER BAGARAY SMALL LETTER JAGARAY SMALL LETTER SAGARAY SMA" +
"LL LETTER WAGARAY SMALL LETTER LAGARAY SMALL LETTER GAGARAY SMALL LETTER" +
" DAGARAY SMALL LETTER XAGARAY SMALL LETTER YAGARAY SMALL LETTER TAGARAY " +
"SMALL LETTER RAGARAY SMALL LETTER NYAGARAY SMALL LETTER FAGARAY SMALL LE" +
"TTER NAGARAY SMALL LETTER PAGARAY SMALL LETTER HAGARAY SMALL LETTER OLD " +
"KAGARAY SMALL LETTER OLD NAGARAY PLUS SIGNGARAY MINUS SIGNRUMI DIGIT ONE" +
"RUMI DIGIT TWORUMI DIGIT THREERUMI DIGIT FOURRUMI DIGIT FIVERUMI DIGIT S" +
"IXRUMI DIGIT SEVENRUMI DIGIT EIGHTRUMI DIGIT NINERUMI NUMBER TENRUMI NUM" +
"BER TWENTYRUMI NUMBER THIRTYRUMI NUMBER FORTYRUMI NUMBER FIFTYRUMI NUMBE" +
"R SIXTYRUMI NUMBER SEVENTYRUMI NUMBER EIGHTYRUMI NUMBER NINETYRUMI NUMBE" +
"R ONE HUNDREDRUMI NUMBER TWO HUNDREDRUMI NUMBER THREE HUNDREDRUMI NUMBER" +
" FOUR HUNDREDRUMI NUMBER FIVE HUNDREDRUMI NUMBER SIX HUNDREDRUMI NUMBER " +
"SEVEN HUNDREDRUMI NUMBER EIGHT HUNDREDRUMI NUMBER NINE HUNDREDRUMI FRACT" +
"ION ONE HALFRUMI FRACTION ONE QUARTERRUMI FRACTION ONE THIRDRUMI FRACTIO" +
"N TWO THIRDSYEZIDI LETTER ELIFYEZIDI LETTER BEYEZIDI LETTER PEYEZIDI LET" +
"TER PHEYEZIDI LETTER THEYEZIDI LETTER SEYEZIDI LETTER CIMYEZIDI LETTER C" +
"HIMYEZIDI LETTER CHHIMYEZIDI LETTER HHAYEZIDI LETTER XAYEZIDI LETTER DAL" +
"YEZIDI LETTER ZALYEZIDI LETTER RAYEZIDI LETTER RHAYEZIDI LETTER ZAYEZIDI" +
" LETTER JAYEZIDI LETTER SINYEZIDI LETTER SHINYEZIDI LETTER SADYEZIDI LET") + ("" +
"TER DADYEZIDI LETTER TAYEZIDI LETTER ZEYEZIDI LETTER EYNYEZIDI LETTER XH" +
"EYNYEZIDI LETTER FAYEZIDI LETTER VAYEZIDI LETTER VA ALTERNATE FORMYEZIDI" +
" LETTER QAFYEZIDI LETTER KAFYEZIDI LETTER KHAFYEZIDI LETTER GAFYEZIDI LE" +
"TTER LAMYEZIDI LETTER MIMYEZIDI LETTER NUNYEZIDI LETTER UMYEZIDI LETTER " +
"WAWYEZIDI LETTER OWYEZIDI LETTER EWYEZIDI LETTER HAYYEZIDI LETTER YOTYEZ" +
"IDI LETTER ETYEZIDI COMBINING HAMZA MARKYEZIDI COMBINING MADDA MARKYEZID" +
"I HYPHENATION MARKYEZIDI LETTER LAM WITH DOT ABOVEYEZIDI LETTER YOT WITH" +
" CIRCUMFLEX ABOVEARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOWARABIC " +
"LETTER TAH WITH TWO DOTS VERTICALLY BELOWARABIC LETTER KAF WITH TWO DOTS" +
" VERTICALLY BELOWARABIC SMALL YEH BARREE WITH TWO DOTS BELOWARABIC LETTE" +
"R THIN NOONARABIC LETTER YEH WITH FOUR DOTS BELOWARABIC BIBLICAL END OF " +
"VERSEARABIC LIGATURE ALAYHAA AS-SALAATU WAS-SALAAMARABIC LIGATURE ALAYHI" +
"M AS-SALAATU WAS-SALAAMARABIC LIGATURE ALAYHIMAA AS-SALAATU WAS-SALAAMAR" +
"ABIC LIGATURE QADDASA ALLAAHU SIRRAHARABIC LIGATURE QUDDISA SIRRUHUMARAB" +
"IC LIGATURE QUDDISA SIRRUHUMAAARABIC LIGATURE QUDDISAT ASRAARUHUMARABIC " +
"LIGATURE NAWWARA ALLAAHU MARQADAHARABIC DOUBLE VERTICAL BAR BELOWARABIC " +
"SMALL LOW NOONARABIC COMBINING ALEF OVERLAYARABIC SMALL LOW WORD SAKTAAR" +
"ABIC SMALL LOW WORD QASRARABIC SMALL LOW WORD MADDAOLD SOGDIAN LETTER AL" +
"EPHOLD SOGDIAN LETTER FINAL ALEPHOLD SOGDIAN LETTER BETHOLD SOGDIAN LETT" +
"ER FINAL BETHOLD SOGDIAN LETTER GIMELOLD SOGDIAN LETTER HEOLD SOGDIAN LE" +
"TTER FINAL HEOLD SOGDIAN LETTER WAWOLD SOGDIAN LETTER ZAYINOLD SOGDIAN L" +
"ETTER HETHOLD SOGDIAN LETTER YODHOLD SOGDIAN LETTER KAPHOLD SOGDIAN LETT" +
"ER LAMEDHOLD SOGDIAN LETTER MEMOLD SOGDIAN LETTER NUNOLD SOGDIAN LETTER " +
"FINAL NUNOLD SOGDIAN LETTER FINAL NUN WITH VERTICAL TAILOLD SOGDIAN LETT" +
"ER SAMEKHOLD SOGDIAN LETTER AYINOLD SOGDIAN LETTER ALTERNATE AYINOLD SOG" +
"DIAN LETTER PEOLD SOGDIAN LETTER SADHEOLD SOGDIAN LETTER FINAL SADHEOLD " +
"SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAILOLD SOGDIAN LETTER RESH-AYI" +
"N-DALETHOLD SOGDIAN LETTER SHINOLD SOGDIAN LETTER TAWOLD SOGDIAN LETTER " +
"FINAL TAWOLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAILOLD SOGDIAN NUMB" +
"ER ONEOLD SOGDIAN NUMBER TWOOLD SOGDIAN NUMBER THREEOLD SOGDIAN NUMBER F" +
"OUROLD SOGDIAN NUMBER FIVEOLD SOGDIAN NUMBER TENOLD SOGDIAN NUMBER TWENT" +
"YOLD SOGDIAN NUMBER THIRTYOLD SOGDIAN NUMBER ONE HUNDREDOLD SOGDIAN FRAC" +
"TION ONE HALFOLD SOGDIAN LIGATURE AYIN-DALETHSOGDIAN LETTER ALEPHSOGDIAN" +
" LETTER BETHSOGDIAN LETTER GIMELSOGDIAN LETTER HESOGDIAN LETTER WAWSOGDI" +
"AN LETTER ZAYINSOGDIAN LETTER HETHSOGDIAN LETTER YODHSOGDIAN LETTER KAPH" +
"SOGDIAN LETTER LAMEDHSOGDIAN LETTER MEMSOGDIAN LETTER NUNSOGDIAN LETTER " +
"SAMEKHSOGDIAN LETTER AYINSOGDIAN LETTER PESOGDIAN LETTER SADHESOGDIAN LE" +
"TTER RESH-AYINSOGDIAN LETTER SHINSOGDIAN LETTER TAWSOGDIAN LETTER FETHSO" +
"GDIAN LETTER LESHSOGDIAN INDEPENDENT SHINSOGDIAN COMBINING DOT BELOWSOGD" +
"IAN COMBINING TWO DOTS BELOWSOGDIAN COMBINING DOT ABOVESOGDIAN COMBINING" +
" TWO DOTS ABOVESOGDIAN COMBINING CURVE ABOVESOGDIAN COMBINING CURVE BELO" +
"WSOGDIAN COMBINING HOOK ABOVESOGDIAN COMBINING HOOK BELOWSOGDIAN COMBINI" +
"NG LONG HOOK BELOWSOGDIAN COMBINING RESH BELOWSOGDIAN COMBINING STROKE B" +
"ELOWSOGDIAN NUMBER ONESOGDIAN NUMBER TENSOGDIAN NUMBER TWENTYSOGDIAN NUM" +
"BER ONE HUNDREDSOGDIAN PUNCTUATION TWO VERTICAL BARSSOGDIAN PUNCTUATION " +
"TWO VERTICAL BARS WITH DOTSSOGDIAN PUNCTUATION CIRCLE WITH DOTSOGDIAN PU" +
"NCTUATION TWO CIRCLES WITH DOTSSOGDIAN PUNCTUATION HALF CIRCLE WITH DOTO" +
"LD UYGHUR LETTER ALEPHOLD UYGHUR LETTER BETHOLD UYGHUR LETTER GIMEL-HETH" +
"OLD UYGHUR LETTER WAWOLD UYGHUR LETTER ZAYINOLD UYGHUR LETTER FINAL HETH" +
"OLD UYGHUR LETTER YODHOLD UYGHUR LETTER KAPHOLD UYGHUR LETTER LAMEDHOLD " +
"UYGHUR LETTER MEMOLD UYGHUR LETTER NUNOLD UYGHUR LETTER SAMEKHOLD UYGHUR" +
" LETTER PEOLD UYGHUR LETTER SADHEOLD UYGHUR LETTER RESHOLD UYGHUR LETTER" +
" SHINOLD UYGHUR LETTER TAWOLD UYGHUR LETTER LESHOLD UYGHUR COMBINING DOT" +
" ABOVEOLD UYGHUR COMBINING DOT BELOWOLD UYGHUR COMBINING TWO DOTS ABOVEO" +
"LD UYGHUR COMBINING TWO DOTS BELOWOLD UYGHUR PUNCTUATION BAROLD UYGHUR P" +
"UNCTUATION TWO BARSOLD UYGHUR PUNCTUATION TWO DOTSOLD UYGHUR PUNCTUATION" +
" FOUR DOTSCHORASMIAN LETTER ALEPHCHORASMIAN LETTER SMALL ALEPHCHORASMIAN" +
" LETTER BETHCHORASMIAN LETTER GIMELCHORASMIAN LETTER DALETHCHORASMIAN LE" +
"TTER HECHORASMIAN LETTER WAWCHORASMIAN LETTER CURLED WAWCHORASMIAN LETTE" +
"R ZAYINCHORASMIAN LETTER HETHCHORASMIAN LETTER YODHCHORASMIAN LETTER KAP" +
"HCHORASMIAN LETTER LAMEDHCHORASMIAN LETTER MEMCHORASMIAN LETTER NUNCHORA" +
"SMIAN LETTER SAMEKHCHORASMIAN LETTER AYINCHORASMIAN LETTER PECHORASMIAN " +
"LETTER RESHCHORASMIAN LETTER SHINCHORASMIAN LETTER TAWCHORASMIAN NUMBER " +
"ONECHORASMIAN NUMBER TWOCHORASMIAN NUMBER THREECHORASMIAN NUMBER FOURCHO") + ("" +
"RASMIAN NUMBER TENCHORASMIAN NUMBER TWENTYCHORASMIAN NUMBER ONE HUNDREDE" +
"LYMAIC LETTER ALEPHELYMAIC LETTER BETHELYMAIC LETTER GIMELELYMAIC LETTER" +
" DALETHELYMAIC LETTER HEELYMAIC LETTER WAWELYMAIC LETTER ZAYINELYMAIC LE" +
"TTER HETHELYMAIC LETTER TETHELYMAIC LETTER YODHELYMAIC LETTER KAPHELYMAI" +
"C LETTER LAMEDHELYMAIC LETTER MEMELYMAIC LETTER NUNELYMAIC LETTER SAMEKH" +
"ELYMAIC LETTER AYINELYMAIC LETTER PEELYMAIC LETTER SADHEELYMAIC LETTER Q" +
"OPHELYMAIC LETTER RESHELYMAIC LETTER SHINELYMAIC LETTER TAWELYMAIC LIGAT" +
"URE ZAYIN-YODHBRAHMI SIGN CANDRABINDUBRAHMI SIGN ANUSVARABRAHMI SIGN VIS" +
"ARGABRAHMI SIGN JIHVAMULIYABRAHMI SIGN UPADHMANIYABRAHMI LETTER ABRAHMI " +
"LETTER AABRAHMI LETTER IBRAHMI LETTER IIBRAHMI LETTER UBRAHMI LETTER UUB" +
"RAHMI LETTER VOCALIC RBRAHMI LETTER VOCALIC RRBRAHMI LETTER VOCALIC LBRA" +
"HMI LETTER VOCALIC LLBRAHMI LETTER EBRAHMI LETTER AIBRAHMI LETTER OBRAHM" +
"I LETTER AUBRAHMI LETTER KABRAHMI LETTER KHABRAHMI LETTER GABRAHMI LETTE" +
"R GHABRAHMI LETTER NGABRAHMI LETTER CABRAHMI LETTER CHABRAHMI LETTER JAB" +
"RAHMI LETTER JHABRAHMI LETTER NYABRAHMI LETTER TTABRAHMI LETTER TTHABRAH" +
"MI LETTER DDABRAHMI LETTER DDHABRAHMI LETTER NNABRAHMI LETTER TABRAHMI L" +
"ETTER THABRAHMI LETTER DABRAHMI LETTER DHABRAHMI LETTER NABRAHMI LETTER " +
"PABRAHMI LETTER PHABRAHMI LETTER BABRAHMI LETTER BHABRAHMI LETTER MABRAH" +
"MI LETTER YABRAHMI LETTER RABRAHMI LETTER LABRAHMI LETTER VABRAHMI LETTE" +
"R SHABRAHMI LETTER SSABRAHMI LETTER SABRAHMI LETTER HABRAHMI LETTER LLAB" +
"RAHMI LETTER OLD TAMIL LLLABRAHMI LETTER OLD TAMIL RRABRAHMI LETTER OLD " +
"TAMIL NNNABRAHMI VOWEL SIGN AABRAHMI VOWEL SIGN BHATTIPROLU AABRAHMI VOW" +
"EL SIGN IBRAHMI VOWEL SIGN IIBRAHMI VOWEL SIGN UBRAHMI VOWEL SIGN UUBRAH" +
"MI VOWEL SIGN VOCALIC RBRAHMI VOWEL SIGN VOCALIC RRBRAHMI VOWEL SIGN VOC" +
"ALIC LBRAHMI VOWEL SIGN VOCALIC LLBRAHMI VOWEL SIGN EBRAHMI VOWEL SIGN A" +
"IBRAHMI VOWEL SIGN OBRAHMI VOWEL SIGN AUBRAHMI VIRAMABRAHMI DANDABRAHMI " +
"DOUBLE DANDABRAHMI PUNCTUATION DOTBRAHMI PUNCTUATION DOUBLE DOTBRAHMI PU" +
"NCTUATION LINEBRAHMI PUNCTUATION CRESCENT BARBRAHMI PUNCTUATION LOTUSBRA" +
"HMI NUMBER ONEBRAHMI NUMBER TWOBRAHMI NUMBER THREEBRAHMI NUMBER FOURBRAH" +
"MI NUMBER FIVEBRAHMI NUMBER SIXBRAHMI NUMBER SEVENBRAHMI NUMBER EIGHTBRA" +
"HMI NUMBER NINEBRAHMI NUMBER TENBRAHMI NUMBER TWENTYBRAHMI NUMBER THIRTY" +
"BRAHMI NUMBER FORTYBRAHMI NUMBER FIFTYBRAHMI NUMBER SIXTYBRAHMI NUMBER S" +
"EVENTYBRAHMI NUMBER EIGHTYBRAHMI NUMBER NINETYBRAHMI NUMBER ONE HUNDREDB" +
"RAHMI NUMBER ONE THOUSANDBRAHMI DIGIT ZEROBRAHMI DIGIT ONEBRAHMI DIGIT T" +
"WOBRAHMI DIGIT THREEBRAHMI DIGIT FOURBRAHMI DIGIT FIVEBRAHMI DIGIT SIXBR" +
"AHMI DIGIT SEVENBRAHMI DIGIT EIGHTBRAHMI DIGIT NINEBRAHMI SIGN OLD TAMIL" +
" VIRAMABRAHMI LETTER OLD TAMIL SHORT EBRAHMI LETTER OLD TAMIL SHORT OBRA" +
"HMI VOWEL SIGN OLD TAMIL SHORT EBRAHMI VOWEL SIGN OLD TAMIL SHORT OBRAHM" +
"I LETTER OLD TAMIL LLABRAHMI NUMBER JOINERKAITHI SIGN CANDRABINDUKAITHI " +
"SIGN ANUSVARAKAITHI SIGN VISARGAKAITHI LETTER AKAITHI LETTER AAKAITHI LE" +
"TTER IKAITHI LETTER IIKAITHI LETTER UKAITHI LETTER UUKAITHI LETTER EKAIT" +
"HI LETTER AIKAITHI LETTER OKAITHI LETTER AUKAITHI LETTER KAKAITHI LETTER" +
" KHAKAITHI LETTER GAKAITHI LETTER GHAKAITHI LETTER NGAKAITHI LETTER CAKA" +
"ITHI LETTER CHAKAITHI LETTER JAKAITHI LETTER JHAKAITHI LETTER NYAKAITHI " +
"LETTER TTAKAITHI LETTER TTHAKAITHI LETTER DDAKAITHI LETTER DDDHAKAITHI L" +
"ETTER DDHAKAITHI LETTER RHAKAITHI LETTER NNAKAITHI LETTER TAKAITHI LETTE" +
"R THAKAITHI LETTER DAKAITHI LETTER DHAKAITHI LETTER NAKAITHI LETTER PAKA" +
"ITHI LETTER PHAKAITHI LETTER BAKAITHI LETTER BHAKAITHI LETTER MAKAITHI L" +
"ETTER YAKAITHI LETTER RAKAITHI LETTER LAKAITHI LETTER VAKAITHI LETTER SH" +
"AKAITHI LETTER SSAKAITHI LETTER SAKAITHI LETTER HAKAITHI VOWEL SIGN AAKA" +
"ITHI VOWEL SIGN IKAITHI VOWEL SIGN IIKAITHI VOWEL SIGN UKAITHI VOWEL SIG" +
"N UUKAITHI VOWEL SIGN EKAITHI VOWEL SIGN AIKAITHI VOWEL SIGN OKAITHI VOW" +
"EL SIGN AUKAITHI SIGN VIRAMAKAITHI SIGN NUKTAKAITHI ABBREVIATION SIGNKAI" +
"THI ENUMERATION SIGNKAITHI NUMBER SIGNKAITHI SECTION MARKKAITHI DOUBLE S" +
"ECTION MARKKAITHI DANDAKAITHI DOUBLE DANDAKAITHI VOWEL SIGN VOCALIC RKAI" +
"THI NUMBER SIGN ABOVESORA SOMPENG LETTER SAHSORA SOMPENG LETTER TAHSORA " +
"SOMPENG LETTER BAHSORA SOMPENG LETTER CAHSORA SOMPENG LETTER DAHSORA SOM" +
"PENG LETTER GAHSORA SOMPENG LETTER MAHSORA SOMPENG LETTER NGAHSORA SOMPE" +
"NG LETTER LAHSORA SOMPENG LETTER NAHSORA SOMPENG LETTER VAHSORA SOMPENG " +
"LETTER PAHSORA SOMPENG LETTER YAHSORA SOMPENG LETTER RAHSORA SOMPENG LET" +
"TER HAHSORA SOMPENG LETTER KAHSORA SOMPENG LETTER JAHSORA SOMPENG LETTER" +
" NYAHSORA SOMPENG LETTER AHSORA SOMPENG LETTER EEHSORA SOMPENG LETTER IH" +
"SORA SOMPENG LETTER UHSORA SOMPENG LETTER OHSORA SOMPENG LETTER EHSORA S" +
"OMPENG LETTER MAESORA SOMPENG DIGIT ZEROSORA SOMPENG DIGIT ONESORA SOMPE") + ("" +
"NG DIGIT TWOSORA SOMPENG DIGIT THREESORA SOMPENG DIGIT FOURSORA SOMPENG " +
"DIGIT FIVESORA SOMPENG DIGIT SIXSORA SOMPENG DIGIT SEVENSORA SOMPENG DIG" +
"IT EIGHTSORA SOMPENG DIGIT NINECHAKMA SIGN CANDRABINDUCHAKMA SIGN ANUSVA" +
"RACHAKMA SIGN VISARGACHAKMA LETTER AACHAKMA LETTER ICHAKMA LETTER UCHAKM" +
"A LETTER ECHAKMA LETTER KAACHAKMA LETTER KHAACHAKMA LETTER GAACHAKMA LET" +
"TER GHAACHAKMA LETTER NGAACHAKMA LETTER CAACHAKMA LETTER CHAACHAKMA LETT" +
"ER JAACHAKMA LETTER JHAACHAKMA LETTER NYAACHAKMA LETTER TTAACHAKMA LETTE" +
"R TTHAACHAKMA LETTER DDAACHAKMA LETTER DDHAACHAKMA LETTER NNAACHAKMA LET" +
"TER TAACHAKMA LETTER THAACHAKMA LETTER DAACHAKMA LETTER DHAACHAKMA LETTE" +
"R NAACHAKMA LETTER PAACHAKMA LETTER PHAACHAKMA LETTER BAACHAKMA LETTER B" +
"HAACHAKMA LETTER MAACHAKMA LETTER YYAACHAKMA LETTER YAACHAKMA LETTER RAA" +
"CHAKMA LETTER LAACHAKMA LETTER WAACHAKMA LETTER SAACHAKMA LETTER HAACHAK" +
"MA VOWEL SIGN ACHAKMA VOWEL SIGN ICHAKMA VOWEL SIGN IICHAKMA VOWEL SIGN " +
"UCHAKMA VOWEL SIGN UUCHAKMA VOWEL SIGN ECHAKMA VOWEL SIGN AICHAKMA VOWEL" +
" SIGN OCHAKMA VOWEL SIGN AUCHAKMA VOWEL SIGN OICHAKMA O MARKCHAKMA AU MA" +
"RKCHAKMA VIRAMACHAKMA MAAYYAACHAKMA DIGIT ZEROCHAKMA DIGIT ONECHAKMA DIG" +
"IT TWOCHAKMA DIGIT THREECHAKMA DIGIT FOURCHAKMA DIGIT FIVECHAKMA DIGIT S" +
"IXCHAKMA DIGIT SEVENCHAKMA DIGIT EIGHTCHAKMA DIGIT NINECHAKMA SECTION MA" +
"RKCHAKMA DANDACHAKMA DOUBLE DANDACHAKMA QUESTION MARKCHAKMA LETTER LHAAC" +
"HAKMA VOWEL SIGN AACHAKMA VOWEL SIGN EICHAKMA LETTER VAAMAHAJANI LETTER " +
"AMAHAJANI LETTER IMAHAJANI LETTER UMAHAJANI LETTER EMAHAJANI LETTER OMAH" +
"AJANI LETTER KAMAHAJANI LETTER KHAMAHAJANI LETTER GAMAHAJANI LETTER GHAM" +
"AHAJANI LETTER CAMAHAJANI LETTER CHAMAHAJANI LETTER JAMAHAJANI LETTER JH" +
"AMAHAJANI LETTER NYAMAHAJANI LETTER TTAMAHAJANI LETTER TTHAMAHAJANI LETT" +
"ER DDAMAHAJANI LETTER DDHAMAHAJANI LETTER NNAMAHAJANI LETTER TAMAHAJANI " +
"LETTER THAMAHAJANI LETTER DAMAHAJANI LETTER DHAMAHAJANI LETTER NAMAHAJAN" +
"I LETTER PAMAHAJANI LETTER PHAMAHAJANI LETTER BAMAHAJANI LETTER BHAMAHAJ" +
"ANI LETTER MAMAHAJANI LETTER RAMAHAJANI LETTER LAMAHAJANI LETTER VAMAHAJ" +
"ANI LETTER SAMAHAJANI LETTER HAMAHAJANI LETTER RRAMAHAJANI SIGN NUKTAMAH" +
"AJANI ABBREVIATION SIGNMAHAJANI SECTION MARKMAHAJANI LIGATURE SHRISHARAD" +
"A SIGN CANDRABINDUSHARADA SIGN ANUSVARASHARADA SIGN VISARGASHARADA LETTE" +
"R ASHARADA LETTER AASHARADA LETTER ISHARADA LETTER IISHARADA LETTER USHA" +
"RADA LETTER UUSHARADA LETTER VOCALIC RSHARADA LETTER VOCALIC RRSHARADA L" +
"ETTER VOCALIC LSHARADA LETTER VOCALIC LLSHARADA LETTER ESHARADA LETTER A" +
"ISHARADA LETTER OSHARADA LETTER AUSHARADA LETTER KASHARADA LETTER KHASHA" +
"RADA LETTER GASHARADA LETTER GHASHARADA LETTER NGASHARADA LETTER CASHARA" +
"DA LETTER CHASHARADA LETTER JASHARADA LETTER JHASHARADA LETTER NYASHARAD" +
"A LETTER TTASHARADA LETTER TTHASHARADA LETTER DDASHARADA LETTER DDHASHAR" +
"ADA LETTER NNASHARADA LETTER TASHARADA LETTER THASHARADA LETTER DASHARAD" +
"A LETTER DHASHARADA LETTER NASHARADA LETTER PASHARADA LETTER PHASHARADA " +
"LETTER BASHARADA LETTER BHASHARADA LETTER MASHARADA LETTER YASHARADA LET" +
"TER RASHARADA LETTER LASHARADA LETTER LLASHARADA LETTER VASHARADA LETTER" +
" SHASHARADA LETTER SSASHARADA LETTER SASHARADA LETTER HASHARADA VOWEL SI" +
"GN AASHARADA VOWEL SIGN ISHARADA VOWEL SIGN IISHARADA VOWEL SIGN USHARAD" +
"A VOWEL SIGN UUSHARADA VOWEL SIGN VOCALIC RSHARADA VOWEL SIGN VOCALIC RR" +
"SHARADA VOWEL SIGN VOCALIC LSHARADA VOWEL SIGN VOCALIC LLSHARADA VOWEL S" +
"IGN ESHARADA VOWEL SIGN AISHARADA VOWEL SIGN OSHARADA VOWEL SIGN AUSHARA" +
"DA SIGN VIRAMASHARADA SIGN AVAGRAHASHARADA SIGN JIHVAMULIYASHARADA SIGN " +
"UPADHMANIYASHARADA OMSHARADA DANDASHARADA DOUBLE DANDASHARADA ABBREVIATI" +
"ON SIGNSHARADA SEPARATORSHARADA SANDHI MARKSHARADA SIGN NUKTASHARADA VOW" +
"EL MODIFIER MARKSHARADA EXTRA SHORT VOWEL MARKSHARADA SUTRA MARKSHARADA " +
"VOWEL SIGN PRISHTHAMATRA ESHARADA SIGN INVERTED CANDRABINDUSHARADA DIGIT" +
" ZEROSHARADA DIGIT ONESHARADA DIGIT TWOSHARADA DIGIT THREESHARADA DIGIT " +
"FOURSHARADA DIGIT FIVESHARADA DIGIT SIXSHARADA DIGIT SEVENSHARADA DIGIT " +
"EIGHTSHARADA DIGIT NINESHARADA EKAMSHARADA SIGN SIDDHAMSHARADA HEADSTROK" +
"ESHARADA CONTINUATION SIGNSHARADA SECTION MARK-1SHARADA SECTION MARK-2SI" +
"NHALA ARCHAIC DIGIT ONESINHALA ARCHAIC DIGIT TWOSINHALA ARCHAIC DIGIT TH" +
"REESINHALA ARCHAIC DIGIT FOURSINHALA ARCHAIC DIGIT FIVESINHALA ARCHAIC D" +
"IGIT SIXSINHALA ARCHAIC DIGIT SEVENSINHALA ARCHAIC DIGIT EIGHTSINHALA AR" +
"CHAIC DIGIT NINESINHALA ARCHAIC NUMBER TENSINHALA ARCHAIC NUMBER TWENTYS" +
"INHALA ARCHAIC NUMBER THIRTYSINHALA ARCHAIC NUMBER FORTYSINHALA ARCHAIC " +
"NUMBER FIFTYSINHALA ARCHAIC NUMBER SIXTYSINHALA ARCHAIC NUMBER SEVENTYSI" +
"NHALA ARCHAIC NUMBER EIGHTYSINHALA ARCHAIC NUMBER NINETYSINHALA ARCHAIC " +
"NUMBER ONE HUNDREDSINHALA ARCHAIC NUMBER ONE THOUSANDKHOJKI LETTER AKHOJ") + ("" +
"KI LETTER AAKHOJKI LETTER IKHOJKI LETTER UKHOJKI LETTER EKHOJKI LETTER A" +
"IKHOJKI LETTER OKHOJKI LETTER AUKHOJKI LETTER KAKHOJKI LETTER KHAKHOJKI " +
"LETTER GAKHOJKI LETTER GGAKHOJKI LETTER GHAKHOJKI LETTER NGAKHOJKI LETTE" +
"R CAKHOJKI LETTER CHAKHOJKI LETTER JAKHOJKI LETTER JJAKHOJKI LETTER NYAK" +
"HOJKI LETTER TTAKHOJKI LETTER TTHAKHOJKI LETTER DDAKHOJKI LETTER DDHAKHO" +
"JKI LETTER NNAKHOJKI LETTER TAKHOJKI LETTER THAKHOJKI LETTER DAKHOJKI LE" +
"TTER DDDAKHOJKI LETTER DHAKHOJKI LETTER NAKHOJKI LETTER PAKHOJKI LETTER " +
"PHAKHOJKI LETTER BAKHOJKI LETTER BBAKHOJKI LETTER BHAKHOJKI LETTER MAKHO" +
"JKI LETTER YAKHOJKI LETTER RAKHOJKI LETTER LAKHOJKI LETTER VAKHOJKI LETT" +
"ER SAKHOJKI LETTER HAKHOJKI LETTER LLAKHOJKI VOWEL SIGN AAKHOJKI VOWEL S" +
"IGN IKHOJKI VOWEL SIGN IIKHOJKI VOWEL SIGN UKHOJKI VOWEL SIGN EKHOJKI VO" +
"WEL SIGN AIKHOJKI VOWEL SIGN OKHOJKI VOWEL SIGN AUKHOJKI SIGN ANUSVARAKH" +
"OJKI SIGN VIRAMAKHOJKI SIGN NUKTAKHOJKI SIGN SHADDAKHOJKI DANDAKHOJKI DO" +
"UBLE DANDAKHOJKI WORD SEPARATORKHOJKI SECTION MARKKHOJKI DOUBLE SECTION " +
"MARKKHOJKI ABBREVIATION SIGNKHOJKI SIGN SUKUNKHOJKI LETTER QAKHOJKI LETT" +
"ER SHORT IKHOJKI VOWEL SIGN VOCALIC RMULTANI LETTER AMULTANI LETTER IMUL" +
"TANI LETTER UMULTANI LETTER EMULTANI LETTER KAMULTANI LETTER KHAMULTANI " +
"LETTER GAMULTANI LETTER GHAMULTANI LETTER CAMULTANI LETTER CHAMULTANI LE" +
"TTER JAMULTANI LETTER JJAMULTANI LETTER NYAMULTANI LETTER TTAMULTANI LET" +
"TER TTHAMULTANI LETTER DDAMULTANI LETTER DDDAMULTANI LETTER DDHAMULTANI " +
"LETTER NNAMULTANI LETTER TAMULTANI LETTER THAMULTANI LETTER DAMULTANI LE" +
"TTER DHAMULTANI LETTER NAMULTANI LETTER PAMULTANI LETTER PHAMULTANI LETT" +
"ER BAMULTANI LETTER BHAMULTANI LETTER MAMULTANI LETTER YAMULTANI LETTER " +
"RAMULTANI LETTER LAMULTANI LETTER VAMULTANI LETTER SAMULTANI LETTER HAMU" +
"LTANI LETTER RRAMULTANI LETTER RHAMULTANI SECTION MARKKHUDAWADI LETTER A" +
"KHUDAWADI LETTER AAKHUDAWADI LETTER IKHUDAWADI LETTER IIKHUDAWADI LETTER" +
" UKHUDAWADI LETTER UUKHUDAWADI LETTER EKHUDAWADI LETTER AIKHUDAWADI LETT" +
"ER OKHUDAWADI LETTER AUKHUDAWADI LETTER KAKHUDAWADI LETTER KHAKHUDAWADI " +
"LETTER GAKHUDAWADI LETTER GGAKHUDAWADI LETTER GHAKHUDAWADI LETTER NGAKHU" +
"DAWADI LETTER CAKHUDAWADI LETTER CHAKHUDAWADI LETTER JAKHUDAWADI LETTER " +
"JJAKHUDAWADI LETTER JHAKHUDAWADI LETTER NYAKHUDAWADI LETTER TTAKHUDAWADI" +
" LETTER TTHAKHUDAWADI LETTER DDAKHUDAWADI LETTER DDDAKHUDAWADI LETTER RR" +
"AKHUDAWADI LETTER DDHAKHUDAWADI LETTER NNAKHUDAWADI LETTER TAKHUDAWADI L" +
"ETTER THAKHUDAWADI LETTER DAKHUDAWADI LETTER DHAKHUDAWADI LETTER NAKHUDA" +
"WADI LETTER PAKHUDAWADI LETTER PHAKHUDAWADI LETTER BAKHUDAWADI LETTER BB" +
"AKHUDAWADI LETTER BHAKHUDAWADI LETTER MAKHUDAWADI LETTER YAKHUDAWADI LET" +
"TER RAKHUDAWADI LETTER LAKHUDAWADI LETTER VAKHUDAWADI LETTER SHAKHUDAWAD" +
"I LETTER SAKHUDAWADI LETTER HAKHUDAWADI SIGN ANUSVARAKHUDAWADI VOWEL SIG" +
"N AAKHUDAWADI VOWEL SIGN IKHUDAWADI VOWEL SIGN IIKHUDAWADI VOWEL SIGN UK" +
"HUDAWADI VOWEL SIGN UUKHUDAWADI VOWEL SIGN EKHUDAWADI VOWEL SIGN AIKHUDA" +
"WADI VOWEL SIGN OKHUDAWADI VOWEL SIGN AUKHUDAWADI SIGN NUKTAKHUDAWADI SI" +
"GN VIRAMAKHUDAWADI DIGIT ZEROKHUDAWADI DIGIT ONEKHUDAWADI DIGIT TWOKHUDA" +
"WADI DIGIT THREEKHUDAWADI DIGIT FOURKHUDAWADI DIGIT FIVEKHUDAWADI DIGIT " +
"SIXKHUDAWADI DIGIT SEVENKHUDAWADI DIGIT EIGHTKHUDAWADI DIGIT NINEGRANTHA" +
" SIGN COMBINING ANUSVARA ABOVEGRANTHA SIGN CANDRABINDUGRANTHA SIGN ANUSV" +
"ARAGRANTHA SIGN VISARGAGRANTHA LETTER AGRANTHA LETTER AAGRANTHA LETTER I" +
"GRANTHA LETTER IIGRANTHA LETTER UGRANTHA LETTER UUGRANTHA LETTER VOCALIC" +
" RGRANTHA LETTER VOCALIC LGRANTHA LETTER EEGRANTHA LETTER AIGRANTHA LETT" +
"ER OOGRANTHA LETTER AUGRANTHA LETTER KAGRANTHA LETTER KHAGRANTHA LETTER " +
"GAGRANTHA LETTER GHAGRANTHA LETTER NGAGRANTHA LETTER CAGRANTHA LETTER CH" +
"AGRANTHA LETTER JAGRANTHA LETTER JHAGRANTHA LETTER NYAGRANTHA LETTER TTA" +
"GRANTHA LETTER TTHAGRANTHA LETTER DDAGRANTHA LETTER DDHAGRANTHA LETTER N" +
"NAGRANTHA LETTER TAGRANTHA LETTER THAGRANTHA LETTER DAGRANTHA LETTER DHA" +
"GRANTHA LETTER NAGRANTHA LETTER PAGRANTHA LETTER PHAGRANTHA LETTER BAGRA" +
"NTHA LETTER BHAGRANTHA LETTER MAGRANTHA LETTER YAGRANTHA LETTER RAGRANTH" +
"A LETTER LAGRANTHA LETTER LLAGRANTHA LETTER VAGRANTHA LETTER SHAGRANTHA " +
"LETTER SSAGRANTHA LETTER SAGRANTHA LETTER HACOMBINING BINDU BELOWGRANTHA" +
" SIGN NUKTAGRANTHA SIGN AVAGRAHAGRANTHA VOWEL SIGN AAGRANTHA VOWEL SIGN " +
"IGRANTHA VOWEL SIGN IIGRANTHA VOWEL SIGN UGRANTHA VOWEL SIGN UUGRANTHA V" +
"OWEL SIGN VOCALIC RGRANTHA VOWEL SIGN VOCALIC RRGRANTHA VOWEL SIGN EEGRA" +
"NTHA VOWEL SIGN AIGRANTHA VOWEL SIGN OOGRANTHA VOWEL SIGN AUGRANTHA SIGN" +
" VIRAMAGRANTHA OMGRANTHA AU LENGTH MARKGRANTHA SIGN PLUTAGRANTHA LETTER " +
"VEDIC ANUSVARAGRANTHA LETTER VEDIC DOUBLE ANUSVARAGRANTHA LETTER VOCALIC" +
" RRGRANTHA LETTER VOCALIC LLGRANTHA VOWEL SIGN VOCALIC LGRANTHA VOWEL SI") + ("" +
"GN VOCALIC LLCOMBINING GRANTHA DIGIT ZEROCOMBINING GRANTHA DIGIT ONECOMB" +
"INING GRANTHA DIGIT TWOCOMBINING GRANTHA DIGIT THREECOMBINING GRANTHA DI" +
"GIT FOURCOMBINING GRANTHA DIGIT FIVECOMBINING GRANTHA DIGIT SIXCOMBINING" +
" GRANTHA LETTER ACOMBINING GRANTHA LETTER KACOMBINING GRANTHA LETTER NAC" +
"OMBINING GRANTHA LETTER VICOMBINING GRANTHA LETTER PATULU-TIGALARI LETTE" +
"R ATULU-TIGALARI LETTER AATULU-TIGALARI LETTER ITULU-TIGALARI LETTER IIT" +
"ULU-TIGALARI LETTER UTULU-TIGALARI LETTER UUTULU-TIGALARI LETTER VOCALIC" +
" RTULU-TIGALARI LETTER VOCALIC RRTULU-TIGALARI LETTER VOCALIC LTULU-TIGA" +
"LARI LETTER VOCALIC LLTULU-TIGALARI LETTER EETULU-TIGALARI LETTER AITULU" +
"-TIGALARI LETTER OOTULU-TIGALARI LETTER AUTULU-TIGALARI LETTER KATULU-TI" +
"GALARI LETTER KHATULU-TIGALARI LETTER GATULU-TIGALARI LETTER GHATULU-TIG" +
"ALARI LETTER NGATULU-TIGALARI LETTER CATULU-TIGALARI LETTER CHATULU-TIGA" +
"LARI LETTER JATULU-TIGALARI LETTER JHATULU-TIGALARI LETTER NYATULU-TIGAL" +
"ARI LETTER TTATULU-TIGALARI LETTER TTHATULU-TIGALARI LETTER DDATULU-TIGA" +
"LARI LETTER DDHATULU-TIGALARI LETTER NNATULU-TIGALARI LETTER TATULU-TIGA" +
"LARI LETTER THATULU-TIGALARI LETTER DATULU-TIGALARI LETTER DHATULU-TIGAL" +
"ARI LETTER NATULU-TIGALARI LETTER PATULU-TIGALARI LETTER PHATULU-TIGALAR" +
"I LETTER BATULU-TIGALARI LETTER BHATULU-TIGALARI LETTER MATULU-TIGALARI " +
"LETTER YATULU-TIGALARI LETTER RATULU-TIGALARI LETTER LATULU-TIGALARI LET" +
"TER VATULU-TIGALARI LETTER SHATULU-TIGALARI LETTER SSATULU-TIGALARI LETT" +
"ER SATULU-TIGALARI LETTER HATULU-TIGALARI LETTER LLATULU-TIGALARI LETTER" +
" RRATULU-TIGALARI LETTER LLLATULU-TIGALARI SIGN AVAGRAHATULU-TIGALARI VO" +
"WEL SIGN AATULU-TIGALARI VOWEL SIGN ITULU-TIGALARI VOWEL SIGN IITULU-TIG" +
"ALARI VOWEL SIGN UTULU-TIGALARI VOWEL SIGN UUTULU-TIGALARI VOWEL SIGN VO" +
"CALIC RTULU-TIGALARI VOWEL SIGN VOCALIC RRTULU-TIGALARI VOWEL SIGN VOCAL" +
"IC LTULU-TIGALARI VOWEL SIGN VOCALIC LLTULU-TIGALARI VOWEL SIGN EETULU-T" +
"IGALARI VOWEL SIGN AITULU-TIGALARI VOWEL SIGN OOTULU-TIGALARI VOWEL SIGN" +
" AUTULU-TIGALARI AU LENGTH MARKTULU-TIGALARI SIGN CANDRA ANUNASIKATULU-T" +
"IGALARI SIGN ANUSVARATULU-TIGALARI SIGN VISARGATULU-TIGALARI SIGN VIRAMA" +
"TULU-TIGALARI SIGN LOOPED VIRAMATULU-TIGALARI CONJOINERTULU-TIGALARI REP" +
"HATULU-TIGALARI GEMINATION MARKTULU-TIGALARI SIGN PLUTATULU-TIGALARI DAN" +
"DATULU-TIGALARI DOUBLE DANDATULU-TIGALARI SIGN OM PUSHPIKATULU-TIGALARI " +
"SIGN SHRII PUSHPIKATULU-TIGALARI VEDIC TONE SVARITATULU-TIGALARI VEDIC T" +
"ONE ANUDATTANEWA LETTER ANEWA LETTER AANEWA LETTER INEWA LETTER IINEWA L" +
"ETTER UNEWA LETTER UUNEWA LETTER VOCALIC RNEWA LETTER VOCALIC RRNEWA LET" +
"TER VOCALIC LNEWA LETTER VOCALIC LLNEWA LETTER ENEWA LETTER AINEWA LETTE" +
"R ONEWA LETTER AUNEWA LETTER KANEWA LETTER KHANEWA LETTER GANEWA LETTER " +
"GHANEWA LETTER NGANEWA LETTER NGHANEWA LETTER CANEWA LETTER CHANEWA LETT" +
"ER JANEWA LETTER JHANEWA LETTER NYANEWA LETTER NYHANEWA LETTER TTANEWA L" +
"ETTER TTHANEWA LETTER DDANEWA LETTER DDHANEWA LETTER NNANEWA LETTER TANE" +
"WA LETTER THANEWA LETTER DANEWA LETTER DHANEWA LETTER NANEWA LETTER NHAN" +
"EWA LETTER PANEWA LETTER PHANEWA LETTER BANEWA LETTER BHANEWA LETTER MAN" +
"EWA LETTER MHANEWA LETTER YANEWA LETTER RANEWA LETTER RHANEWA LETTER LAN" +
"EWA LETTER LHANEWA LETTER WANEWA LETTER SHANEWA LETTER SSANEWA LETTER SA" +
"NEWA LETTER HANEWA VOWEL SIGN AANEWA VOWEL SIGN INEWA VOWEL SIGN IINEWA " +
"VOWEL SIGN UNEWA VOWEL SIGN UUNEWA VOWEL SIGN VOCALIC RNEWA VOWEL SIGN V" +
"OCALIC RRNEWA VOWEL SIGN VOCALIC LNEWA VOWEL SIGN VOCALIC LLNEWA VOWEL S" +
"IGN ENEWA VOWEL SIGN AINEWA VOWEL SIGN ONEWA VOWEL SIGN AUNEWA SIGN VIRA" +
"MANEWA SIGN CANDRABINDUNEWA SIGN ANUSVARANEWA SIGN VISARGANEWA SIGN NUKT" +
"ANEWA SIGN AVAGRAHANEWA SIGN FINAL ANUSVARANEWA OMNEWA SIDDHINEWA DANDAN" +
"EWA DOUBLE DANDANEWA COMMANEWA GAP FILLERNEWA ABBREVIATION SIGNNEWA DIGI" +
"T ZERONEWA DIGIT ONENEWA DIGIT TWONEWA DIGIT THREENEWA DIGIT FOURNEWA DI" +
"GIT FIVENEWA DIGIT SIXNEWA DIGIT SEVENNEWA DIGIT EIGHTNEWA DIGIT NINENEW" +
"A DOUBLE COMMANEWA PLACEHOLDER MARKNEWA INSERTION SIGNNEWA SANDHI MARKNE" +
"WA LETTER VEDIC ANUSVARANEWA SIGN JIHVAMULIYANEWA SIGN UPADHMANIYATIRHUT" +
"A ANJITIRHUTA LETTER ATIRHUTA LETTER AATIRHUTA LETTER ITIRHUTA LETTER II" +
"TIRHUTA LETTER UTIRHUTA LETTER UUTIRHUTA LETTER VOCALIC RTIRHUTA LETTER " +
"VOCALIC RRTIRHUTA LETTER VOCALIC LTIRHUTA LETTER VOCALIC LLTIRHUTA LETTE" +
"R ETIRHUTA LETTER AITIRHUTA LETTER OTIRHUTA LETTER AUTIRHUTA LETTER KATI" +
"RHUTA LETTER KHATIRHUTA LETTER GATIRHUTA LETTER GHATIRHUTA LETTER NGATIR" +
"HUTA LETTER CATIRHUTA LETTER CHATIRHUTA LETTER JATIRHUTA LETTER JHATIRHU" +
"TA LETTER NYATIRHUTA LETTER TTATIRHUTA LETTER TTHATIRHUTA LETTER DDATIRH" +
"UTA LETTER DDHATIRHUTA LETTER NNATIRHUTA LETTER TATIRHUTA LETTER THATIRH" +
"UTA LETTER DATIRHUTA LETTER DHATIRHUTA LETTER NATIRHUTA LETTER PATIRHUTA") + ("" +
" LETTER PHATIRHUTA LETTER BATIRHUTA LETTER BHATIRHUTA LETTER MATIRHUTA L" +
"ETTER YATIRHUTA LETTER RATIRHUTA LETTER LATIRHUTA LETTER VATIRHUTA LETTE" +
"R SHATIRHUTA LETTER SSATIRHUTA LETTER SATIRHUTA LETTER HATIRHUTA VOWEL S" +
"IGN AATIRHUTA VOWEL SIGN ITIRHUTA VOWEL SIGN IITIRHUTA VOWEL SIGN UTIRHU" +
"TA VOWEL SIGN UUTIRHUTA VOWEL SIGN VOCALIC RTIRHUTA VOWEL SIGN VOCALIC R" +
"RTIRHUTA VOWEL SIGN VOCALIC LTIRHUTA VOWEL SIGN VOCALIC LLTIRHUTA VOWEL " +
"SIGN ETIRHUTA VOWEL SIGN SHORT ETIRHUTA VOWEL SIGN AITIRHUTA VOWEL SIGN " +
"OTIRHUTA VOWEL SIGN SHORT OTIRHUTA VOWEL SIGN AUTIRHUTA SIGN CANDRABINDU" +
"TIRHUTA SIGN ANUSVARATIRHUTA SIGN VISARGATIRHUTA SIGN VIRAMATIRHUTA SIGN" +
" NUKTATIRHUTA SIGN AVAGRAHATIRHUTA GVANGTIRHUTA ABBREVIATION SIGNTIRHUTA" +
" OMTIRHUTA DIGIT ZEROTIRHUTA DIGIT ONETIRHUTA DIGIT TWOTIRHUTA DIGIT THR" +
"EETIRHUTA DIGIT FOURTIRHUTA DIGIT FIVETIRHUTA DIGIT SIXTIRHUTA DIGIT SEV" +
"ENTIRHUTA DIGIT EIGHTTIRHUTA DIGIT NINESIDDHAM LETTER ASIDDHAM LETTER AA" +
"SIDDHAM LETTER ISIDDHAM LETTER IISIDDHAM LETTER USIDDHAM LETTER UUSIDDHA" +
"M LETTER VOCALIC RSIDDHAM LETTER VOCALIC RRSIDDHAM LETTER VOCALIC LSIDDH" +
"AM LETTER VOCALIC LLSIDDHAM LETTER ESIDDHAM LETTER AISIDDHAM LETTER OSID" +
"DHAM LETTER AUSIDDHAM LETTER KASIDDHAM LETTER KHASIDDHAM LETTER GASIDDHA" +
"M LETTER GHASIDDHAM LETTER NGASIDDHAM LETTER CASIDDHAM LETTER CHASIDDHAM" +
" LETTER JASIDDHAM LETTER JHASIDDHAM LETTER NYASIDDHAM LETTER TTASIDDHAM " +
"LETTER TTHASIDDHAM LETTER DDASIDDHAM LETTER DDHASIDDHAM LETTER NNASIDDHA" +
"M LETTER TASIDDHAM LETTER THASIDDHAM LETTER DASIDDHAM LETTER DHASIDDHAM " +
"LETTER NASIDDHAM LETTER PASIDDHAM LETTER PHASIDDHAM LETTER BASIDDHAM LET" +
"TER BHASIDDHAM LETTER MASIDDHAM LETTER YASIDDHAM LETTER RASIDDHAM LETTER" +
" LASIDDHAM LETTER VASIDDHAM LETTER SHASIDDHAM LETTER SSASIDDHAM LETTER S" +
"ASIDDHAM LETTER HASIDDHAM VOWEL SIGN AASIDDHAM VOWEL SIGN ISIDDHAM VOWEL" +
" SIGN IISIDDHAM VOWEL SIGN USIDDHAM VOWEL SIGN UUSIDDHAM VOWEL SIGN VOCA" +
"LIC RSIDDHAM VOWEL SIGN VOCALIC RRSIDDHAM VOWEL SIGN ESIDDHAM VOWEL SIGN" +
" AISIDDHAM VOWEL SIGN OSIDDHAM VOWEL SIGN AUSIDDHAM SIGN CANDRABINDUSIDD" +
"HAM SIGN ANUSVARASIDDHAM SIGN VISARGASIDDHAM SIGN VIRAMASIDDHAM SIGN NUK" +
"TASIDDHAM SIGN SIDDHAMSIDDHAM DANDASIDDHAM DOUBLE DANDASIDDHAM SEPARATOR" +
" DOTSIDDHAM SEPARATOR BARSIDDHAM REPETITION MARK-1SIDDHAM REPETITION MAR" +
"K-2SIDDHAM REPETITION MARK-3SIDDHAM END OF TEXT MARKSIDDHAM SECTION MARK" +
" WITH TRIDENT AND U-SHAPED ORNAMENTSSIDDHAM SECTION MARK WITH TRIDENT AN" +
"D DOTTED CRESCENTSSIDDHAM SECTION MARK WITH RAYS AND DOTTED CRESCENTSSID" +
"DHAM SECTION MARK WITH RAYS AND DOTTED DOUBLE CRESCENTSSIDDHAM SECTION M" +
"ARK WITH RAYS AND DOTTED TRIPLE CRESCENTSSIDDHAM SECTION MARK DOUBLE RIN" +
"GSIDDHAM SECTION MARK DOUBLE RING WITH RAYSSIDDHAM SECTION MARK WITH DOU" +
"BLE CRESCENTSSIDDHAM SECTION MARK WITH TRIPLE CRESCENTSSIDDHAM SECTION M" +
"ARK WITH QUADRUPLE CRESCENTSSIDDHAM SECTION MARK WITH SEPTUPLE CRESCENTS" +
"SIDDHAM SECTION MARK WITH CIRCLES AND RAYSSIDDHAM SECTION MARK WITH CIRC" +
"LES AND TWO ENCLOSURESSIDDHAM SECTION MARK WITH CIRCLES AND FOUR ENCLOSU" +
"RESSIDDHAM LETTER THREE-CIRCLE ALTERNATE ISIDDHAM LETTER TWO-CIRCLE ALTE" +
"RNATE ISIDDHAM LETTER TWO-CIRCLE ALTERNATE IISIDDHAM LETTER ALTERNATE US" +
"IDDHAM VOWEL SIGN ALTERNATE USIDDHAM VOWEL SIGN ALTERNATE UUMODI LETTER " +
"AMODI LETTER AAMODI LETTER IMODI LETTER IIMODI LETTER UMODI LETTER UUMOD" +
"I LETTER VOCALIC RMODI LETTER VOCALIC RRMODI LETTER VOCALIC LMODI LETTER" +
" VOCALIC LLMODI LETTER EMODI LETTER AIMODI LETTER OMODI LETTER AUMODI LE" +
"TTER KAMODI LETTER KHAMODI LETTER GAMODI LETTER GHAMODI LETTER NGAMODI L" +
"ETTER CAMODI LETTER CHAMODI LETTER JAMODI LETTER JHAMODI LETTER NYAMODI " +
"LETTER TTAMODI LETTER TTHAMODI LETTER DDAMODI LETTER DDHAMODI LETTER NNA" +
"MODI LETTER TAMODI LETTER THAMODI LETTER DAMODI LETTER DHAMODI LETTER NA" +
"MODI LETTER PAMODI LETTER PHAMODI LETTER BAMODI LETTER BHAMODI LETTER MA" +
"MODI LETTER YAMODI LETTER RAMODI LETTER LAMODI LETTER VAMODI LETTER SHAM" +
"ODI LETTER SSAMODI LETTER SAMODI LETTER HAMODI LETTER LLAMODI VOWEL SIGN" +
" AAMODI VOWEL SIGN IMODI VOWEL SIGN IIMODI VOWEL SIGN UMODI VOWEL SIGN U" +
"UMODI VOWEL SIGN VOCALIC RMODI VOWEL SIGN VOCALIC RRMODI VOWEL SIGN VOCA" +
"LIC LMODI VOWEL SIGN VOCALIC LLMODI VOWEL SIGN EMODI VOWEL SIGN AIMODI V" +
"OWEL SIGN OMODI VOWEL SIGN AUMODI SIGN ANUSVARAMODI SIGN VISARGAMODI SIG" +
"N VIRAMAMODI SIGN ARDHACANDRAMODI DANDAMODI DOUBLE DANDAMODI ABBREVIATIO" +
"N SIGNMODI SIGN HUVAMODI DIGIT ZEROMODI DIGIT ONEMODI DIGIT TWOMODI DIGI" +
"T THREEMODI DIGIT FOURMODI DIGIT FIVEMODI DIGIT SIXMODI DIGIT SEVENMODI " +
"DIGIT EIGHTMODI DIGIT NINEMONGOLIAN BIRGA WITH ORNAMENTMONGOLIAN ROTATED" +
" BIRGAMONGOLIAN DOUBLE BIRGA WITH ORNAMENTMONGOLIAN TRIPLE BIRGA WITH OR" +
"NAMENTMONGOLIAN BIRGA WITH DOUBLE ORNAMENTMONGOLIAN ROTATED BIRGA WITH O") + ("" +
"RNAMENTMONGOLIAN ROTATED BIRGA WITH DOUBLE ORNAMENTMONGOLIAN INVERTED BI" +
"RGAMONGOLIAN INVERTED BIRGA WITH DOUBLE ORNAMENTMONGOLIAN SWIRL BIRGAMON" +
"GOLIAN SWIRL BIRGA WITH ORNAMENTMONGOLIAN SWIRL BIRGA WITH DOUBLE ORNAME" +
"NTMONGOLIAN TURNED SWIRL BIRGA WITH DOUBLE ORNAMENTTAKRI LETTER ATAKRI L" +
"ETTER AATAKRI LETTER ITAKRI LETTER IITAKRI LETTER UTAKRI LETTER UUTAKRI " +
"LETTER ETAKRI LETTER AITAKRI LETTER OTAKRI LETTER AUTAKRI LETTER KATAKRI" +
" LETTER KHATAKRI LETTER GATAKRI LETTER GHATAKRI LETTER NGATAKRI LETTER C" +
"ATAKRI LETTER CHATAKRI LETTER JATAKRI LETTER JHATAKRI LETTER NYATAKRI LE" +
"TTER TTATAKRI LETTER TTHATAKRI LETTER DDATAKRI LETTER DDHATAKRI LETTER N" +
"NATAKRI LETTER TATAKRI LETTER THATAKRI LETTER DATAKRI LETTER DHATAKRI LE" +
"TTER NATAKRI LETTER PATAKRI LETTER PHATAKRI LETTER BATAKRI LETTER BHATAK" +
"RI LETTER MATAKRI LETTER YATAKRI LETTER RATAKRI LETTER LATAKRI LETTER VA" +
"TAKRI LETTER SHATAKRI LETTER SATAKRI LETTER HATAKRI LETTER RRATAKRI SIGN" +
" ANUSVARATAKRI SIGN VISARGATAKRI VOWEL SIGN AATAKRI VOWEL SIGN ITAKRI VO" +
"WEL SIGN IITAKRI VOWEL SIGN UTAKRI VOWEL SIGN UUTAKRI VOWEL SIGN ETAKRI " +
"VOWEL SIGN AITAKRI VOWEL SIGN OTAKRI VOWEL SIGN AUTAKRI SIGN VIRAMATAKRI" +
" SIGN NUKTATAKRI LETTER ARCHAIC KHATAKRI ABBREVIATION SIGNTAKRI DIGIT ZE" +
"ROTAKRI DIGIT ONETAKRI DIGIT TWOTAKRI DIGIT THREETAKRI DIGIT FOURTAKRI D" +
"IGIT FIVETAKRI DIGIT SIXTAKRI DIGIT SEVENTAKRI DIGIT EIGHTTAKRI DIGIT NI" +
"NEMYANMAR PAO DIGIT ZEROMYANMAR PAO DIGIT ONEMYANMAR PAO DIGIT TWOMYANMA" +
"R PAO DIGIT THREEMYANMAR PAO DIGIT FOURMYANMAR PAO DIGIT FIVEMYANMAR PAO" +
" DIGIT SIXMYANMAR PAO DIGIT SEVENMYANMAR PAO DIGIT EIGHTMYANMAR PAO DIGI" +
"T NINEMYANMAR EASTERN PWO KAREN DIGIT ZEROMYANMAR EASTERN PWO KAREN DIGI" +
"T ONEMYANMAR EASTERN PWO KAREN DIGIT TWOMYANMAR EASTERN PWO KAREN DIGIT " +
"THREEMYANMAR EASTERN PWO KAREN DIGIT FOURMYANMAR EASTERN PWO KAREN DIGIT" +
" FIVEMYANMAR EASTERN PWO KAREN DIGIT SIXMYANMAR EASTERN PWO KAREN DIGIT " +
"SEVENMYANMAR EASTERN PWO KAREN DIGIT EIGHTMYANMAR EASTERN PWO KAREN DIGI" +
"T NINEAHOM LETTER KAAHOM LETTER KHAAHOM LETTER NGAAHOM LETTER NAAHOM LET" +
"TER TAAHOM LETTER ALTERNATE TAAHOM LETTER PAAHOM LETTER PHAAHOM LETTER B" +
"AAHOM LETTER MAAHOM LETTER JAAHOM LETTER CHAAHOM LETTER THAAHOM LETTER R" +
"AAHOM LETTER LAAHOM LETTER SAAHOM LETTER NYAAHOM LETTER HAAHOM LETTER AA" +
"HOM LETTER DAAHOM LETTER DHAAHOM LETTER GAAHOM LETTER ALTERNATE GAAHOM L" +
"ETTER GHAAHOM LETTER BHAAHOM LETTER JHAAHOM LETTER ALTERNATE BAAHOM CONS" +
"ONANT SIGN MEDIAL LAAHOM CONSONANT SIGN MEDIAL RAAHOM CONSONANT SIGN MED" +
"IAL LIGATING RAAHOM VOWEL SIGN AAHOM VOWEL SIGN AAAHOM VOWEL SIGN IAHOM " +
"VOWEL SIGN IIAHOM VOWEL SIGN UAHOM VOWEL SIGN UUAHOM VOWEL SIGN EAHOM VO" +
"WEL SIGN AWAHOM VOWEL SIGN OAHOM VOWEL SIGN AIAHOM VOWEL SIGN AMAHOM SIG" +
"N KILLERAHOM DIGIT ZEROAHOM DIGIT ONEAHOM DIGIT TWOAHOM DIGIT THREEAHOM " +
"DIGIT FOURAHOM DIGIT FIVEAHOM DIGIT SIXAHOM DIGIT SEVENAHOM DIGIT EIGHTA" +
"HOM DIGIT NINEAHOM NUMBER TENAHOM NUMBER TWENTYAHOM SIGN SMALL SECTIONAH" +
"OM SIGN SECTIONAHOM SIGN RULAIAHOM SYMBOL VIAHOM LETTER CAAHOM LETTER TT" +
"AAHOM LETTER TTHAAHOM LETTER DDAAHOM LETTER DDHAAHOM LETTER NNAAHOM LETT" +
"ER LLADOGRA LETTER ADOGRA LETTER AADOGRA LETTER IDOGRA LETTER IIDOGRA LE" +
"TTER UDOGRA LETTER UUDOGRA LETTER EDOGRA LETTER AIDOGRA LETTER ODOGRA LE" +
"TTER AUDOGRA LETTER KADOGRA LETTER KHADOGRA LETTER GADOGRA LETTER GHADOG" +
"RA LETTER NGADOGRA LETTER CADOGRA LETTER CHADOGRA LETTER JADOGRA LETTER " +
"JHADOGRA LETTER NYADOGRA LETTER TTADOGRA LETTER TTHADOGRA LETTER DDADOGR" +
"A LETTER DDHADOGRA LETTER NNADOGRA LETTER TADOGRA LETTER THADOGRA LETTER" +
" DADOGRA LETTER DHADOGRA LETTER NADOGRA LETTER PADOGRA LETTER PHADOGRA L" +
"ETTER BADOGRA LETTER BHADOGRA LETTER MADOGRA LETTER YADOGRA LETTER RADOG" +
"RA LETTER LADOGRA LETTER VADOGRA LETTER SHADOGRA LETTER SSADOGRA LETTER " +
"SADOGRA LETTER HADOGRA LETTER RRADOGRA VOWEL SIGN AADOGRA VOWEL SIGN IDO" +
"GRA VOWEL SIGN IIDOGRA VOWEL SIGN UDOGRA VOWEL SIGN UUDOGRA VOWEL SIGN V" +
"OCALIC RDOGRA VOWEL SIGN VOCALIC RRDOGRA VOWEL SIGN EDOGRA VOWEL SIGN AI" +
"DOGRA VOWEL SIGN ODOGRA VOWEL SIGN AUDOGRA SIGN ANUSVARADOGRA SIGN VISAR" +
"GADOGRA SIGN VIRAMADOGRA SIGN NUKTADOGRA ABBREVIATION SIGNWARANG CITI CA" +
"PITAL LETTER NGAAWARANG CITI CAPITAL LETTER AWARANG CITI CAPITAL LETTER " +
"WIWARANG CITI CAPITAL LETTER YUWARANG CITI CAPITAL LETTER YAWARANG CITI " +
"CAPITAL LETTER YOWARANG CITI CAPITAL LETTER IIWARANG CITI CAPITAL LETTER" +
" UUWARANG CITI CAPITAL LETTER EWARANG CITI CAPITAL LETTER OWARANG CITI C" +
"APITAL LETTER ANGWARANG CITI CAPITAL LETTER GAWARANG CITI CAPITAL LETTER" +
" KOWARANG CITI CAPITAL LETTER ENYWARANG CITI CAPITAL LETTER YUJWARANG CI" +
"TI CAPITAL LETTER UCWARANG CITI CAPITAL LETTER ENNWARANG CITI CAPITAL LE" +
"TTER ODDWARANG CITI CAPITAL LETTER TTEWARANG CITI CAPITAL LETTER NUNGWAR") + ("" +
"ANG CITI CAPITAL LETTER DAWARANG CITI CAPITAL LETTER ATWARANG CITI CAPIT" +
"AL LETTER AMWARANG CITI CAPITAL LETTER BUWARANG CITI CAPITAL LETTER PUWA" +
"RANG CITI CAPITAL LETTER HIYOWARANG CITI CAPITAL LETTER HOLOWARANG CITI " +
"CAPITAL LETTER HORRWARANG CITI CAPITAL LETTER HARWARANG CITI CAPITAL LET" +
"TER SSUUWARANG CITI CAPITAL LETTER SIIWARANG CITI CAPITAL LETTER VIYOWAR" +
"ANG CITI SMALL LETTER NGAAWARANG CITI SMALL LETTER AWARANG CITI SMALL LE" +
"TTER WIWARANG CITI SMALL LETTER YUWARANG CITI SMALL LETTER YAWARANG CITI" +
" SMALL LETTER YOWARANG CITI SMALL LETTER IIWARANG CITI SMALL LETTER UUWA" +
"RANG CITI SMALL LETTER EWARANG CITI SMALL LETTER OWARANG CITI SMALL LETT" +
"ER ANGWARANG CITI SMALL LETTER GAWARANG CITI SMALL LETTER KOWARANG CITI " +
"SMALL LETTER ENYWARANG CITI SMALL LETTER YUJWARANG CITI SMALL LETTER UCW" +
"ARANG CITI SMALL LETTER ENNWARANG CITI SMALL LETTER ODDWARANG CITI SMALL" +
" LETTER TTEWARANG CITI SMALL LETTER NUNGWARANG CITI SMALL LETTER DAWARAN" +
"G CITI SMALL LETTER ATWARANG CITI SMALL LETTER AMWARANG CITI SMALL LETTE" +
"R BUWARANG CITI SMALL LETTER PUWARANG CITI SMALL LETTER HIYOWARANG CITI " +
"SMALL LETTER HOLOWARANG CITI SMALL LETTER HORRWARANG CITI SMALL LETTER H" +
"ARWARANG CITI SMALL LETTER SSUUWARANG CITI SMALL LETTER SIIWARANG CITI S" +
"MALL LETTER VIYOWARANG CITI DIGIT ZEROWARANG CITI DIGIT ONEWARANG CITI D" +
"IGIT TWOWARANG CITI DIGIT THREEWARANG CITI DIGIT FOURWARANG CITI DIGIT F" +
"IVEWARANG CITI DIGIT SIXWARANG CITI DIGIT SEVENWARANG CITI DIGIT EIGHTWA" +
"RANG CITI DIGIT NINEWARANG CITI NUMBER TENWARANG CITI NUMBER TWENTYWARAN" +
"G CITI NUMBER THIRTYWARANG CITI NUMBER FORTYWARANG CITI NUMBER FIFTYWARA" +
"NG CITI NUMBER SIXTYWARANG CITI NUMBER SEVENTYWARANG CITI NUMBER EIGHTYW" +
"ARANG CITI NUMBER NINETYWARANG CITI OMDIVES AKURU LETTER ADIVES AKURU LE" +
"TTER AADIVES AKURU LETTER IDIVES AKURU LETTER IIDIVES AKURU LETTER UDIVE" +
"S AKURU LETTER UUDIVES AKURU LETTER EDIVES AKURU LETTER ODIVES AKURU LET" +
"TER KADIVES AKURU LETTER KHADIVES AKURU LETTER GADIVES AKURU LETTER GHAD" +
"IVES AKURU LETTER NGADIVES AKURU LETTER CADIVES AKURU LETTER CHADIVES AK" +
"URU LETTER JADIVES AKURU LETTER NYADIVES AKURU LETTER TTADIVES AKURU LET" +
"TER DDADIVES AKURU LETTER DDHADIVES AKURU LETTER NNADIVES AKURU LETTER T" +
"ADIVES AKURU LETTER THADIVES AKURU LETTER DADIVES AKURU LETTER DHADIVES " +
"AKURU LETTER NADIVES AKURU LETTER PADIVES AKURU LETTER PHADIVES AKURU LE" +
"TTER BADIVES AKURU LETTER BHADIVES AKURU LETTER MADIVES AKURU LETTER YAD" +
"IVES AKURU LETTER YYADIVES AKURU LETTER RADIVES AKURU LETTER LADIVES AKU" +
"RU LETTER VADIVES AKURU LETTER SHADIVES AKURU LETTER SSADIVES AKURU LETT" +
"ER SADIVES AKURU LETTER HADIVES AKURU LETTER LLADIVES AKURU LETTER ZADIV" +
"ES AKURU VOWEL SIGN AADIVES AKURU VOWEL SIGN IDIVES AKURU VOWEL SIGN IID" +
"IVES AKURU VOWEL SIGN UDIVES AKURU VOWEL SIGN UUDIVES AKURU VOWEL SIGN E" +
"DIVES AKURU VOWEL SIGN AIDIVES AKURU VOWEL SIGN ODIVES AKURU SIGN ANUSVA" +
"RADIVES AKURU SIGN CANDRABINDUDIVES AKURU SIGN HALANTADIVES AKURU VIRAMA" +
"DIVES AKURU PREFIXED NASAL SIGNDIVES AKURU MEDIAL YADIVES AKURU INITIAL " +
"RADIVES AKURU MEDIAL RADIVES AKURU SIGN NUKTADIVES AKURU DOUBLE DANDADIV" +
"ES AKURU GAP FILLERDIVES AKURU END OF TEXT MARKDIVES AKURU DIGIT ZERODIV" +
"ES AKURU DIGIT ONEDIVES AKURU DIGIT TWODIVES AKURU DIGIT THREEDIVES AKUR" +
"U DIGIT FOURDIVES AKURU DIGIT FIVEDIVES AKURU DIGIT SIXDIVES AKURU DIGIT" +
" SEVENDIVES AKURU DIGIT EIGHTDIVES AKURU DIGIT NINENANDINAGARI LETTER AN" +
"ANDINAGARI LETTER AANANDINAGARI LETTER INANDINAGARI LETTER IINANDINAGARI" +
" LETTER UNANDINAGARI LETTER UUNANDINAGARI LETTER VOCALIC RNANDINAGARI LE" +
"TTER VOCALIC RRNANDINAGARI LETTER ENANDINAGARI LETTER AINANDINAGARI LETT" +
"ER ONANDINAGARI LETTER AUNANDINAGARI LETTER KANANDINAGARI LETTER KHANAND" +
"INAGARI LETTER GANANDINAGARI LETTER GHANANDINAGARI LETTER NGANANDINAGARI" +
" LETTER CANANDINAGARI LETTER CHANANDINAGARI LETTER JANANDINAGARI LETTER " +
"JHANANDINAGARI LETTER NYANANDINAGARI LETTER TTANANDINAGARI LETTER TTHANA" +
"NDINAGARI LETTER DDANANDINAGARI LETTER DDHANANDINAGARI LETTER NNANANDINA" +
"GARI LETTER TANANDINAGARI LETTER THANANDINAGARI LETTER DANANDINAGARI LET" +
"TER DHANANDINAGARI LETTER NANANDINAGARI LETTER PANANDINAGARI LETTER PHAN" +
"ANDINAGARI LETTER BANANDINAGARI LETTER BHANANDINAGARI LETTER MANANDINAGA" +
"RI LETTER YANANDINAGARI LETTER RANANDINAGARI LETTER LANANDINAGARI LETTER" +
" VANANDINAGARI LETTER SHANANDINAGARI LETTER SSANANDINAGARI LETTER SANAND" +
"INAGARI LETTER HANANDINAGARI LETTER LLANANDINAGARI LETTER RRANANDINAGARI" +
" VOWEL SIGN AANANDINAGARI VOWEL SIGN INANDINAGARI VOWEL SIGN IINANDINAGA" +
"RI VOWEL SIGN UNANDINAGARI VOWEL SIGN UUNANDINAGARI VOWEL SIGN VOCALIC R" +
"NANDINAGARI VOWEL SIGN VOCALIC RRNANDINAGARI VOWEL SIGN ENANDINAGARI VOW" +
"EL SIGN AINANDINAGARI VOWEL SIGN ONANDINAGARI VOWEL SIGN AUNANDINAGARI S") + ("" +
"IGN ANUSVARANANDINAGARI SIGN VISARGANANDINAGARI SIGN VIRAMANANDINAGARI S" +
"IGN AVAGRAHANANDINAGARI SIGN SIDDHAMNANDINAGARI HEADSTROKENANDINAGARI VO" +
"WEL SIGN PRISHTHAMATRA EZANABAZAR SQUARE LETTER AZANABAZAR SQUARE VOWEL " +
"SIGN IZANABAZAR SQUARE VOWEL SIGN UEZANABAZAR SQUARE VOWEL SIGN UZANABAZ" +
"AR SQUARE VOWEL SIGN EZANABAZAR SQUARE VOWEL SIGN OEZANABAZAR SQUARE VOW" +
"EL SIGN OZANABAZAR SQUARE VOWEL SIGN AIZANABAZAR SQUARE VOWEL SIGN AUZAN" +
"ABAZAR SQUARE VOWEL SIGN REVERSED IZANABAZAR SQUARE VOWEL LENGTH MARKZAN" +
"ABAZAR SQUARE LETTER KAZANABAZAR SQUARE LETTER KHAZANABAZAR SQUARE LETTE" +
"R GAZANABAZAR SQUARE LETTER GHAZANABAZAR SQUARE LETTER NGAZANABAZAR SQUA" +
"RE LETTER CAZANABAZAR SQUARE LETTER CHAZANABAZAR SQUARE LETTER JAZANABAZ" +
"AR SQUARE LETTER NYAZANABAZAR SQUARE LETTER TTAZANABAZAR SQUARE LETTER T" +
"THAZANABAZAR SQUARE LETTER DDAZANABAZAR SQUARE LETTER DDHAZANABAZAR SQUA" +
"RE LETTER NNAZANABAZAR SQUARE LETTER TAZANABAZAR SQUARE LETTER THAZANABA" +
"ZAR SQUARE LETTER DAZANABAZAR SQUARE LETTER DHAZANABAZAR SQUARE LETTER N" +
"AZANABAZAR SQUARE LETTER PAZANABAZAR SQUARE LETTER PHAZANABAZAR SQUARE L" +
"ETTER BAZANABAZAR SQUARE LETTER BHAZANABAZAR SQUARE LETTER MAZANABAZAR S" +
"QUARE LETTER TSAZANABAZAR SQUARE LETTER TSHAZANABAZAR SQUARE LETTER DZAZ" +
"ANABAZAR SQUARE LETTER DZHAZANABAZAR SQUARE LETTER ZHAZANABAZAR SQUARE L" +
"ETTER ZAZANABAZAR SQUARE LETTER -AZANABAZAR SQUARE LETTER YAZANABAZAR SQ" +
"UARE LETTER RAZANABAZAR SQUARE LETTER LAZANABAZAR SQUARE LETTER VAZANABA" +
"ZAR SQUARE LETTER SHAZANABAZAR SQUARE LETTER SSAZANABAZAR SQUARE LETTER " +
"SAZANABAZAR SQUARE LETTER HAZANABAZAR SQUARE LETTER KSSAZANABAZAR SQUARE" +
" FINAL CONSONANT MARKZANABAZAR SQUARE SIGN VIRAMAZANABAZAR SQUARE SIGN C" +
"ANDRABINDUZANABAZAR SQUARE SIGN CANDRABINDU WITH ORNAMENTZANABAZAR SQUAR" +
"E SIGN CANDRA WITH ORNAMENTZANABAZAR SQUARE SIGN ANUSVARAZANABAZAR SQUAR" +
"E SIGN VISARGAZANABAZAR SQUARE CLUSTER-INITIAL LETTER RAZANABAZAR SQUARE" +
" CLUSTER-FINAL LETTER YAZANABAZAR SQUARE CLUSTER-FINAL LETTER RAZANABAZA" +
"R SQUARE CLUSTER-FINAL LETTER LAZANABAZAR SQUARE CLUSTER-FINAL LETTER VA" +
"ZANABAZAR SQUARE INITIAL HEAD MARKZANABAZAR SQUARE CLOSING HEAD MARKZANA" +
"BAZAR SQUARE MARK TSHEGZANABAZAR SQUARE MARK SHADZANABAZAR SQUARE MARK D" +
"OUBLE SHADZANABAZAR SQUARE MARK LONG TSHEGZANABAZAR SQUARE INITIAL DOUBL" +
"E-LINED HEAD MARKZANABAZAR SQUARE CLOSING DOUBLE-LINED HEAD MARKZANABAZA" +
"R SQUARE SUBJOINERSOYOMBO LETTER ASOYOMBO VOWEL SIGN ISOYOMBO VOWEL SIGN" +
" UESOYOMBO VOWEL SIGN USOYOMBO VOWEL SIGN ESOYOMBO VOWEL SIGN OSOYOMBO V" +
"OWEL SIGN OESOYOMBO VOWEL SIGN AISOYOMBO VOWEL SIGN AUSOYOMBO VOWEL SIGN" +
" VOCALIC RSOYOMBO VOWEL SIGN VOCALIC LSOYOMBO VOWEL LENGTH MARKSOYOMBO L" +
"ETTER KASOYOMBO LETTER KHASOYOMBO LETTER GASOYOMBO LETTER GHASOYOMBO LET" +
"TER NGASOYOMBO LETTER CASOYOMBO LETTER CHASOYOMBO LETTER JASOYOMBO LETTE" +
"R JHASOYOMBO LETTER NYASOYOMBO LETTER TTASOYOMBO LETTER TTHASOYOMBO LETT" +
"ER DDASOYOMBO LETTER DDHASOYOMBO LETTER NNASOYOMBO LETTER TASOYOMBO LETT" +
"ER THASOYOMBO LETTER DASOYOMBO LETTER DHASOYOMBO LETTER NASOYOMBO LETTER" +
" PASOYOMBO LETTER PHASOYOMBO LETTER BASOYOMBO LETTER BHASOYOMBO LETTER M" +
"ASOYOMBO LETTER TSASOYOMBO LETTER TSHASOYOMBO LETTER DZASOYOMBO LETTER Z" +
"HASOYOMBO LETTER ZASOYOMBO LETTER -ASOYOMBO LETTER YASOYOMBO LETTER RASO" +
"YOMBO LETTER LASOYOMBO LETTER VASOYOMBO LETTER SHASOYOMBO LETTER SSASOYO" +
"MBO LETTER SASOYOMBO LETTER HASOYOMBO LETTER KSSASOYOMBO SIGN JIHVAMULIY" +
"ASOYOMBO SIGN UPADHMANIYASOYOMBO CLUSTER-INITIAL LETTER RASOYOMBO CLUSTE" +
"R-INITIAL LETTER LASOYOMBO CLUSTER-INITIAL LETTER SHASOYOMBO CLUSTER-INI" +
"TIAL LETTER SASOYOMBO FINAL CONSONANT SIGN GSOYOMBO FINAL CONSONANT SIGN" +
" KSOYOMBO FINAL CONSONANT SIGN NGSOYOMBO FINAL CONSONANT SIGN DSOYOMBO F" +
"INAL CONSONANT SIGN NSOYOMBO FINAL CONSONANT SIGN BSOYOMBO FINAL CONSONA" +
"NT SIGN MSOYOMBO FINAL CONSONANT SIGN RSOYOMBO FINAL CONSONANT SIGN LSOY" +
"OMBO FINAL CONSONANT SIGN SHSOYOMBO FINAL CONSONANT SIGN SSOYOMBO FINAL " +
"CONSONANT SIGN -ASOYOMBO SIGN ANUSVARASOYOMBO SIGN VISARGASOYOMBO GEMINA" +
"TION MARKSOYOMBO SUBJOINERSOYOMBO MARK TSHEGSOYOMBO MARK SHADSOYOMBO MAR" +
"K DOUBLE SHADSOYOMBO MARK PLUTASOYOMBO HEAD MARK WITH MOON AND SUN AND T" +
"RIPLE FLAMESOYOMBO HEAD MARK WITH MOON AND SUN AND FLAMESOYOMBO HEAD MAR" +
"K WITH MOON AND SUNSOYOMBO TERMINAL MARK-1SOYOMBO TERMINAL MARK-2CANADIA" +
"N SYLLABICS NATTILIK HICANADIAN SYLLABICS NATTILIK HIICANADIAN SYLLABICS" +
" NATTILIK HOCANADIAN SYLLABICS NATTILIK HOOCANADIAN SYLLABICS NATTILIK H" +
"ACANADIAN SYLLABICS NATTILIK HAACANADIAN SYLLABICS NATTILIK SHRICANADIAN" +
" SYLLABICS NATTILIK SHRIICANADIAN SYLLABICS NATTILIK SHROCANADIAN SYLLAB" +
"ICS NATTILIK SHROOCANADIAN SYLLABICS NATTILIK SHRACANADIAN SYLLABICS NAT" +
"TILIK SHRAACANADIAN SYLLABICS SPECANADIAN SYLLABICS SPICANADIAN SYLLABIC") + ("" +
"S SPOCANADIAN SYLLABICS SPAPAU CIN HAU LETTER PAPAU CIN HAU LETTER KAPAU" +
" CIN HAU LETTER LAPAU CIN HAU LETTER MAPAU CIN HAU LETTER DAPAU CIN HAU " +
"LETTER ZAPAU CIN HAU LETTER VAPAU CIN HAU LETTER NGAPAU CIN HAU LETTER H" +
"APAU 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 LETT" +
"ER THAPAU CIN HAU LETTER NAPAU CIN HAU LETTER PHAPAU CIN HAU LETTER RAPA" +
"U CIN HAU LETTER 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 LETTER UAPAU CIN HAU LETTER IAPAU CIN HAU LETTER FINAL PPAU CIN" +
" HAU LETTER FINAL KPAU CIN HAU LETTER FINAL TPAU CIN HAU LETTER FINAL MP" +
"AU CIN HAU LETTER FINAL NPAU CIN HAU LETTER FINAL LPAU CIN HAU LETTER FI" +
"NAL WPAU CIN HAU LETTER FINAL NGPAU CIN HAU LETTER FINAL YPAU CIN HAU RI" +
"SING TONE LONGPAU CIN HAU RISING TONEPAU CIN HAU SANDHI GLOTTAL STOPPAU " +
"CIN HAU RISING TONE LONG FINALPAU CIN HAU RISING TONE FINALPAU CIN HAU S" +
"ANDHI GLOTTAL STOP FINALPAU CIN HAU SANDHI TONE LONGPAU CIN HAU SANDHI T" +
"ONEPAU CIN HAU SANDHI TONE LONG FINALPAU CIN HAU SANDHI TONE FINALPAU CI" +
"N HAU MID-LEVEL TONEPAU CIN HAU GLOTTAL STOP VARIANTPAU CIN HAU MID-LEVE" +
"L TONE LONG FINALPAU CIN HAU MID-LEVEL TONE FINALPAU CIN HAU LOW-FALLING" +
" TONE LONGPAU CIN HAU LOW-FALLING TONEPAU CIN HAU GLOTTAL STOPPAU CIN HA" +
"U LOW-FALLING TONE LONG FINALPAU CIN HAU LOW-FALLING TONE FINALPAU CIN H" +
"AU GLOTTAL STOP FINALDEVANAGARI HEAD MARKDEVANAGARI HEAD MARK WITH HEADS" +
"TROKEDEVANAGARI SIGN BHALEDEVANAGARI SIGN BHALE WITH HOOKDEVANAGARI SIGN" +
" EXTENDED BHALEDEVANAGARI SIGN EXTENDED BHALE WITH HOOKDEVANAGARI SIGN W" +
"ESTERN FIVE-LIKE BHALEDEVANAGARI SIGN WESTERN NINE-LIKE BHALEDEVANAGARI " +
"SIGN REVERSED NINE-LIKE BHALEDEVANAGARI SIGN MINDUSHARADA VOWEL SIGN OES" +
"HARADA VOWEL SIGN OOESHARADA VOWEL SIGN UESHARADA VOWEL SIGN UUESHARADA " +
"VOWEL SIGN SHORT ESHARADA VOWEL SIGN SHORT OSHARADA VOWEL SIGN CANDRA ES" +
"HARADA VOWEL SIGN CANDRA OSUNUWAR LETTER DEVISUNUWAR LETTER TASLASUNUWAR" +
" LETTER EKOSUNUWAR LETTER IMARSUNUWAR LETTER REUSUNUWAR LETTER UTTHISUNU" +
"WAR LETTER KIKSUNUWAR LETTER MASUNUWAR LETTER APPHOSUNUWAR LETTER PIPSUN" +
"UWAR LETTER GILSUNUWAR LETTER HAMSOSUNUWAR LETTER CARMISUNUWAR LETTER NA" +
"HSUNUWAR LETTER BURSUNUWAR LETTER JYAHSUNUWAR LETTER LOACHASUNUWAR LETTE" +
"R OTTHISUNUWAR LETTER SHYELESUNUWAR LETTER VARCASUNUWAR LETTER YATSUNUWA" +
"R LETTER AVASUNUWAR LETTER AALSUNUWAR LETTER DONGASUNUWAR LETTER THARISU" +
"NUWAR LETTER PHARSUNUWAR LETTER NGARSUNUWAR LETTER KHASUNUWAR LETTER SHY" +
"ERSUNUWAR LETTER CHELAPSUNUWAR LETTER TENTUSUNUWAR LETTER THELESUNUWAR L" +
"ETTER KLOKOSUNUWAR SIGN PVOSUNUWAR DIGIT ZEROSUNUWAR DIGIT ONESUNUWAR DI" +
"GIT TWOSUNUWAR DIGIT THREESUNUWAR DIGIT FOURSUNUWAR DIGIT FIVESUNUWAR DI" +
"GIT SIXSUNUWAR DIGIT SEVENSUNUWAR DIGIT EIGHTSUNUWAR DIGIT NINEBHAIKSUKI" +
" LETTER ABHAIKSUKI LETTER AABHAIKSUKI LETTER IBHAIKSUKI LETTER IIBHAIKSU" +
"KI LETTER UBHAIKSUKI LETTER UUBHAIKSUKI LETTER VOCALIC RBHAIKSUKI LETTER" +
" VOCALIC RRBHAIKSUKI LETTER VOCALIC LBHAIKSUKI LETTER EBHAIKSUKI LETTER " +
"AIBHAIKSUKI LETTER OBHAIKSUKI LETTER AUBHAIKSUKI LETTER KABHAIKSUKI LETT" +
"ER KHABHAIKSUKI LETTER GABHAIKSUKI LETTER GHABHAIKSUKI LETTER NGABHAIKSU" +
"KI LETTER CABHAIKSUKI LETTER CHABHAIKSUKI LETTER JABHAIKSUKI LETTER JHAB" +
"HAIKSUKI LETTER NYABHAIKSUKI LETTER TTABHAIKSUKI LETTER TTHABHAIKSUKI LE" +
"TTER DDABHAIKSUKI LETTER DDHABHAIKSUKI LETTER NNABHAIKSUKI LETTER TABHAI" +
"KSUKI LETTER THABHAIKSUKI LETTER DABHAIKSUKI LETTER DHABHAIKSUKI LETTER " +
"NABHAIKSUKI LETTER PABHAIKSUKI LETTER PHABHAIKSUKI LETTER BABHAIKSUKI LE" +
"TTER BHABHAIKSUKI LETTER MABHAIKSUKI LETTER YABHAIKSUKI LETTER RABHAIKSU" +
"KI LETTER LABHAIKSUKI LETTER VABHAIKSUKI LETTER SHABHAIKSUKI LETTER SSAB" +
"HAIKSUKI LETTER SABHAIKSUKI LETTER HABHAIKSUKI VOWEL SIGN AABHAIKSUKI VO" +
"WEL SIGN IBHAIKSUKI VOWEL SIGN IIBHAIKSUKI VOWEL SIGN UBHAIKSUKI VOWEL S" +
"IGN UUBHAIKSUKI VOWEL SIGN VOCALIC RBHAIKSUKI VOWEL SIGN VOCALIC RRBHAIK" +
"SUKI VOWEL SIGN VOCALIC LBHAIKSUKI VOWEL SIGN EBHAIKSUKI VOWEL SIGN AIBH" +
"AIKSUKI VOWEL SIGN OBHAIKSUKI VOWEL SIGN AUBHAIKSUKI SIGN CANDRABINDUBHA" +
"IKSUKI SIGN ANUSVARABHAIKSUKI SIGN VISARGABHAIKSUKI SIGN VIRAMABHAIKSUKI" +
" SIGN AVAGRAHABHAIKSUKI DANDABHAIKSUKI DOUBLE DANDABHAIKSUKI WORD SEPARA" +
"TORBHAIKSUKI GAP FILLER-1BHAIKSUKI GAP FILLER-2BHAIKSUKI DIGIT ZEROBHAIK" +
"SUKI DIGIT ONEBHAIKSUKI DIGIT TWOBHAIKSUKI DIGIT THREEBHAIKSUKI DIGIT FO" +
"URBHAIKSUKI DIGIT FIVEBHAIKSUKI DIGIT SIXBHAIKSUKI DIGIT SEVENBHAIKSUKI " +
"DIGIT EIGHTBHAIKSUKI DIGIT NINEBHAIKSUKI NUMBER ONEBHAIKSUKI NUMBER TWOB" +
"HAIKSUKI NUMBER THREEBHAIKSUKI NUMBER FOURBHAIKSUKI NUMBER FIVEBHAIKSUKI" +
" NUMBER SIXBHAIKSUKI NUMBER SEVENBHAIKSUKI NUMBER EIGHTBHAIKSUKI NUMBER ") + ("" +
"NINEBHAIKSUKI NUMBER TENBHAIKSUKI NUMBER TWENTYBHAIKSUKI NUMBER THIRTYBH" +
"AIKSUKI NUMBER FORTYBHAIKSUKI NUMBER FIFTYBHAIKSUKI NUMBER SIXTYBHAIKSUK" +
"I NUMBER SEVENTYBHAIKSUKI NUMBER EIGHTYBHAIKSUKI NUMBER NINETYBHAIKSUKI " +
"HUNDREDS UNIT MARKMARCHEN HEAD MARKMARCHEN MARK SHADMARCHEN LETTER KAMAR" +
"CHEN LETTER KHAMARCHEN LETTER GAMARCHEN LETTER NGAMARCHEN LETTER CAMARCH" +
"EN LETTER CHAMARCHEN LETTER JAMARCHEN LETTER NYAMARCHEN LETTER TAMARCHEN" +
" LETTER THAMARCHEN LETTER DAMARCHEN LETTER NAMARCHEN LETTER PAMARCHEN LE" +
"TTER PHAMARCHEN LETTER BAMARCHEN LETTER MAMARCHEN LETTER TSAMARCHEN LETT" +
"ER TSHAMARCHEN LETTER DZAMARCHEN LETTER WAMARCHEN LETTER ZHAMARCHEN LETT" +
"ER ZAMARCHEN LETTER -AMARCHEN LETTER YAMARCHEN LETTER RAMARCHEN LETTER L" +
"AMARCHEN LETTER SHAMARCHEN LETTER SAMARCHEN LETTER HAMARCHEN LETTER AMAR" +
"CHEN SUBJOINED LETTER KAMARCHEN SUBJOINED LETTER KHAMARCHEN SUBJOINED LE" +
"TTER GAMARCHEN SUBJOINED LETTER NGAMARCHEN SUBJOINED LETTER CAMARCHEN SU" +
"BJOINED LETTER CHAMARCHEN SUBJOINED LETTER JAMARCHEN SUBJOINED LETTER NY" +
"AMARCHEN SUBJOINED LETTER TAMARCHEN SUBJOINED LETTER THAMARCHEN SUBJOINE" +
"D LETTER DAMARCHEN SUBJOINED LETTER NAMARCHEN SUBJOINED LETTER PAMARCHEN" +
" SUBJOINED LETTER PHAMARCHEN SUBJOINED LETTER BAMARCHEN SUBJOINED LETTER" +
" MAMARCHEN SUBJOINED LETTER TSAMARCHEN SUBJOINED LETTER TSHAMARCHEN SUBJ" +
"OINED LETTER DZAMARCHEN SUBJOINED LETTER WAMARCHEN SUBJOINED LETTER ZHAM" +
"ARCHEN SUBJOINED LETTER ZAMARCHEN SUBJOINED LETTER YAMARCHEN SUBJOINED L" +
"ETTER RAMARCHEN SUBJOINED LETTER LAMARCHEN SUBJOINED LETTER SHAMARCHEN S" +
"UBJOINED LETTER SAMARCHEN SUBJOINED LETTER HAMARCHEN SUBJOINED LETTER AM" +
"ARCHEN VOWEL SIGN AAMARCHEN VOWEL SIGN IMARCHEN VOWEL SIGN UMARCHEN VOWE" +
"L SIGN EMARCHEN VOWEL SIGN OMARCHEN SIGN ANUSVARAMARCHEN SIGN CANDRABIND" +
"UMASARAM GONDI LETTER AMASARAM GONDI LETTER AAMASARAM GONDI LETTER IMASA" +
"RAM GONDI LETTER IIMASARAM GONDI LETTER UMASARAM GONDI LETTER UUMASARAM " +
"GONDI LETTER EMASARAM GONDI LETTER AIMASARAM GONDI LETTER OMASARAM GONDI" +
" LETTER AUMASARAM GONDI LETTER KAMASARAM GONDI LETTER KHAMASARAM GONDI L" +
"ETTER GAMASARAM GONDI LETTER GHAMASARAM GONDI LETTER NGAMASARAM GONDI LE" +
"TTER CAMASARAM GONDI LETTER CHAMASARAM GONDI LETTER JAMASARAM GONDI LETT" +
"ER JHAMASARAM GONDI LETTER NYAMASARAM GONDI LETTER TTAMASARAM GONDI LETT" +
"ER TTHAMASARAM GONDI LETTER DDAMASARAM GONDI LETTER DDHAMASARAM GONDI LE" +
"TTER NNAMASARAM GONDI LETTER TAMASARAM GONDI LETTER THAMASARAM GONDI LET" +
"TER DAMASARAM GONDI LETTER DHAMASARAM GONDI LETTER NAMASARAM GONDI LETTE" +
"R PAMASARAM GONDI LETTER PHAMASARAM GONDI LETTER BAMASARAM GONDI LETTER " +
"BHAMASARAM GONDI LETTER MAMASARAM GONDI LETTER YAMASARAM GONDI LETTER RA" +
"MASARAM GONDI LETTER LAMASARAM GONDI LETTER VAMASARAM GONDI LETTER SHAMA" +
"SARAM GONDI LETTER SSAMASARAM GONDI LETTER SAMASARAM GONDI LETTER HAMASA" +
"RAM GONDI LETTER LLAMASARAM GONDI LETTER KSSAMASARAM GONDI LETTER JNYAMA" +
"SARAM GONDI LETTER TRAMASARAM GONDI VOWEL SIGN AAMASARAM GONDI VOWEL SIG" +
"N IMASARAM GONDI VOWEL SIGN IIMASARAM GONDI VOWEL SIGN UMASARAM GONDI VO" +
"WEL SIGN UUMASARAM GONDI VOWEL SIGN VOCALIC RMASARAM GONDI VOWEL SIGN EM" +
"ASARAM GONDI VOWEL SIGN AIMASARAM GONDI VOWEL SIGN OMASARAM GONDI VOWEL " +
"SIGN AUMASARAM GONDI SIGN ANUSVARAMASARAM GONDI SIGN VISARGAMASARAM GOND" +
"I SIGN NUKTAMASARAM GONDI SIGN CANDRAMASARAM GONDI SIGN HALANTAMASARAM G" +
"ONDI VIRAMAMASARAM GONDI REPHAMASARAM GONDI RA-KARAMASARAM GONDI DIGIT Z" +
"EROMASARAM GONDI DIGIT ONEMASARAM GONDI DIGIT TWOMASARAM GONDI DIGIT THR" +
"EEMASARAM GONDI DIGIT FOURMASARAM GONDI DIGIT FIVEMASARAM GONDI DIGIT SI" +
"XMASARAM GONDI DIGIT SEVENMASARAM GONDI DIGIT EIGHTMASARAM GONDI DIGIT N" +
"INEGUNJALA GONDI LETTER AGUNJALA GONDI LETTER AAGUNJALA GONDI LETTER IGU" +
"NJALA GONDI LETTER IIGUNJALA GONDI LETTER UGUNJALA GONDI LETTER UUGUNJAL" +
"A GONDI LETTER EEGUNJALA GONDI LETTER AIGUNJALA GONDI LETTER OOGUNJALA G" +
"ONDI LETTER AUGUNJALA GONDI LETTER YAGUNJALA GONDI LETTER VAGUNJALA GOND" +
"I LETTER BAGUNJALA GONDI LETTER BHAGUNJALA GONDI LETTER MAGUNJALA GONDI " +
"LETTER KAGUNJALA GONDI LETTER KHAGUNJALA GONDI LETTER TAGUNJALA GONDI LE" +
"TTER THAGUNJALA GONDI LETTER LAGUNJALA GONDI LETTER GAGUNJALA GONDI LETT" +
"ER GHAGUNJALA GONDI LETTER DAGUNJALA GONDI LETTER DHAGUNJALA GONDI LETTE" +
"R NAGUNJALA GONDI LETTER CAGUNJALA GONDI LETTER CHAGUNJALA GONDI LETTER " +
"TTAGUNJALA GONDI LETTER TTHAGUNJALA GONDI LETTER LLAGUNJALA GONDI LETTER" +
" JAGUNJALA GONDI LETTER JHAGUNJALA GONDI LETTER DDAGUNJALA GONDI LETTER " +
"DDHAGUNJALA GONDI LETTER NGAGUNJALA GONDI LETTER PAGUNJALA GONDI LETTER " +
"PHAGUNJALA GONDI LETTER HAGUNJALA GONDI LETTER RAGUNJALA GONDI LETTER SA" +
"GUNJALA GONDI VOWEL SIGN AAGUNJALA GONDI VOWEL SIGN IGUNJALA GONDI VOWEL" +
" SIGN IIGUNJALA GONDI VOWEL SIGN UGUNJALA GONDI VOWEL SIGN UUGUNJALA GON") + ("" +
"DI VOWEL SIGN EEGUNJALA GONDI VOWEL SIGN AIGUNJALA GONDI VOWEL SIGN OOGU" +
"NJALA GONDI VOWEL SIGN AUGUNJALA GONDI SIGN ANUSVARAGUNJALA GONDI SIGN V" +
"ISARGAGUNJALA GONDI VIRAMAGUNJALA GONDI OMGUNJALA GONDI DIGIT ZEROGUNJAL" +
"A 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 NINETOLONG" +
" SIKI LETTER ITOLONG SIKI LETTER ETOLONG SIKI LETTER UTOLONG SIKI LETTER" +
" OTOLONG SIKI LETTER ATOLONG SIKI LETTER AATOLONG SIKI LETTER PTOLONG SI" +
"KI LETTER PHTOLONG SIKI LETTER BTOLONG SIKI LETTER BHTOLONG SIKI LETTER " +
"MTOLONG SIKI LETTER TTOLONG SIKI LETTER THTOLONG SIKI LETTER DTOLONG SIK" +
"I LETTER DHTOLONG SIKI LETTER NTOLONG SIKI LETTER TTTOLONG SIKI LETTER T" +
"THTOLONG SIKI LETTER DDTOLONG SIKI LETTER DDHTOLONG SIKI LETTER NNTOLONG" +
" SIKI LETTER CTOLONG SIKI LETTER CHTOLONG SIKI LETTER JTOLONG SIKI LETTE" +
"R JHTOLONG SIKI LETTER NYTOLONG SIKI LETTER KTOLONG SIKI LETTER KHTOLONG" +
" SIKI LETTER GTOLONG SIKI LETTER GHTOLONG SIKI LETTER NGTOLONG SIKI LETT" +
"ER YTOLONG SIKI LETTER RTOLONG SIKI LETTER LTOLONG SIKI LETTER VTOLONG S" +
"IKI LETTER NNYTOLONG SIKI LETTER STOLONG SIKI LETTER HTOLONG SIKI LETTER" +
" XTOLONG SIKI LETTER RRTOLONG SIKI LETTER RRHTOLONG SIKI SIGN SELATOLONG" +
" SIKI SIGN HECAKATOLONG SIKI UNGGATOLONG SIKI DIGIT ZEROTOLONG SIKI DIGI" +
"T ONETOLONG SIKI DIGIT TWOTOLONG SIKI DIGIT THREETOLONG SIKI DIGIT FOURT" +
"OLONG SIKI DIGIT FIVETOLONG SIKI DIGIT SIXTOLONG SIKI DIGIT SEVENTOLONG " +
"SIKI DIGIT EIGHTTOLONG SIKI DIGIT NINEMAKASAR LETTER KAMAKASAR LETTER GA" +
"MAKASAR LETTER NGAMAKASAR LETTER PAMAKASAR LETTER BAMAKASAR LETTER MAMAK" +
"ASAR LETTER TAMAKASAR LETTER DAMAKASAR LETTER NAMAKASAR LETTER CAMAKASAR" +
" LETTER JAMAKASAR LETTER NYAMAKASAR LETTER YAMAKASAR LETTER RAMAKASAR LE" +
"TTER LAMAKASAR LETTER VAMAKASAR LETTER SAMAKASAR LETTER AMAKASAR ANGKAMA" +
"KASAR VOWEL SIGN IMAKASAR VOWEL SIGN UMAKASAR VOWEL SIGN EMAKASAR VOWEL " +
"SIGN OMAKASAR PASSIMBANGMAKASAR END OF SECTIONKAWI SIGN CANDRABINDUKAWI " +
"SIGN ANUSVARAKAWI SIGN REPHAKAWI SIGN VISARGAKAWI LETTER AKAWI LETTER AA" +
"KAWI LETTER IKAWI LETTER IIKAWI LETTER UKAWI LETTER UUKAWI LETTER VOCALI" +
"C RKAWI LETTER VOCALIC RRKAWI LETTER VOCALIC LKAWI LETTER VOCALIC LLKAWI" +
" LETTER EKAWI LETTER AIKAWI LETTER OKAWI LETTER KAKAWI LETTER KHAKAWI LE" +
"TTER GAKAWI LETTER GHAKAWI LETTER NGAKAWI LETTER CAKAWI LETTER CHAKAWI L" +
"ETTER JAKAWI LETTER JHAKAWI LETTER NYAKAWI LETTER TTAKAWI LETTER TTHAKAW" +
"I LETTER DDAKAWI LETTER DDHAKAWI LETTER NNAKAWI LETTER TAKAWI LETTER THA" +
"KAWI LETTER DAKAWI LETTER DHAKAWI LETTER NAKAWI LETTER PAKAWI LETTER PHA" +
"KAWI LETTER BAKAWI LETTER BHAKAWI LETTER MAKAWI LETTER YAKAWI LETTER RAK" +
"AWI LETTER LAKAWI LETTER WAKAWI LETTER SHAKAWI LETTER SSAKAWI LETTER SAK" +
"AWI LETTER HAKAWI LETTER JNYAKAWI VOWEL SIGN AAKAWI VOWEL SIGN ALTERNATE" +
" AAKAWI VOWEL SIGN IKAWI VOWEL SIGN IIKAWI VOWEL SIGN UKAWI VOWEL SIGN U" +
"UKAWI VOWEL SIGN VOCALIC RKAWI VOWEL SIGN EKAWI VOWEL SIGN AIKAWI VOWEL " +
"SIGN EUKAWI SIGN KILLERKAWI CONJOINERKAWI DANDAKAWI DOUBLE DANDAKAWI PUN" +
"CTUATION SECTION MARKERKAWI PUNCTUATION ALTERNATE SECTION MARKERKAWI PUN" +
"CTUATION FLOWERKAWI PUNCTUATION SPACE FILLERKAWI PUNCTUATION DOTKAWI PUN" +
"CTUATION DOUBLE DOTKAWI PUNCTUATION TRIPLE DOTKAWI PUNCTUATION CIRCLEKAW" +
"I PUNCTUATION FILLED CIRCLEKAWI PUNCTUATION SPIRALKAWI PUNCTUATION CLOSI" +
"NG SPIRALKAWI DIGIT ZEROKAWI DIGIT ONEKAWI DIGIT TWOKAWI DIGIT THREEKAWI" +
" DIGIT FOURKAWI DIGIT FIVEKAWI DIGIT SIXKAWI DIGIT SEVENKAWI DIGIT EIGHT" +
"KAWI DIGIT NINEKAWI SIGN NUKTALISU LETTER YHATAMIL FRACTION ONE THREE-HU" +
"NDRED-AND-TWENTIETHTAMIL FRACTION ONE ONE-HUNDRED-AND-SIXTIETHTAMIL FRAC" +
"TION ONE EIGHTIETHTAMIL FRACTION ONE SIXTY-FOURTHTAMIL FRACTION ONE FORT" +
"IETHTAMIL FRACTION ONE THIRTY-SECONDTAMIL FRACTION THREE EIGHTIETHSTAMIL" +
" FRACTION THREE SIXTY-FOURTHSTAMIL FRACTION ONE TWENTIETHTAMIL FRACTION " +
"ONE SIXTEENTH-1TAMIL FRACTION ONE SIXTEENTH-2TAMIL FRACTION ONE TENTHTAM" +
"IL FRACTION ONE EIGHTHTAMIL FRACTION THREE TWENTIETHSTAMIL FRACTION THRE" +
"E SIXTEENTHSTAMIL FRACTION ONE FIFTHTAMIL FRACTION ONE QUARTERTAMIL FRAC" +
"TION ONE HALF-1TAMIL FRACTION ONE HALF-2TAMIL FRACTION THREE QUARTERSTAM" +
"IL FRACTION DOWNSCALING FACTOR KIIZHTAMIL SIGN NELTAMIL SIGN CEVITUTAMIL" +
" SIGN AAZHAAKKUTAMIL SIGN UZHAKKUTAMIL SIGN MUUVUZHAKKUTAMIL SIGN KURUNI" +
"TAMIL SIGN PATHAKKUTAMIL SIGN MUKKURUNITAMIL SIGN KAACUTAMIL SIGN PANAMT" +
"AMIL SIGN PONTAMIL SIGN VARAAKANTAMIL SIGN PAARAMTAMIL SIGN KUZHITAMIL S" +
"IGN VELITAMIL WET CULTIVATION SIGNTAMIL DRY CULTIVATION SIGNTAMIL LAND S" +
"IGNTAMIL SALT PAN SIGNTAMIL TRADITIONAL CREDIT SIGNTAMIL TRADITIONAL NUM" +
"BER SIGNTAMIL CURRENT SIGNTAMIL AND ODD SIGNTAMIL SPENT SIGNTAMIL TOTAL ") + ("" +
"SIGNTAMIL IN POSSESSION SIGNTAMIL STARTING FROM SIGNTAMIL SIGN MUTHALIYA" +
"TAMIL SIGN VAKAIYARAATAMIL PUNCTUATION END OF TEXTCUNEIFORM SIGN ACUNEIF" +
"ORM SIGN A TIMES ACUNEIFORM SIGN A TIMES BADCUNEIFORM SIGN A TIMES GAN2 " +
"TENUCUNEIFORM SIGN A TIMES HACUNEIFORM SIGN A TIMES IGICUNEIFORM SIGN A " +
"TIMES LAGAR GUNUCUNEIFORM SIGN A TIMES MUSHCUNEIFORM SIGN A TIMES SAGCUN" +
"EIFORM SIGN A2CUNEIFORM SIGN ABCUNEIFORM SIGN AB TIMES ASH2CUNEIFORM SIG" +
"N AB TIMES DUN3 GUNUCUNEIFORM SIGN AB TIMES GALCUNEIFORM SIGN AB TIMES G" +
"AN2 TENUCUNEIFORM SIGN AB TIMES HACUNEIFORM SIGN AB TIMES IGI GUNUCUNEIF" +
"ORM SIGN AB TIMES IMINCUNEIFORM SIGN AB TIMES LAGABCUNEIFORM SIGN AB TIM" +
"ES SHESHCUNEIFORM SIGN AB TIMES U PLUS U PLUS UCUNEIFORM SIGN AB GUNUCUN" +
"EIFORM SIGN AB2CUNEIFORM SIGN AB2 TIMES BALAGCUNEIFORM SIGN AB2 TIMES GA" +
"N2 TENUCUNEIFORM SIGN AB2 TIMES ME PLUS ENCUNEIFORM SIGN AB2 TIMES SHA3C" +
"UNEIFORM SIGN AB2 TIMES TAK4CUNEIFORM SIGN ADCUNEIFORM SIGN AKCUNEIFORM " +
"SIGN AK TIMES ERIN2CUNEIFORM SIGN AK TIMES SHITA PLUS GISHCUNEIFORM SIGN" +
" ALCUNEIFORM SIGN AL TIMES ALCUNEIFORM SIGN AL TIMES DIM2CUNEIFORM SIGN " +
"AL TIMES GISHCUNEIFORM SIGN AL TIMES HACUNEIFORM SIGN AL TIMES KAD3CUNEI" +
"FORM SIGN AL TIMES KICUNEIFORM SIGN AL TIMES SHECUNEIFORM SIGN AL TIMES " +
"USHCUNEIFORM SIGN ALANCUNEIFORM SIGN ALEPHCUNEIFORM SIGN AMARCUNEIFORM S" +
"IGN AMAR TIMES SHECUNEIFORM SIGN ANCUNEIFORM SIGN AN OVER ANCUNEIFORM SI" +
"GN AN THREE TIMESCUNEIFORM SIGN AN PLUS NAGA OPPOSING AN PLUS NAGACUNEIF" +
"ORM SIGN AN PLUS NAGA SQUAREDCUNEIFORM SIGN ANSHECUNEIFORM SIGN APINCUNE" +
"IFORM SIGN ARADCUNEIFORM SIGN ARAD TIMES KURCUNEIFORM SIGN ARKABCUNEIFOR" +
"M SIGN ASAL2CUNEIFORM SIGN ASHCUNEIFORM SIGN ASH ZIDA TENUCUNEIFORM SIGN" +
" ASH KABA TENUCUNEIFORM 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 ASHG" +
"ABCUNEIFORM SIGN BACUNEIFORM SIGN BADCUNEIFORM SIGN BAG3CUNEIFORM SIGN B" +
"AHAR2CUNEIFORM SIGN BALCUNEIFORM SIGN BAL OVER BALCUNEIFORM SIGN BALAGCU" +
"NEIFORM SIGN BARCUNEIFORM SIGN BARA2CUNEIFORM SIGN BICUNEIFORM SIGN BI T" +
"IMES ACUNEIFORM SIGN BI TIMES GARCUNEIFORM SIGN BI TIMES IGI GUNUCUNEIFO" +
"RM SIGN BUCUNEIFORM SIGN BU OVER BU ABCUNEIFORM SIGN BU OVER BU UNCUNEIF" +
"ORM SIGN BU CROSSING BUCUNEIFORM SIGN BULUGCUNEIFORM SIGN BULUG OVER BUL" +
"UGCUNEIFORM SIGN BURCUNEIFORM SIGN BUR2CUNEIFORM SIGN DACUNEIFORM SIGN D" +
"AGCUNEIFORM SIGN DAG KISIM5 TIMES A PLUS MASHCUNEIFORM SIGN DAG KISIM5 T" +
"IMES AMARCUNEIFORM SIGN DAG KISIM5 TIMES BALAGCUNEIFORM SIGN DAG KISIM5 " +
"TIMES BICUNEIFORM SIGN DAG KISIM5 TIMES GACUNEIFORM SIGN DAG KISIM5 TIME" +
"S GA PLUS MASHCUNEIFORM SIGN DAG KISIM5 TIMES GICUNEIFORM SIGN DAG KISIM" +
"5 TIMES GIR2CUNEIFORM SIGN DAG KISIM5 TIMES GUDCUNEIFORM SIGN DAG KISIM5" +
" TIMES HACUNEIFORM SIGN DAG KISIM5 TIMES IRCUNEIFORM SIGN DAG KISIM5 TIM" +
"ES IR PLUS LUCUNEIFORM SIGN DAG KISIM5 TIMES KAKCUNEIFORM SIGN DAG KISIM" +
"5 TIMES LACUNEIFORM SIGN DAG KISIM5 TIMES LUCUNEIFORM SIGN DAG KISIM5 TI" +
"MES LU PLUS MASH2CUNEIFORM SIGN DAG KISIM5 TIMES LUMCUNEIFORM SIGN DAG K" +
"ISIM5 TIMES NECUNEIFORM SIGN DAG KISIM5 TIMES PAP PLUS PAPCUNEIFORM SIGN" +
" DAG KISIM5 TIMES SICUNEIFORM SIGN DAG KISIM5 TIMES TAK4CUNEIFORM SIGN D" +
"AG KISIM5 TIMES U2 PLUS GIR2CUNEIFORM SIGN DAG KISIM5 TIMES USHCUNEIFORM" +
" SIGN DAMCUNEIFORM SIGN DARCUNEIFORM SIGN DARA3CUNEIFORM SIGN DARA4CUNEI" +
"FORM SIGN DICUNEIFORM SIGN DIBCUNEIFORM SIGN DIMCUNEIFORM SIGN DIM TIMES" +
" SHECUNEIFORM SIGN DIM2CUNEIFORM SIGN DINCUNEIFORM SIGN DIN KASKAL U GUN" +
"U DISHCUNEIFORM SIGN DISHCUNEIFORM SIGN DUCUNEIFORM SIGN DU OVER DUCUNEI" +
"FORM SIGN DU GUNUCUNEIFORM SIGN DU SHESHIGCUNEIFORM SIGN DUBCUNEIFORM SI" +
"GN DUB TIMES ESH2CUNEIFORM SIGN DUB2CUNEIFORM SIGN DUGCUNEIFORM SIGN DUG" +
"UDCUNEIFORM SIGN DUHCUNEIFORM SIGN DUNCUNEIFORM SIGN DUN3CUNEIFORM SIGN " +
"DUN3 GUNUCUNEIFORM SIGN DUN3 GUNU GUNUCUNEIFORM SIGN DUN4CUNEIFORM SIGN " +
"DUR2CUNEIFORM SIGN ECUNEIFORM SIGN E TIMES PAPCUNEIFORM SIGN E OVER E NU" +
"N OVER NUNCUNEIFORM SIGN E2CUNEIFORM SIGN E2 TIMES A PLUS HA PLUS DACUNE" +
"IFORM SIGN E2 TIMES GARCUNEIFORM SIGN E2 TIMES MICUNEIFORM SIGN E2 TIMES" +
" SALCUNEIFORM SIGN E2 TIMES SHECUNEIFORM SIGN E2 TIMES UCUNEIFORM SIGN E" +
"DINCUNEIFORM SIGN EGIRCUNEIFORM SIGN ELCUNEIFORM SIGN ENCUNEIFORM SIGN E" +
"N TIMES GAN2CUNEIFORM SIGN EN TIMES GAN2 TENUCUNEIFORM SIGN EN TIMES MEC" +
"UNEIFORM SIGN EN CROSSING ENCUNEIFORM SIGN EN OPPOSING ENCUNEIFORM SIGN " +
"EN SQUAREDCUNEIFORM SIGN ERENCUNEIFORM SIGN ERIN2CUNEIFORM SIGN ESH2CUNE" +
"IFORM SIGN EZENCUNEIFORM SIGN EZEN TIMES ACUNEIFORM SIGN EZEN TIMES A PL" +
"US LALCUNEIFORM SIGN EZEN TIMES A PLUS LAL TIMES LALCUNEIFORM SIGN EZEN " +
"TIMES ANCUNEIFORM SIGN EZEN TIMES BADCUNEIFORM SIGN EZEN TIMES DUN3 GUNU") + ("" +
"CUNEIFORM SIGN EZEN TIMES DUN3 GUNU GUNUCUNEIFORM SIGN EZEN TIMES HACUNE" +
"IFORM SIGN EZEN TIMES HA GUNUCUNEIFORM SIGN EZEN TIMES IGI GUNUCUNEIFORM" +
" SIGN EZEN TIMES KASKALCUNEIFORM SIGN EZEN TIMES KASKAL SQUAREDCUNEIFORM" +
" SIGN EZEN TIMES KU3CUNEIFORM SIGN EZEN TIMES LACUNEIFORM SIGN EZEN TIME" +
"S LAL TIMES LALCUNEIFORM SIGN EZEN TIMES LICUNEIFORM SIGN EZEN TIMES LUC" +
"UNEIFORM SIGN EZEN TIMES U2CUNEIFORM SIGN EZEN TIMES UDCUNEIFORM SIGN GA" +
"CUNEIFORM SIGN GA GUNUCUNEIFORM SIGN GA2CUNEIFORM SIGN GA2 TIMES A PLUS " +
"DA PLUS HACUNEIFORM SIGN GA2 TIMES A PLUS HACUNEIFORM SIGN GA2 TIMES A P" +
"LUS IGICUNEIFORM SIGN GA2 TIMES AB2 TENU PLUS TABCUNEIFORM SIGN GA2 TIME" +
"S ANCUNEIFORM SIGN GA2 TIMES ASHCUNEIFORM SIGN GA2 TIMES ASH2 PLUS GALCU" +
"NEIFORM SIGN GA2 TIMES BADCUNEIFORM SIGN GA2 TIMES BAR PLUS RACUNEIFORM " +
"SIGN GA2 TIMES BURCUNEIFORM SIGN GA2 TIMES BUR PLUS RACUNEIFORM SIGN GA2" +
" TIMES DACUNEIFORM SIGN GA2 TIMES DICUNEIFORM SIGN GA2 TIMES DIM TIMES S" +
"HECUNEIFORM SIGN GA2 TIMES DUBCUNEIFORM SIGN GA2 TIMES ELCUNEIFORM SIGN " +
"GA2 TIMES EL PLUS LACUNEIFORM SIGN GA2 TIMES ENCUNEIFORM SIGN GA2 TIMES " +
"EN TIMES GAN2 TENUCUNEIFORM SIGN GA2 TIMES GAN2 TENUCUNEIFORM SIGN GA2 T" +
"IMES GARCUNEIFORM SIGN GA2 TIMES GICUNEIFORM SIGN GA2 TIMES GI4CUNEIFORM" +
" SIGN GA2 TIMES GI4 PLUS ACUNEIFORM SIGN GA2 TIMES GIR2 PLUS SUCUNEIFORM" +
" SIGN GA2 TIMES HA PLUS LU PLUS ESH2CUNEIFORM SIGN GA2 TIMES HALCUNEIFOR" +
"M SIGN GA2 TIMES HAL PLUS LACUNEIFORM SIGN GA2 TIMES HI PLUS LICUNEIFORM" +
" SIGN GA2 TIMES HUB2CUNEIFORM SIGN GA2 TIMES IGI GUNUCUNEIFORM SIGN GA2 " +
"TIMES ISH PLUS HU PLUS ASHCUNEIFORM SIGN GA2 TIMES KAKCUNEIFORM SIGN GA2" +
" TIMES KASKALCUNEIFORM SIGN GA2 TIMES KIDCUNEIFORM SIGN GA2 TIMES KID PL" +
"US LALCUNEIFORM SIGN GA2 TIMES KU3 PLUS ANCUNEIFORM SIGN GA2 TIMES LACUN" +
"EIFORM SIGN GA2 TIMES ME PLUS ENCUNEIFORM SIGN GA2 TIMES MICUNEIFORM SIG" +
"N GA2 TIMES NUNCUNEIFORM SIGN GA2 TIMES NUN OVER NUNCUNEIFORM SIGN GA2 T" +
"IMES PACUNEIFORM SIGN GA2 TIMES SALCUNEIFORM SIGN GA2 TIMES SARCUNEIFORM" +
" SIGN GA2 TIMES SHECUNEIFORM SIGN GA2 TIMES SHE PLUS TURCUNEIFORM SIGN G" +
"A2 TIMES SHIDCUNEIFORM SIGN GA2 TIMES SUMCUNEIFORM SIGN GA2 TIMES TAK4CU" +
"NEIFORM SIGN GA2 TIMES UCUNEIFORM SIGN GA2 TIMES UDCUNEIFORM SIGN GA2 TI" +
"MES UD PLUS DUCUNEIFORM SIGN GA2 OVER GA2CUNEIFORM SIGN GABACUNEIFORM SI" +
"GN GABA CROSSING GABACUNEIFORM SIGN GADCUNEIFORM SIGN GAD OVER GAD GAR O" +
"VER GARCUNEIFORM SIGN GALCUNEIFORM SIGN GAL GAD OVER GAD GAR OVER GARCUN" +
"EIFORM SIGN GALAMCUNEIFORM SIGN GAMCUNEIFORM SIGN GANCUNEIFORM SIGN GAN2" +
"CUNEIFORM SIGN GAN2 TENUCUNEIFORM SIGN GAN2 OVER GAN2CUNEIFORM SIGN GAN2" +
" CROSSING GAN2CUNEIFORM SIGN GARCUNEIFORM SIGN GAR3CUNEIFORM SIGN GASHAN" +
"CUNEIFORM SIGN GESHTINCUNEIFORM SIGN GESHTIN TIMES KURCUNEIFORM SIGN GIC" +
"UNEIFORM SIGN GI TIMES ECUNEIFORM SIGN GI TIMES UCUNEIFORM SIGN GI CROSS" +
"ING GICUNEIFORM SIGN GI4CUNEIFORM SIGN GI4 OVER GI4CUNEIFORM SIGN GI4 CR" +
"OSSING GI4CUNEIFORM SIGN GIDIMCUNEIFORM SIGN GIR2CUNEIFORM SIGN GIR2 GUN" +
"UCUNEIFORM SIGN GIR3CUNEIFORM SIGN GIR3 TIMES A PLUS IGICUNEIFORM SIGN G" +
"IR3 TIMES GAN2 TENUCUNEIFORM SIGN GIR3 TIMES IGICUNEIFORM SIGN GIR3 TIME" +
"S LU PLUS IGICUNEIFORM SIGN GIR3 TIMES PACUNEIFORM SIGN GISALCUNEIFORM S" +
"IGN GISHCUNEIFORM SIGN GISH CROSSING GISHCUNEIFORM SIGN GISH TIMES BADCU" +
"NEIFORM SIGN GISH TIMES TAK4CUNEIFORM SIGN GISH TENUCUNEIFORM SIGN GUCUN" +
"EIFORM SIGN GU CROSSING GUCUNEIFORM SIGN GU2CUNEIFORM SIGN GU2 TIMES KAK" +
"CUNEIFORM SIGN GU2 TIMES KAK TIMES IGI GUNUCUNEIFORM SIGN GU2 TIMES NUNC" +
"UNEIFORM SIGN GU2 TIMES SAL PLUS TUG2CUNEIFORM SIGN GU2 GUNUCUNEIFORM SI" +
"GN GUDCUNEIFORM SIGN GUD TIMES A PLUS KURCUNEIFORM SIGN GUD TIMES KURCUN" +
"EIFORM SIGN GUD OVER GUD LUGALCUNEIFORM SIGN GULCUNEIFORM SIGN GUMCUNEIF" +
"ORM SIGN GUM TIMES SHECUNEIFORM SIGN GURCUNEIFORM SIGN GUR7CUNEIFORM SIG" +
"N GURUNCUNEIFORM SIGN GURUSHCUNEIFORM SIGN HACUNEIFORM SIGN HA TENUCUNEI" +
"FORM SIGN HA GUNUCUNEIFORM SIGN HALCUNEIFORM SIGN HICUNEIFORM SIGN HI TI" +
"MES ASHCUNEIFORM SIGN HI TIMES ASH2CUNEIFORM SIGN HI TIMES BADCUNEIFORM " +
"SIGN HI TIMES DISHCUNEIFORM SIGN HI TIMES GADCUNEIFORM SIGN HI TIMES KIN" +
"CUNEIFORM SIGN HI TIMES NUNCUNEIFORM SIGN HI TIMES SHECUNEIFORM SIGN HI " +
"TIMES UCUNEIFORM SIGN HUCUNEIFORM SIGN HUB2CUNEIFORM SIGN HUB2 TIMES ANC" +
"UNEIFORM SIGN HUB2 TIMES HALCUNEIFORM SIGN HUB2 TIMES KASKALCUNEIFORM SI" +
"GN HUB2 TIMES LISHCUNEIFORM SIGN HUB2 TIMES UDCUNEIFORM SIGN HUL2CUNEIFO" +
"RM SIGN ICUNEIFORM SIGN I ACUNEIFORM SIGN IBCUNEIFORM SIGN IDIMCUNEIFORM" +
" SIGN IDIM OVER IDIM BURCUNEIFORM SIGN IDIM OVER IDIM SQUAREDCUNEIFORM S" +
"IGN IGCUNEIFORM SIGN IGICUNEIFORM SIGN IGI DIBCUNEIFORM SIGN IGI RICUNEI" +
"FORM SIGN IGI OVER IGI SHIR OVER SHIR UD OVER UDCUNEIFORM SIGN IGI GUNUC" +
"UNEIFORM SIGN ILCUNEIFORM SIGN IL TIMES GAN2 TENUCUNEIFORM SIGN IL2CUNEI") + ("" +
"FORM SIGN IMCUNEIFORM SIGN IM TIMES TAK4CUNEIFORM SIGN IM CROSSING IMCUN" +
"EIFORM SIGN IM OPPOSING IMCUNEIFORM SIGN IM SQUAREDCUNEIFORM SIGN IMINCU" +
"NEIFORM SIGN INCUNEIFORM SIGN IRCUNEIFORM SIGN ISHCUNEIFORM SIGN KACUNEI" +
"FORM SIGN KA TIMES ACUNEIFORM SIGN KA TIMES ADCUNEIFORM SIGN KA TIMES AD" +
" PLUS KU3CUNEIFORM SIGN KA TIMES ASH2CUNEIFORM SIGN KA TIMES BADCUNEIFOR" +
"M SIGN KA TIMES BALAGCUNEIFORM SIGN KA TIMES BARCUNEIFORM SIGN KA TIMES " +
"BICUNEIFORM SIGN KA TIMES ERIN2CUNEIFORM SIGN KA TIMES ESH2CUNEIFORM SIG" +
"N KA TIMES GACUNEIFORM SIGN KA TIMES GALCUNEIFORM SIGN KA TIMES GAN2 TEN" +
"UCUNEIFORM SIGN KA TIMES GARCUNEIFORM SIGN KA TIMES GAR PLUS SHA3 PLUS A" +
"CUNEIFORM SIGN KA TIMES GICUNEIFORM SIGN KA TIMES GIR2CUNEIFORM SIGN KA " +
"TIMES GISH PLUS SARCUNEIFORM SIGN KA TIMES GISH CROSSING GISHCUNEIFORM S" +
"IGN KA TIMES GUCUNEIFORM SIGN KA TIMES GUR7CUNEIFORM SIGN KA TIMES IGICU" +
"NEIFORM SIGN KA TIMES IMCUNEIFORM SIGN KA TIMES KAKCUNEIFORM SIGN KA TIM" +
"ES KICUNEIFORM SIGN KA TIMES KIDCUNEIFORM SIGN KA TIMES LICUNEIFORM SIGN" +
" KA TIMES LUCUNEIFORM SIGN KA TIMES MECUNEIFORM SIGN KA TIMES ME PLUS DU" +
"CUNEIFORM SIGN KA TIMES ME PLUS GICUNEIFORM SIGN KA TIMES ME PLUS TECUNE" +
"IFORM SIGN KA TIMES MICUNEIFORM SIGN KA TIMES MI PLUS NUNUZCUNEIFORM SIG" +
"N KA TIMES NECUNEIFORM SIGN KA TIMES NUNCUNEIFORM SIGN KA TIMES PICUNEIF" +
"ORM SIGN KA TIMES RUCUNEIFORM SIGN KA TIMES SACUNEIFORM SIGN KA TIMES SA" +
"RCUNEIFORM SIGN KA TIMES SHACUNEIFORM SIGN KA TIMES SHECUNEIFORM SIGN KA" +
" TIMES SHIDCUNEIFORM SIGN KA TIMES SHUCUNEIFORM SIGN KA TIMES SIGCUNEIFO" +
"RM SIGN KA TIMES SUHURCUNEIFORM SIGN KA TIMES TARCUNEIFORM SIGN KA TIMES" +
" UCUNEIFORM SIGN KA TIMES U2CUNEIFORM SIGN KA TIMES UDCUNEIFORM SIGN KA " +
"TIMES UMUM TIMES PACUNEIFORM SIGN KA TIMES USHCUNEIFORM SIGN KA TIMES ZI" +
"CUNEIFORM SIGN KA2CUNEIFORM SIGN KA2 CROSSING KA2CUNEIFORM SIGN KABCUNEI" +
"FORM SIGN KAD2CUNEIFORM SIGN KAD3CUNEIFORM SIGN KAD4CUNEIFORM SIGN KAD5C" +
"UNEIFORM SIGN KAD5 OVER KAD5CUNEIFORM SIGN KAKCUNEIFORM SIGN KAK TIMES I" +
"GI GUNUCUNEIFORM SIGN KALCUNEIFORM SIGN KAL TIMES BADCUNEIFORM SIGN KAL " +
"CROSSING KALCUNEIFORM SIGN KAM2CUNEIFORM SIGN KAM4CUNEIFORM SIGN KASKALC" +
"UNEIFORM SIGN KASKAL LAGAB TIMES U OVER LAGAB TIMES UCUNEIFORM SIGN KASK" +
"AL OVER KASKAL LAGAB TIMES U OVER LAGAB TIMES UCUNEIFORM SIGN KESH2CUNEI" +
"FORM SIGN KICUNEIFORM SIGN KI TIMES BADCUNEIFORM SIGN KI TIMES UCUNEIFOR" +
"M SIGN KI TIMES UDCUNEIFORM SIGN KIDCUNEIFORM SIGN KINCUNEIFORM SIGN KIS" +
"ALCUNEIFORM SIGN KISHCUNEIFORM SIGN KISIM5CUNEIFORM SIGN KISIM5 OVER KIS" +
"IM5CUNEIFORM SIGN KUCUNEIFORM SIGN KU OVER HI TIMES ASH2 KU OVER HI TIME" +
"S ASH2CUNEIFORM SIGN KU3CUNEIFORM SIGN KU4CUNEIFORM SIGN KU4 VARIANT FOR" +
"MCUNEIFORM SIGN KU7CUNEIFORM SIGN KULCUNEIFORM SIGN KUL GUNUCUNEIFORM SI" +
"GN KUNCUNEIFORM SIGN KURCUNEIFORM SIGN KUR OPPOSING KURCUNEIFORM SIGN KU" +
"SHU2CUNEIFORM SIGN KWU318CUNEIFORM SIGN LACUNEIFORM SIGN LAGABCUNEIFORM " +
"SIGN LAGAB TIMES ACUNEIFORM SIGN LAGAB TIMES A PLUS DA PLUS HACUNEIFORM " +
"SIGN LAGAB TIMES A PLUS GARCUNEIFORM SIGN LAGAB TIMES A PLUS LALCUNEIFOR" +
"M SIGN LAGAB TIMES ALCUNEIFORM SIGN LAGAB TIMES ANCUNEIFORM SIGN LAGAB T" +
"IMES ASH ZIDA TENUCUNEIFORM SIGN LAGAB TIMES BADCUNEIFORM SIGN LAGAB TIM" +
"ES BICUNEIFORM SIGN LAGAB TIMES DARCUNEIFORM SIGN LAGAB TIMES ENCUNEIFOR" +
"M SIGN LAGAB TIMES GACUNEIFORM SIGN LAGAB TIMES GARCUNEIFORM SIGN LAGAB " +
"TIMES GUDCUNEIFORM SIGN LAGAB TIMES GUD PLUS GUDCUNEIFORM SIGN LAGAB TIM" +
"ES HACUNEIFORM SIGN LAGAB TIMES HALCUNEIFORM SIGN LAGAB TIMES HI TIMES N" +
"UNCUNEIFORM SIGN LAGAB TIMES IGI GUNUCUNEIFORM SIGN LAGAB TIMES IMCUNEIF" +
"ORM SIGN LAGAB TIMES IM PLUS HACUNEIFORM SIGN LAGAB TIMES IM PLUS LUCUNE" +
"IFORM SIGN LAGAB TIMES KICUNEIFORM SIGN LAGAB TIMES KINCUNEIFORM SIGN LA" +
"GAB TIMES KU3CUNEIFORM SIGN LAGAB TIMES KULCUNEIFORM SIGN LAGAB TIMES KU" +
"L PLUS HI PLUS ACUNEIFORM SIGN LAGAB TIMES LAGABCUNEIFORM SIGN LAGAB TIM" +
"ES LISHCUNEIFORM SIGN LAGAB TIMES LUCUNEIFORM SIGN LAGAB TIMES LULCUNEIF" +
"ORM SIGN LAGAB TIMES MECUNEIFORM SIGN LAGAB TIMES ME PLUS ENCUNEIFORM SI" +
"GN LAGAB TIMES MUSHCUNEIFORM SIGN LAGAB TIMES NECUNEIFORM SIGN LAGAB TIM" +
"ES SHE PLUS SUMCUNEIFORM SIGN LAGAB TIMES SHITA PLUS GISH PLUS ERIN2CUNE" +
"IFORM SIGN LAGAB TIMES SHITA PLUS GISH TENUCUNEIFORM SIGN LAGAB TIMES SH" +
"U2CUNEIFORM SIGN LAGAB TIMES SHU2 PLUS SHU2CUNEIFORM SIGN LAGAB TIMES SU" +
"MCUNEIFORM SIGN LAGAB TIMES TAGCUNEIFORM SIGN LAGAB TIMES TAK4CUNEIFORM " +
"SIGN LAGAB TIMES TE PLUS A PLUS SU PLUS NACUNEIFORM SIGN LAGAB TIMES UCU" +
"NEIFORM SIGN LAGAB TIMES U PLUS ACUNEIFORM SIGN LAGAB TIMES U PLUS U PLU" +
"S UCUNEIFORM SIGN LAGAB TIMES U2 PLUS ASHCUNEIFORM SIGN LAGAB TIMES UDCU" +
"NEIFORM SIGN LAGAB TIMES USHCUNEIFORM SIGN LAGAB SQUAREDCUNEIFORM SIGN L" +
"AGARCUNEIFORM SIGN LAGAR TIMES SHECUNEIFORM SIGN LAGAR TIMES SHE PLUS SU") + ("" +
"MCUNEIFORM SIGN LAGAR GUNUCUNEIFORM SIGN LAGAR GUNU OVER LAGAR GUNU SHEC" +
"UNEIFORM SIGN LAHSHUCUNEIFORM SIGN LALCUNEIFORM SIGN LAL TIMES LALCUNEIF" +
"ORM SIGN LAMCUNEIFORM SIGN LAM TIMES KURCUNEIFORM SIGN LAM TIMES KUR PLU" +
"S RUCUNEIFORM SIGN LICUNEIFORM SIGN LILCUNEIFORM SIGN LIMMU2CUNEIFORM SI" +
"GN LISHCUNEIFORM SIGN LUCUNEIFORM SIGN LU TIMES BADCUNEIFORM SIGN LU2CUN" +
"EIFORM SIGN LU2 TIMES ALCUNEIFORM SIGN LU2 TIMES BADCUNEIFORM SIGN LU2 T" +
"IMES ESH2CUNEIFORM SIGN LU2 TIMES ESH2 TENUCUNEIFORM SIGN LU2 TIMES GAN2" +
" TENUCUNEIFORM SIGN LU2 TIMES HI TIMES BADCUNEIFORM SIGN LU2 TIMES IMCUN" +
"EIFORM SIGN LU2 TIMES KAD2CUNEIFORM SIGN LU2 TIMES KAD3CUNEIFORM SIGN LU" +
"2 TIMES KAD3 PLUS ASHCUNEIFORM SIGN LU2 TIMES KICUNEIFORM SIGN LU2 TIMES" +
" LA PLUS ASHCUNEIFORM SIGN LU2 TIMES LAGABCUNEIFORM SIGN LU2 TIMES ME PL" +
"US ENCUNEIFORM SIGN LU2 TIMES NECUNEIFORM SIGN LU2 TIMES NUCUNEIFORM SIG" +
"N LU2 TIMES SI PLUS ASHCUNEIFORM SIGN LU2 TIMES SIK2 PLUS BUCUNEIFORM SI" +
"GN LU2 TIMES TUG2CUNEIFORM SIGN LU2 TENUCUNEIFORM SIGN LU2 CROSSING LU2C" +
"UNEIFORM SIGN LU2 OPPOSING LU2CUNEIFORM SIGN LU2 SQUAREDCUNEIFORM SIGN L" +
"U2 SHESHIGCUNEIFORM SIGN LU3CUNEIFORM SIGN LUGALCUNEIFORM SIGN LUGAL OVE" +
"R LUGALCUNEIFORM SIGN LUGAL OPPOSING LUGALCUNEIFORM SIGN LUGAL SHESHIGCU" +
"NEIFORM SIGN LUHCUNEIFORM SIGN LULCUNEIFORM SIGN LUMCUNEIFORM SIGN LUM O" +
"VER LUMCUNEIFORM SIGN LUM OVER LUM GAR OVER GARCUNEIFORM SIGN MACUNEIFOR" +
"M SIGN MA TIMES TAK4CUNEIFORM SIGN MA GUNUCUNEIFORM SIGN MA2CUNEIFORM SI" +
"GN MAHCUNEIFORM SIGN MARCUNEIFORM SIGN MASHCUNEIFORM SIGN MASH2CUNEIFORM" +
" SIGN MECUNEIFORM SIGN MESCUNEIFORM SIGN MICUNEIFORM SIGN MINCUNEIFORM S" +
"IGN MUCUNEIFORM SIGN MU OVER MUCUNEIFORM SIGN MUGCUNEIFORM SIGN MUG GUNU" +
"CUNEIFORM SIGN MUNSUBCUNEIFORM SIGN MURGU2CUNEIFORM SIGN MUSHCUNEIFORM S" +
"IGN MUSH TIMES ACUNEIFORM SIGN MUSH TIMES KURCUNEIFORM SIGN MUSH TIMES Z" +
"ACUNEIFORM SIGN MUSH OVER MUSHCUNEIFORM SIGN MUSH OVER MUSH TIMES A PLUS" +
" NACUNEIFORM SIGN MUSH CROSSING MUSHCUNEIFORM SIGN MUSH3CUNEIFORM SIGN M" +
"USH3 TIMES ACUNEIFORM SIGN MUSH3 TIMES A PLUS DICUNEIFORM SIGN MUSH3 TIM" +
"ES DICUNEIFORM SIGN MUSH3 GUNUCUNEIFORM SIGN NACUNEIFORM SIGN NA2CUNEIFO" +
"RM SIGN NAGACUNEIFORM SIGN NAGA INVERTEDCUNEIFORM SIGN NAGA TIMES SHU TE" +
"NUCUNEIFORM SIGN NAGA OPPOSING NAGACUNEIFORM SIGN NAGARCUNEIFORM SIGN NA" +
"M NUTILLUCUNEIFORM SIGN NAMCUNEIFORM SIGN NAM2CUNEIFORM SIGN NECUNEIFORM" +
" SIGN NE TIMES ACUNEIFORM SIGN NE TIMES UDCUNEIFORM SIGN NE SHESHIGCUNEI" +
"FORM SIGN NICUNEIFORM SIGN NI TIMES ECUNEIFORM SIGN NI2CUNEIFORM SIGN NI" +
"MCUNEIFORM SIGN NIM TIMES GAN2 TENUCUNEIFORM SIGN NIM TIMES GAR PLUS GAN" +
"2 TENUCUNEIFORM SIGN NINDA2CUNEIFORM SIGN NINDA2 TIMES ANCUNEIFORM SIGN " +
"NINDA2 TIMES ASHCUNEIFORM SIGN NINDA2 TIMES ASH PLUS ASHCUNEIFORM SIGN N" +
"INDA2 TIMES GUDCUNEIFORM SIGN NINDA2 TIMES ME PLUS GAN2 TENUCUNEIFORM SI" +
"GN NINDA2 TIMES NECUNEIFORM SIGN NINDA2 TIMES NUNCUNEIFORM SIGN NINDA2 T" +
"IMES SHECUNEIFORM SIGN NINDA2 TIMES SHE PLUS A ANCUNEIFORM SIGN NINDA2 T" +
"IMES SHE PLUS ASHCUNEIFORM SIGN NINDA2 TIMES SHE PLUS ASH PLUS ASHCUNEIF" +
"ORM SIGN NINDA2 TIMES U2 PLUS ASHCUNEIFORM SIGN NINDA2 TIMES USHCUNEIFOR" +
"M SIGN NISAGCUNEIFORM SIGN NUCUNEIFORM SIGN NU11CUNEIFORM SIGN NUNCUNEIF" +
"ORM SIGN NUN LAGAR TIMES GARCUNEIFORM SIGN NUN LAGAR TIMES MASHCUNEIFORM" +
" SIGN NUN LAGAR TIMES SALCUNEIFORM SIGN NUN LAGAR TIMES SAL OVER NUN LAG" +
"AR TIMES SALCUNEIFORM SIGN NUN LAGAR TIMES USHCUNEIFORM SIGN NUN TENUCUN" +
"EIFORM SIGN NUN OVER NUNCUNEIFORM SIGN NUN CROSSING NUNCUNEIFORM SIGN NU" +
"N CROSSING NUN LAGAR OVER LAGARCUNEIFORM SIGN NUNUZCUNEIFORM SIGN NUNUZ " +
"AB2 TIMES ASHGABCUNEIFORM SIGN NUNUZ AB2 TIMES BICUNEIFORM SIGN NUNUZ AB" +
"2 TIMES DUGCUNEIFORM SIGN NUNUZ AB2 TIMES GUDCUNEIFORM SIGN NUNUZ AB2 TI" +
"MES IGI GUNUCUNEIFORM SIGN NUNUZ AB2 TIMES KAD3CUNEIFORM SIGN NUNUZ AB2 " +
"TIMES LACUNEIFORM SIGN NUNUZ AB2 TIMES NECUNEIFORM SIGN NUNUZ AB2 TIMES " +
"SILA3CUNEIFORM 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 SIG" +
"N PICUNEIFORM SIGN PI TIMES ACUNEIFORM SIGN PI TIMES ABCUNEIFORM SIGN PI" +
" TIMES BICUNEIFORM SIGN PI TIMES BUCUNEIFORM SIGN PI TIMES ECUNEIFORM SI" +
"GN PI TIMES ICUNEIFORM SIGN PI TIMES IBCUNEIFORM SIGN PI TIMES UCUNEIFOR" +
"M SIGN PI TIMES U2CUNEIFORM SIGN PI CROSSING PICUNEIFORM SIGN PIRIGCUNEI" +
"FORM SIGN PIRIG TIMES KALCUNEIFORM SIGN PIRIG TIMES UDCUNEIFORM SIGN PIR" +
"IG TIMES ZACUNEIFORM SIGN PIRIG OPPOSING PIRIGCUNEIFORM SIGN RACUNEIFORM" +
" SIGN RABCUNEIFORM SIGN RICUNEIFORM SIGN RUCUNEIFORM SIGN SACUNEIFORM SI" +
"GN SAG NUTILLUCUNEIFORM SIGN SAGCUNEIFORM SIGN SAG TIMES ACUNEIFORM SIGN" +
" SAG TIMES DUCUNEIFORM SIGN SAG TIMES DUBCUNEIFORM SIGN SAG TIMES HACUNE") + ("" +
"IFORM SIGN SAG TIMES KAKCUNEIFORM SIGN SAG TIMES KURCUNEIFORM SIGN SAG T" +
"IMES LUMCUNEIFORM SIGN SAG TIMES MICUNEIFORM SIGN SAG TIMES NUNCUNEIFORM" +
" SIGN SAG TIMES SALCUNEIFORM SIGN SAG TIMES SHIDCUNEIFORM SIGN SAG TIMES" +
" TABCUNEIFORM SIGN SAG TIMES U2CUNEIFORM SIGN SAG TIMES UBCUNEIFORM SIGN" +
" SAG TIMES UMCUNEIFORM SIGN SAG TIMES URCUNEIFORM SIGN SAG TIMES USHCUNE" +
"IFORM SIGN SAG OVER SAGCUNEIFORM SIGN SAG GUNUCUNEIFORM SIGN SALCUNEIFOR" +
"M SIGN SAL LAGAB TIMES ASH2CUNEIFORM SIGN SANGA2CUNEIFORM SIGN SARCUNEIF" +
"ORM SIGN SHACUNEIFORM SIGN SHA3CUNEIFORM SIGN SHA3 TIMES ACUNEIFORM SIGN" +
" SHA3 TIMES BADCUNEIFORM SIGN SHA3 TIMES GISHCUNEIFORM SIGN SHA3 TIMES N" +
"ECUNEIFORM SIGN SHA3 TIMES SHU2CUNEIFORM SIGN SHA3 TIMES TURCUNEIFORM SI" +
"GN SHA3 TIMES UCUNEIFORM SIGN SHA3 TIMES U PLUS ACUNEIFORM SIGN SHA6CUNE" +
"IFORM SIGN SHAB6CUNEIFORM SIGN SHAR2CUNEIFORM SIGN SHECUNEIFORM SIGN SHE" +
" HUCUNEIFORM SIGN SHE OVER SHE GAD OVER GAD GAR OVER GARCUNEIFORM SIGN S" +
"HE OVER SHE TAB OVER TAB GAR OVER GARCUNEIFORM SIGN SHEG9CUNEIFORM SIGN " +
"SHENCUNEIFORM SIGN SHESHCUNEIFORM SIGN SHESH2CUNEIFORM SIGN SHESHLAMCUNE" +
"IFORM SIGN SHIDCUNEIFORM SIGN SHID TIMES ACUNEIFORM SIGN SHID TIMES IMCU" +
"NEIFORM SIGN SHIMCUNEIFORM SIGN SHIM TIMES ACUNEIFORM SIGN SHIM TIMES BA" +
"LCUNEIFORM SIGN SHIM TIMES BULUGCUNEIFORM SIGN SHIM TIMES DINCUNEIFORM S" +
"IGN SHIM TIMES GARCUNEIFORM SIGN SHIM TIMES IGICUNEIFORM SIGN SHIM TIMES" +
" IGI GUNUCUNEIFORM SIGN SHIM TIMES KUSHU2CUNEIFORM SIGN SHIM TIMES LULCU" +
"NEIFORM SIGN SHIM TIMES MUGCUNEIFORM SIGN SHIM TIMES SALCUNEIFORM SIGN S" +
"HINIGCUNEIFORM SIGN SHIRCUNEIFORM SIGN SHIR TENUCUNEIFORM SIGN SHIR OVER" +
" SHIR BUR OVER BURCUNEIFORM SIGN SHITACUNEIFORM SIGN SHUCUNEIFORM SIGN S" +
"HU OVER INVERTED SHUCUNEIFORM SIGN SHU2CUNEIFORM SIGN SHUBURCUNEIFORM SI" +
"GN SICUNEIFORM SIGN SI GUNUCUNEIFORM SIGN SIGCUNEIFORM SIGN SIG4CUNEIFOR" +
"M SIGN SIG4 OVER SIG4 SHU2CUNEIFORM SIGN SIK2CUNEIFORM SIGN SILA3CUNEIFO" +
"RM SIGN SUCUNEIFORM SIGN SU OVER SUCUNEIFORM SIGN SUDCUNEIFORM SIGN SUD2" +
"CUNEIFORM SIGN SUHURCUNEIFORM SIGN SUMCUNEIFORM SIGN SUMASHCUNEIFORM SIG" +
"N SURCUNEIFORM SIGN SUR9CUNEIFORM SIGN TACUNEIFORM SIGN TA ASTERISKCUNEI" +
"FORM SIGN TA TIMES HICUNEIFORM SIGN TA TIMES MICUNEIFORM SIGN TA GUNUCUN" +
"EIFORM SIGN TABCUNEIFORM SIGN TAB OVER TAB NI OVER NI DISH OVER DISHCUNE" +
"IFORM SIGN TAB SQUAREDCUNEIFORM SIGN TAGCUNEIFORM SIGN TAG TIMES BICUNEI" +
"FORM SIGN TAG TIMES GUDCUNEIFORM SIGN TAG TIMES SHECUNEIFORM SIGN TAG TI" +
"MES SHUCUNEIFORM SIGN TAG TIMES TUG2CUNEIFORM SIGN TAG TIMES UDCUNEIFORM" +
" SIGN TAK4CUNEIFORM SIGN TARCUNEIFORM SIGN TECUNEIFORM SIGN TE GUNUCUNEI" +
"FORM SIGN TICUNEIFORM SIGN TI TENUCUNEIFORM SIGN TILCUNEIFORM SIGN TIRCU" +
"NEIFORM SIGN TIR TIMES TAK4CUNEIFORM SIGN TIR OVER TIRCUNEIFORM SIGN TIR" +
" OVER TIR GAD OVER GAD GAR OVER GARCUNEIFORM SIGN TUCUNEIFORM SIGN TUG2C" +
"UNEIFORM SIGN 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 SURCUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSEDCUNEIFOR" +
"M SIGN U2CUNEIFORM SIGN UBCUNEIFORM SIGN UDCUNEIFORM SIGN UD KUSHU2CUNEI" +
"FORM SIGN UD TIMES BADCUNEIFORM SIGN UD TIMES MICUNEIFORM SIGN UD TIMES " +
"U PLUS U PLUS UCUNEIFORM SIGN UD TIMES U PLUS U PLUS U GUNUCUNEIFORM SIG" +
"N UD GUNUCUNEIFORM SIGN UD SHESHIGCUNEIFORM SIGN UD SHESHIG TIMES BADCUN" +
"EIFORM SIGN UDUGCUNEIFORM SIGN UMCUNEIFORM SIGN UM TIMES LAGABCUNEIFORM " +
"SIGN UM TIMES ME PLUS DACUNEIFORM SIGN UM TIMES SHA3CUNEIFORM SIGN UM TI" +
"MES UCUNEIFORM SIGN UMBINCUNEIFORM SIGN UMUMCUNEIFORM SIGN UMUM TIMES KA" +
"SKALCUNEIFORM SIGN UMUM TIMES PACUNEIFORM SIGN UNCUNEIFORM SIGN UN GUNUC" +
"UNEIFORM SIGN URCUNEIFORM SIGN UR CROSSING URCUNEIFORM SIGN UR SHESHIGCU" +
"NEIFORM SIGN UR2CUNEIFORM SIGN UR2 TIMES A PLUS HACUNEIFORM SIGN UR2 TIM" +
"ES A PLUS NACUNEIFORM SIGN UR2 TIMES ALCUNEIFORM SIGN UR2 TIMES HACUNEIF" +
"ORM SIGN UR2 TIMES NUNCUNEIFORM SIGN UR2 TIMES U2CUNEIFORM SIGN UR2 TIME" +
"S U2 PLUS ASHCUNEIFORM SIGN UR2 TIMES U2 PLUS BICUNEIFORM SIGN UR4CUNEIF" +
"ORM SIGN URICUNEIFORM SIGN URI3CUNEIFORM SIGN URUCUNEIFORM SIGN URU TIME" +
"S ACUNEIFORM SIGN URU TIMES ASHGABCUNEIFORM SIGN URU TIMES BARCUNEIFORM " +
"SIGN URU TIMES DUNCUNEIFORM SIGN URU TIMES GACUNEIFORM SIGN URU TIMES GA" +
"LCUNEIFORM SIGN URU TIMES GAN2 TENUCUNEIFORM SIGN URU TIMES GARCUNEIFORM" +
" SIGN URU TIMES GUCUNEIFORM SIGN URU TIMES HACUNEIFORM SIGN URU TIMES IG" +
"ICUNEIFORM SIGN URU TIMES IMCUNEIFORM SIGN URU TIMES ISHCUNEIFORM SIGN U" +
"RU TIMES KICUNEIFORM SIGN URU TIMES LUMCUNEIFORM SIGN URU TIMES MINCUNEI" +
"FORM SIGN URU TIMES PACUNEIFORM SIGN URU TIMES SHECUNEIFORM SIGN URU TIM" +
"ES SIG4CUNEIFORM SIGN URU TIMES TUCUNEIFORM SIGN URU TIMES U PLUS GUDCUN") + ("" +
"EIFORM SIGN URU TIMES UDCUNEIFORM SIGN URU TIMES URUDACUNEIFORM SIGN URU" +
"DACUNEIFORM SIGN URUDA TIMES UCUNEIFORM SIGN USHCUNEIFORM SIGN USH TIMES" +
" ACUNEIFORM SIGN USH TIMES KUCUNEIFORM SIGN USH TIMES KURCUNEIFORM SIGN " +
"USH TIMES TAK4CUNEIFORM SIGN USHXCUNEIFORM SIGN USH2CUNEIFORM SIGN USHUM" +
"XCUNEIFORM SIGN UTUKICUNEIFORM SIGN UZ3CUNEIFORM SIGN UZ3 TIMES KASKALCU" +
"NEIFORM SIGN UZUCUNEIFORM SIGN ZACUNEIFORM SIGN ZA TENUCUNEIFORM SIGN ZA" +
" SQUARED TIMES KURCUNEIFORM SIGN ZAGCUNEIFORM SIGN ZAMXCUNEIFORM SIGN ZE" +
"2CUNEIFORM SIGN ZICUNEIFORM SIGN ZI OVER ZICUNEIFORM SIGN ZI3CUNEIFORM S" +
"IGN ZIBCUNEIFORM SIGN ZIB KABA TENUCUNEIFORM SIGN ZIGCUNEIFORM SIGN ZIZ2" +
"CUNEIFORM SIGN ZUCUNEIFORM SIGN ZU5CUNEIFORM SIGN ZU5 TIMES ACUNEIFORM S" +
"IGN ZUBURCUNEIFORM SIGN ZUMCUNEIFORM SIGN KAP ELAMITECUNEIFORM SIGN AB T" +
"IMES NUNCUNEIFORM SIGN AB2 TIMES ACUNEIFORM SIGN AMAR TIMES KUGCUNEIFORM" +
" SIGN DAG KISIM5 TIMES U2 PLUS MASHCUNEIFORM SIGN DAG3CUNEIFORM SIGN DIS" +
"H PLUS SHUCUNEIFORM SIGN DUB TIMES SHECUNEIFORM SIGN EZEN TIMES GUDCUNEI" +
"FORM SIGN EZEN TIMES SHECUNEIFORM SIGN GA2 TIMES AN PLUS KAK PLUS ACUNEI" +
"FORM SIGN GA2 TIMES ASH2CUNEIFORM SIGN GE22CUNEIFORM SIGN GIGCUNEIFORM S" +
"IGN HUSHCUNEIFORM SIGN KA TIMES ANSHECUNEIFORM SIGN KA TIMES ASH3CUNEIFO" +
"RM SIGN KA TIMES GISHCUNEIFORM SIGN KA TIMES GUDCUNEIFORM SIGN KA TIMES " +
"HI TIMES ASH2CUNEIFORM SIGN KA TIMES LUMCUNEIFORM SIGN KA TIMES PACUNEIF" +
"ORM SIGN KA TIMES SHULCUNEIFORM SIGN KA TIMES TUCUNEIFORM SIGN KA TIMES " +
"UR2CUNEIFORM SIGN LAGAB TIMES GICUNEIFORM SIGN LU2 SHESHIG TIMES BADCUNE" +
"IFORM SIGN LU2 TIMES ESH2 PLUS LALCUNEIFORM SIGN LU2 TIMES SHUCUNEIFORM " +
"SIGN MESHCUNEIFORM SIGN MUSH3 TIMES ZACUNEIFORM SIGN NA4CUNEIFORM SIGN N" +
"INCUNEIFORM SIGN NIN9CUNEIFORM SIGN NINDA2 TIMES BALCUNEIFORM SIGN NINDA" +
"2 TIMES GICUNEIFORM SIGN NU11 ROTATED NINETY DEGREESCUNEIFORM SIGN PESH2" +
" ASTERISKCUNEIFORM SIGN PIR2CUNEIFORM SIGN SAG TIMES IGI GUNUCUNEIFORM S" +
"IGN TI2CUNEIFORM SIGN UM TIMES MECUNEIFORM SIGN U UCUNEIFORM NUMERIC SIG" +
"N TWO ASHCUNEIFORM NUMERIC SIGN THREE ASHCUNEIFORM NUMERIC SIGN FOUR ASH" +
"CUNEIFORM NUMERIC SIGN FIVE ASHCUNEIFORM NUMERIC SIGN SIX ASHCUNEIFORM N" +
"UMERIC SIGN SEVEN ASHCUNEIFORM NUMERIC SIGN EIGHT ASHCUNEIFORM NUMERIC S" +
"IGN NINE ASHCUNEIFORM NUMERIC SIGN THREE DISHCUNEIFORM NUMERIC SIGN FOUR" +
" DISHCUNEIFORM NUMERIC SIGN FIVE DISHCUNEIFORM NUMERIC SIGN SIX DISHCUNE" +
"IFORM NUMERIC SIGN SEVEN DISHCUNEIFORM NUMERIC SIGN EIGHT DISHCUNEIFORM " +
"NUMERIC SIGN NINE DISHCUNEIFORM NUMERIC SIGN FOUR UCUNEIFORM NUMERIC SIG" +
"N FIVE UCUNEIFORM NUMERIC SIGN SIX UCUNEIFORM NUMERIC SIGN SEVEN UCUNEIF" +
"ORM NUMERIC SIGN EIGHT UCUNEIFORM NUMERIC SIGN NINE UCUNEIFORM NUMERIC S" +
"IGN ONE GESH2CUNEIFORM NUMERIC SIGN TWO GESH2CUNEIFORM NUMERIC SIGN THRE" +
"E GESH2CUNEIFORM NUMERIC SIGN FOUR GESH2CUNEIFORM NUMERIC SIGN FIVE GESH" +
"2CUNEIFORM NUMERIC SIGN SIX GESH2CUNEIFORM NUMERIC SIGN SEVEN GESH2CUNEI" +
"FORM NUMERIC SIGN EIGHT GESH2CUNEIFORM NUMERIC SIGN NINE GESH2CUNEIFORM " +
"NUMERIC SIGN ONE GESHUCUNEIFORM NUMERIC SIGN TWO GESHUCUNEIFORM NUMERIC " +
"SIGN THREE GESHUCUNEIFORM NUMERIC SIGN FOUR GESHUCUNEIFORM NUMERIC SIGN " +
"FIVE GESHUCUNEIFORM NUMERIC SIGN TWO SHAR2CUNEIFORM NUMERIC SIGN THREE S" +
"HAR2CUNEIFORM NUMERIC SIGN THREE SHAR2 VARIANT FORMCUNEIFORM NUMERIC SIG" +
"N FOUR SHAR2CUNEIFORM NUMERIC SIGN FIVE SHAR2CUNEIFORM NUMERIC SIGN SIX " +
"SHAR2CUNEIFORM NUMERIC SIGN SEVEN SHAR2CUNEIFORM NUMERIC SIGN EIGHT SHAR" +
"2CUNEIFORM NUMERIC SIGN NINE SHAR2CUNEIFORM NUMERIC SIGN ONE SHARUCUNEIF" +
"ORM NUMERIC SIGN TWO SHARUCUNEIFORM NUMERIC SIGN THREE SHARUCUNEIFORM NU" +
"MERIC SIGN THREE SHARU VARIANT FORMCUNEIFORM NUMERIC SIGN FOUR SHARUCUNE" +
"IFORM NUMERIC SIGN FIVE SHARUCUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS" +
" DISHCUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MINCUNEIFORM NUMERIC SI" +
"GN ONE BURUCUNEIFORM NUMERIC SIGN TWO BURUCUNEIFORM NUMERIC SIGN THREE B" +
"URUCUNEIFORM NUMERIC SIGN THREE BURU VARIANT FORMCUNEIFORM NUMERIC SIGN " +
"FOUR BURUCUNEIFORM NUMERIC SIGN FIVE BURUCUNEIFORM NUMERIC SIGN THREE VA" +
"RIANT FORM ESH16CUNEIFORM NUMERIC SIGN THREE VARIANT FORM ESH21CUNEIFORM" +
" NUMERIC SIGN FOUR VARIANT FORM LIMMUCUNEIFORM NUMERIC SIGN FOUR VARIANT" +
" FORM LIMMU4CUNEIFORM NUMERIC SIGN FOUR VARIANT FORM LIMMU ACUNEIFORM NU" +
"MERIC SIGN FOUR VARIANT FORM LIMMU BCUNEIFORM NUMERIC SIGN SIX VARIANT F" +
"ORM ASH9CUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM IMIN3CUNEIFORM NUMERIC" +
" SIGN SEVEN VARIANT FORM IMIN ACUNEIFORM NUMERIC SIGN SEVEN VARIANT FORM" +
" IMIN BCUNEIFORM NUMERIC SIGN EIGHT VARIANT FORM USSUCUNEIFORM NUMERIC S" +
"IGN EIGHT VARIANT FORM USSU3CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILI" +
"MMUCUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIMMU3CUNEIFORM NUMERIC SIG" +
"N NINE VARIANT FORM ILIMMU4CUNEIFORM NUMERIC SIGN NINE VARIANT FORM ILIM") + ("" +
"MU ACUNEIFORM NUMERIC SIGN TWO ASH TENUCUNEIFORM NUMERIC SIGN THREE ASH " +
"TENUCUNEIFORM NUMERIC SIGN FOUR ASH TENUCUNEIFORM NUMERIC SIGN FIVE ASH " +
"TENUCUNEIFORM NUMERIC SIGN SIX ASH TENUCUNEIFORM NUMERIC SIGN ONE BAN2CU" +
"NEIFORM NUMERIC SIGN TWO BAN2CUNEIFORM NUMERIC SIGN THREE BAN2CUNEIFORM " +
"NUMERIC SIGN FOUR BAN2CUNEIFORM NUMERIC SIGN FOUR BAN2 VARIANT FORMCUNEI" +
"FORM NUMERIC SIGN FIVE BAN2CUNEIFORM NUMERIC SIGN FIVE BAN2 VARIANT FORM" +
"CUNEIFORM NUMERIC SIGN NIGIDAMINCUNEIFORM NUMERIC SIGN NIGIDAESHCUNEIFOR" +
"M NUMERIC SIGN ONE ESHE3CUNEIFORM NUMERIC SIGN TWO ESHE3CUNEIFORM NUMERI" +
"C SIGN ONE THIRD DISHCUNEIFORM NUMERIC SIGN TWO THIRDS DISHCUNEIFORM NUM" +
"ERIC SIGN FIVE SIXTHS DISHCUNEIFORM NUMERIC SIGN ONE THIRD VARIANT FORM " +
"ACUNEIFORM NUMERIC SIGN TWO THIRDS VARIANT FORM ACUNEIFORM NUMERIC SIGN " +
"ONE EIGHTH ASHCUNEIFORM NUMERIC SIGN ONE QUARTER ASHCUNEIFORM NUMERIC SI" +
"GN OLD ASSYRIAN ONE SIXTHCUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER" +
"CUNEIFORM NUMERIC SIGN ONE QUARTER GURCUNEIFORM NUMERIC SIGN ONE HALF GU" +
"RCUNEIFORM NUMERIC SIGN ELAMITE ONE THIRDCUNEIFORM NUMERIC SIGN ELAMITE " +
"TWO THIRDSCUNEIFORM NUMERIC SIGN ELAMITE FORTYCUNEIFORM NUMERIC SIGN ELA" +
"MITE FIFTYCUNEIFORM NUMERIC SIGN FOUR U VARIANT FORMCUNEIFORM NUMERIC SI" +
"GN FIVE U VARIANT FORMCUNEIFORM NUMERIC SIGN SIX U VARIANT FORMCUNEIFORM" +
" NUMERIC SIGN SEVEN U VARIANT FORMCUNEIFORM NUMERIC SIGN EIGHT U VARIANT" +
" FORMCUNEIFORM NUMERIC SIGN NINE U VARIANT FORMCUNEIFORM PUNCTUATION SIG" +
"N OLD ASSYRIAN WORD DIVIDERCUNEIFORM PUNCTUATION SIGN VERTICAL COLONCUNE" +
"IFORM PUNCTUATION SIGN DIAGONAL COLONCUNEIFORM PUNCTUATION SIGN DIAGONAL" +
" TRICOLONCUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLONCUNEIFORM SIGN AB " +
"TIMES NUN TENUCUNEIFORM SIGN AB TIMES SHU2CUNEIFORM SIGN AD TIMES ESH2CU" +
"NEIFORM SIGN BAD TIMES DISH TENUCUNEIFORM SIGN BAHAR2 TIMES AB2CUNEIFORM" +
" SIGN BAHAR2 TIMES NICUNEIFORM SIGN BAHAR2 TIMES ZACUNEIFORM SIGN BU OVE" +
"R BU TIMES NA2CUNEIFORM SIGN DA TIMES TAK4CUNEIFORM SIGN DAG TIMES KURCU" +
"NEIFORM SIGN DIM TIMES IGICUNEIFORM SIGN DIM TIMES U U UCUNEIFORM SIGN D" +
"IM2 TIMES UDCUNEIFORM SIGN DUG TIMES ANSHECUNEIFORM SIGN DUG TIMES ASHCU" +
"NEIFORM SIGN DUG TIMES ASH AT LEFTCUNEIFORM SIGN DUG TIMES DINCUNEIFORM " +
"SIGN DUG TIMES DUNCUNEIFORM SIGN DUG TIMES ERIN2CUNEIFORM SIGN DUG TIMES" +
" GACUNEIFORM SIGN DUG TIMES GICUNEIFORM SIGN DUG TIMES GIR2 GUNUCUNEIFOR" +
"M SIGN DUG TIMES GISHCUNEIFORM SIGN DUG TIMES HACUNEIFORM SIGN DUG TIMES" +
" HICUNEIFORM SIGN DUG TIMES IGI GUNUCUNEIFORM SIGN DUG TIMES KASKALCUNEI" +
"FORM SIGN DUG TIMES KURCUNEIFORM SIGN DUG TIMES KUSHU2CUNEIFORM SIGN DUG" +
" TIMES KUSHU2 PLUS KASKALCUNEIFORM SIGN DUG TIMES LAK-020CUNEIFORM SIGN " +
"DUG TIMES LAMCUNEIFORM SIGN DUG TIMES LAM TIMES KURCUNEIFORM SIGN DUG TI" +
"MES LUH PLUS GISHCUNEIFORM SIGN DUG TIMES MASHCUNEIFORM SIGN DUG TIMES M" +
"ESCUNEIFORM SIGN DUG TIMES MICUNEIFORM SIGN DUG TIMES NICUNEIFORM SIGN D" +
"UG TIMES PICUNEIFORM SIGN DUG TIMES SHECUNEIFORM SIGN DUG TIMES SI GUNUC" +
"UNEIFORM SIGN E2 TIMES KURCUNEIFORM SIGN E2 TIMES PAPCUNEIFORM SIGN ERIN" +
"2 XCUNEIFORM SIGN ESH2 CROSSING ESH2CUNEIFORM SIGN EZEN SHESHIG TIMES AS" +
"HCUNEIFORM SIGN EZEN SHESHIG TIMES HICUNEIFORM SIGN EZEN SHESHIG TIMES I" +
"GI GUNUCUNEIFORM SIGN EZEN SHESHIG TIMES LACUNEIFORM SIGN EZEN SHESHIG T" +
"IMES LALCUNEIFORM SIGN EZEN SHESHIG TIMES MECUNEIFORM SIGN EZEN SHESHIG " +
"TIMES MESCUNEIFORM SIGN EZEN SHESHIG TIMES SUCUNEIFORM SIGN EZEN TIMES S" +
"UCUNEIFORM SIGN GA2 TIMES BAHAR2CUNEIFORM SIGN GA2 TIMES DIM GUNUCUNEIFO" +
"RM SIGN GA2 TIMES DUG TIMES IGI GUNUCUNEIFORM SIGN GA2 TIMES DUG TIMES K" +
"ASKALCUNEIFORM SIGN GA2 TIMES ERENCUNEIFORM SIGN GA2 TIMES GACUNEIFORM S" +
"IGN GA2 TIMES GAR PLUS DICUNEIFORM SIGN GA2 TIMES GAR PLUS NECUNEIFORM S" +
"IGN GA2 TIMES HA PLUS ACUNEIFORM SIGN GA2 TIMES KUSHU2 PLUS KASKALCUNEIF" +
"ORM SIGN GA2 TIMES LAMCUNEIFORM SIGN GA2 TIMES LAM TIMES KURCUNEIFORM SI" +
"GN GA2 TIMES LUHCUNEIFORM SIGN GA2 TIMES MUSHCUNEIFORM SIGN GA2 TIMES NE" +
"CUNEIFORM SIGN GA2 TIMES NE PLUS E2CUNEIFORM SIGN GA2 TIMES NE PLUS GICU" +
"NEIFORM SIGN GA2 TIMES SHIMCUNEIFORM SIGN GA2 TIMES ZIZ2CUNEIFORM SIGN G" +
"ABA ROTATED NINETY DEGREESCUNEIFORM SIGN GESHTIN TIMES UCUNEIFORM SIGN G" +
"ISH TIMES GISH CROSSING GISHCUNEIFORM SIGN GU2 TIMES IGI GUNUCUNEIFORM S" +
"IGN GUD PLUS GISH TIMES TAK4CUNEIFORM SIGN HA TENU GUNUCUNEIFORM SIGN HI" +
" TIMES ASH OVER HI TIMES ASHCUNEIFORM SIGN KA TIMES BUCUNEIFORM SIGN KA " +
"TIMES KACUNEIFORM SIGN KA TIMES U U UCUNEIFORM SIGN KA TIMES URCUNEIFORM" +
" SIGN LAGAB TIMES ZU OVER ZUCUNEIFORM SIGN LAK-003CUNEIFORM SIGN LAK-021" +
"CUNEIFORM SIGN LAK-025CUNEIFORM SIGN LAK-030CUNEIFORM SIGN LAK-050CUNEIF" +
"ORM SIGN LAK-051CUNEIFORM SIGN LAK-062CUNEIFORM SIGN LAK-079 OVER LAK-07" +
"9 GUNUCUNEIFORM SIGN LAK-080CUNEIFORM SIGN LAK-081 OVER LAK-081CUNEIFORM") + ("" +
" SIGN LAK-092CUNEIFORM SIGN LAK-130CUNEIFORM SIGN LAK-142CUNEIFORM SIGN " +
"LAK-210CUNEIFORM SIGN LAK-219CUNEIFORM SIGN LAK-220CUNEIFORM SIGN LAK-22" +
"5CUNEIFORM SIGN LAK-228CUNEIFORM SIGN LAK-238CUNEIFORM SIGN LAK-265CUNEI" +
"FORM SIGN LAK-266CUNEIFORM SIGN LAK-343CUNEIFORM SIGN LAK-347CUNEIFORM S" +
"IGN LAK-348CUNEIFORM SIGN LAK-383CUNEIFORM SIGN LAK-384CUNEIFORM SIGN LA" +
"K-390CUNEIFORM SIGN LAK-441CUNEIFORM SIGN LAK-449CUNEIFORM SIGN LAK-449 " +
"TIMES GUCUNEIFORM SIGN LAK-449 TIMES IGICUNEIFORM SIGN LAK-449 TIMES PAP" +
" PLUS LU3CUNEIFORM SIGN LAK-449 TIMES PAP PLUS PAP PLUS LU3CUNEIFORM SIG" +
"N LAK-449 TIMES U2 PLUS BACUNEIFORM SIGN LAK-450CUNEIFORM SIGN LAK-457CU" +
"NEIFORM SIGN LAK-470CUNEIFORM SIGN LAK-483CUNEIFORM SIGN LAK-490CUNEIFOR" +
"M SIGN LAK-492CUNEIFORM SIGN LAK-493CUNEIFORM SIGN LAK-495CUNEIFORM SIGN" +
" LAK-550CUNEIFORM SIGN LAK-608CUNEIFORM SIGN LAK-617CUNEIFORM SIGN LAK-6" +
"17 TIMES ASHCUNEIFORM SIGN LAK-617 TIMES BADCUNEIFORM SIGN LAK-617 TIMES" +
" DUN3 GUNU GUNUCUNEIFORM SIGN LAK-617 TIMES KU3CUNEIFORM SIGN LAK-617 TI" +
"MES LACUNEIFORM SIGN LAK-617 TIMES TARCUNEIFORM SIGN LAK-617 TIMES TECUN" +
"EIFORM SIGN LAK-617 TIMES U2CUNEIFORM SIGN LAK-617 TIMES UDCUNEIFORM SIG" +
"N LAK-617 TIMES URUDACUNEIFORM SIGN LAK-636CUNEIFORM SIGN LAK-648CUNEIFO" +
"RM SIGN LAK-648 TIMES DUBCUNEIFORM SIGN LAK-648 TIMES GACUNEIFORM SIGN L" +
"AK-648 TIMES IGICUNEIFORM SIGN LAK-648 TIMES IGI GUNUCUNEIFORM SIGN LAK-" +
"648 TIMES NICUNEIFORM SIGN LAK-648 TIMES PAP PLUS PAP PLUS LU3CUNEIFORM " +
"SIGN LAK-648 TIMES SHESH PLUS KICUNEIFORM SIGN LAK-648 TIMES UDCUNEIFORM" +
" SIGN LAK-648 TIMES URUDACUNEIFORM SIGN LAK-724CUNEIFORM SIGN LAK-749CUN" +
"EIFORM SIGN LU2 GUNU TIMES ASHCUNEIFORM SIGN LU2 TIMES DISHCUNEIFORM SIG" +
"N LU2 TIMES HALCUNEIFORM SIGN LU2 TIMES PAPCUNEIFORM SIGN LU2 TIMES PAP " +
"PLUS PAP PLUS LU3CUNEIFORM SIGN LU2 TIMES TAK4CUNEIFORM SIGN MI PLUS ZA7" +
"CUNEIFORM SIGN MUSH OVER MUSH TIMES GACUNEIFORM SIGN MUSH OVER MUSH TIME" +
"S KAKCUNEIFORM SIGN NINDA2 TIMES DIM GUNUCUNEIFORM SIGN NINDA2 TIMES GIS" +
"HCUNEIFORM SIGN NINDA2 TIMES GULCUNEIFORM SIGN NINDA2 TIMES HICUNEIFORM " +
"SIGN NINDA2 TIMES KESH2CUNEIFORM SIGN NINDA2 TIMES LAK-050CUNEIFORM SIGN" +
" NINDA2 TIMES MASHCUNEIFORM SIGN NINDA2 TIMES PAP PLUS PAPCUNEIFORM SIGN" +
" NINDA2 TIMES UCUNEIFORM SIGN NINDA2 TIMES U PLUS UCUNEIFORM SIGN NINDA2" +
" TIMES URUDACUNEIFORM SIGN SAG GUNU TIMES HACUNEIFORM SIGN SAG TIMES ENC" +
"UNEIFORM SIGN SAG TIMES SHE AT LEFTCUNEIFORM SIGN SAG TIMES TAK4CUNEIFOR" +
"M SIGN SHA6 TENUCUNEIFORM SIGN SHE OVER SHECUNEIFORM SIGN SHE PLUS HUB2C" +
"UNEIFORM SIGN SHE PLUS NAM2CUNEIFORM SIGN SHE PLUS SARCUNEIFORM SIGN SHU" +
"2 PLUS DUG TIMES NICUNEIFORM SIGN SHU2 PLUS E2 TIMES ANCUNEIFORM SIGN SI" +
" TIMES TAK4CUNEIFORM SIGN TAK4 PLUS SAGCUNEIFORM SIGN TUM TIMES GAN2 TEN" +
"UCUNEIFORM SIGN TUM TIMES THREE DISHCUNEIFORM SIGN UR2 INVERTEDCUNEIFORM" +
" SIGN UR2 TIMES UDCUNEIFORM SIGN URU TIMES DARA3CUNEIFORM SIGN URU TIMES" +
" LAK-668CUNEIFORM SIGN URU TIMES LU3CUNEIFORM SIGN ZA7CUNEIFORM SIGN ZU " +
"OVER ZU PLUS SARCUNEIFORM SIGN ZU5 TIMES THREE DISH TENUCYPRO-MINOAN SIG" +
"N CM001CYPRO-MINOAN SIGN CM002CYPRO-MINOAN SIGN CM004CYPRO-MINOAN SIGN C" +
"M005CYPRO-MINOAN SIGN CM006CYPRO-MINOAN SIGN CM007CYPRO-MINOAN SIGN CM00" +
"8CYPRO-MINOAN SIGN CM009CYPRO-MINOAN SIGN CM010CYPRO-MINOAN SIGN CM011CY" +
"PRO-MINOAN SIGN CM012CYPRO-MINOAN SIGN CM012BCYPRO-MINOAN SIGN CM013CYPR" +
"O-MINOAN SIGN CM015CYPRO-MINOAN SIGN CM017CYPRO-MINOAN SIGN CM019CYPRO-M" +
"INOAN SIGN CM021CYPRO-MINOAN SIGN CM023CYPRO-MINOAN SIGN CM024CYPRO-MINO" +
"AN SIGN CM025CYPRO-MINOAN SIGN CM026CYPRO-MINOAN SIGN CM027CYPRO-MINOAN " +
"SIGN CM028CYPRO-MINOAN SIGN CM029CYPRO-MINOAN SIGN CM030CYPRO-MINOAN SIG" +
"N CM033CYPRO-MINOAN SIGN CM034CYPRO-MINOAN SIGN CM035CYPRO-MINOAN SIGN C" +
"M036CYPRO-MINOAN SIGN CM037CYPRO-MINOAN SIGN CM038CYPRO-MINOAN SIGN CM03" +
"9CYPRO-MINOAN SIGN CM040CYPRO-MINOAN SIGN CM041CYPRO-MINOAN SIGN CM044CY" +
"PRO-MINOAN SIGN CM046CYPRO-MINOAN SIGN CM047CYPRO-MINOAN SIGN CM049CYPRO" +
"-MINOAN SIGN CM050CYPRO-MINOAN SIGN CM051CYPRO-MINOAN SIGN CM052CYPRO-MI" +
"NOAN SIGN CM053CYPRO-MINOAN SIGN CM054CYPRO-MINOAN SIGN CM055CYPRO-MINOA" +
"N SIGN CM056CYPRO-MINOAN SIGN CM058CYPRO-MINOAN SIGN CM059CYPRO-MINOAN S" +
"IGN CM060CYPRO-MINOAN SIGN CM061CYPRO-MINOAN SIGN CM062CYPRO-MINOAN SIGN" +
" CM063CYPRO-MINOAN SIGN CM064CYPRO-MINOAN SIGN CM066CYPRO-MINOAN SIGN CM" +
"067CYPRO-MINOAN SIGN CM068CYPRO-MINOAN SIGN CM069CYPRO-MINOAN SIGN CM070" +
"CYPRO-MINOAN SIGN CM071CYPRO-MINOAN SIGN CM072CYPRO-MINOAN SIGN CM073CYP" +
"RO-MINOAN SIGN CM074CYPRO-MINOAN SIGN CM075CYPRO-MINOAN SIGN CM075BCYPRO" +
"-MINOAN SIGN CM076CYPRO-MINOAN SIGN CM078CYPRO-MINOAN SIGN CM079CYPRO-MI" +
"NOAN SIGN CM080CYPRO-MINOAN SIGN CM081CYPRO-MINOAN SIGN CM082CYPRO-MINOA" +
"N SIGN CM083CYPRO-MINOAN SIGN CM084CYPRO-MINOAN SIGN CM085CYPRO-MINOAN S") + ("" +
"IGN CM086CYPRO-MINOAN SIGN CM087CYPRO-MINOAN SIGN CM088CYPRO-MINOAN SIGN" +
" CM089CYPRO-MINOAN SIGN CM090CYPRO-MINOAN SIGN CM091CYPRO-MINOAN SIGN CM" +
"092CYPRO-MINOAN SIGN CM094CYPRO-MINOAN SIGN CM095CYPRO-MINOAN SIGN CM096" +
"CYPRO-MINOAN SIGN CM097CYPRO-MINOAN SIGN CM098CYPRO-MINOAN SIGN CM099CYP" +
"RO-MINOAN SIGN CM100CYPRO-MINOAN SIGN CM101CYPRO-MINOAN SIGN CM102CYPRO-" +
"MINOAN SIGN CM103CYPRO-MINOAN SIGN CM104CYPRO-MINOAN SIGN CM105CYPRO-MIN" +
"OAN SIGN CM107CYPRO-MINOAN SIGN CM108CYPRO-MINOAN SIGN CM109CYPRO-MINOAN" +
" SIGN CM110CYPRO-MINOAN SIGN CM112CYPRO-MINOAN SIGN CM114CYPRO-MINOAN SI" +
"GN CM301CYPRO-MINOAN SIGN CM302EGYPTIAN HIEROGLYPH A001EGYPTIAN HIEROGLY" +
"PH A002EGYPTIAN HIEROGLYPH A003EGYPTIAN HIEROGLYPH A004EGYPTIAN HIEROGLY" +
"PH A005EGYPTIAN HIEROGLYPH A005AEGYPTIAN HIEROGLYPH A006EGYPTIAN HIEROGL" +
"YPH A006AEGYPTIAN HIEROGLYPH A006BEGYPTIAN HIEROGLYPH A007EGYPTIAN HIERO" +
"GLYPH A008EGYPTIAN HIEROGLYPH A009EGYPTIAN HIEROGLYPH A010EGYPTIAN HIERO" +
"GLYPH A011EGYPTIAN HIEROGLYPH A012EGYPTIAN HIEROGLYPH A013EGYPTIAN HIERO" +
"GLYPH A014EGYPTIAN HIEROGLYPH A014AEGYPTIAN HIEROGLYPH A015EGYPTIAN HIER" +
"OGLYPH A016EGYPTIAN HIEROGLYPH A017EGYPTIAN HIEROGLYPH A017AEGYPTIAN HIE" +
"ROGLYPH A018EGYPTIAN HIEROGLYPH A019EGYPTIAN HIEROGLYPH A020EGYPTIAN HIE" +
"ROGLYPH A021EGYPTIAN HIEROGLYPH A022EGYPTIAN HIEROGLYPH A023EGYPTIAN HIE" +
"ROGLYPH A024EGYPTIAN HIEROGLYPH A025EGYPTIAN HIEROGLYPH A026EGYPTIAN HIE" +
"ROGLYPH A027EGYPTIAN HIEROGLYPH A028EGYPTIAN HIEROGLYPH A029EGYPTIAN HIE" +
"ROGLYPH A030EGYPTIAN HIEROGLYPH A031EGYPTIAN HIEROGLYPH A032EGYPTIAN HIE" +
"ROGLYPH A032AEGYPTIAN HIEROGLYPH A033EGYPTIAN HIEROGLYPH A034EGYPTIAN HI" +
"EROGLYPH A035EGYPTIAN HIEROGLYPH A036EGYPTIAN HIEROGLYPH A037EGYPTIAN HI" +
"EROGLYPH A038EGYPTIAN HIEROGLYPH A039EGYPTIAN HIEROGLYPH A040EGYPTIAN HI" +
"EROGLYPH A040AEGYPTIAN HIEROGLYPH A041EGYPTIAN HIEROGLYPH A042EGYPTIAN H" +
"IEROGLYPH A042AEGYPTIAN HIEROGLYPH A043EGYPTIAN HIEROGLYPH A043AEGYPTIAN" +
" HIEROGLYPH A044EGYPTIAN HIEROGLYPH A045EGYPTIAN HIEROGLYPH A045AEGYPTIA" +
"N HIEROGLYPH A046EGYPTIAN HIEROGLYPH A047EGYPTIAN HIEROGLYPH A048EGYPTIA" +
"N HIEROGLYPH A049EGYPTIAN HIEROGLYPH A050EGYPTIAN HIEROGLYPH A051EGYPTIA" +
"N HIEROGLYPH A052EGYPTIAN HIEROGLYPH A053EGYPTIAN HIEROGLYPH A054EGYPTIA" +
"N HIEROGLYPH A055EGYPTIAN HIEROGLYPH A056EGYPTIAN HIEROGLYPH A057EGYPTIA" +
"N HIEROGLYPH A058EGYPTIAN HIEROGLYPH A059EGYPTIAN HIEROGLYPH A060EGYPTIA" +
"N HIEROGLYPH A061EGYPTIAN HIEROGLYPH A062EGYPTIAN HIEROGLYPH A063EGYPTIA" +
"N HIEROGLYPH A064EGYPTIAN HIEROGLYPH A065EGYPTIAN HIEROGLYPH A066EGYPTIA" +
"N HIEROGLYPH A067EGYPTIAN HIEROGLYPH A068EGYPTIAN HIEROGLYPH A069EGYPTIA" +
"N HIEROGLYPH A070EGYPTIAN HIEROGLYPH B001EGYPTIAN HIEROGLYPH B002EGYPTIA" +
"N HIEROGLYPH B003EGYPTIAN HIEROGLYPH B004EGYPTIAN HIEROGLYPH B005EGYPTIA" +
"N HIEROGLYPH B005AEGYPTIAN HIEROGLYPH B006EGYPTIAN HIEROGLYPH B007EGYPTI" +
"AN HIEROGLYPH B008EGYPTIAN HIEROGLYPH B009EGYPTIAN HIEROGLYPH C001EGYPTI" +
"AN HIEROGLYPH C002EGYPTIAN HIEROGLYPH C002AEGYPTIAN HIEROGLYPH C002BEGYP" +
"TIAN HIEROGLYPH C002CEGYPTIAN HIEROGLYPH C003EGYPTIAN HIEROGLYPH C004EGY" +
"PTIAN HIEROGLYPH C005EGYPTIAN HIEROGLYPH C006EGYPTIAN HIEROGLYPH C007EGY" +
"PTIAN HIEROGLYPH C008EGYPTIAN HIEROGLYPH C009EGYPTIAN HIEROGLYPH C010EGY" +
"PTIAN HIEROGLYPH C010AEGYPTIAN HIEROGLYPH C011EGYPTIAN HIEROGLYPH C012EG" +
"YPTIAN HIEROGLYPH C013EGYPTIAN HIEROGLYPH C014EGYPTIAN HIEROGLYPH C015EG" +
"YPTIAN HIEROGLYPH C016EGYPTIAN HIEROGLYPH C017EGYPTIAN HIEROGLYPH C018EG" +
"YPTIAN HIEROGLYPH C019EGYPTIAN HIEROGLYPH C020EGYPTIAN HIEROGLYPH C021EG" +
"YPTIAN HIEROGLYPH C022EGYPTIAN HIEROGLYPH C023EGYPTIAN HIEROGLYPH C024EG" +
"YPTIAN HIEROGLYPH D001EGYPTIAN HIEROGLYPH D002EGYPTIAN HIEROGLYPH D003EG" +
"YPTIAN HIEROGLYPH D004EGYPTIAN HIEROGLYPH D005EGYPTIAN HIEROGLYPH D006EG" +
"YPTIAN HIEROGLYPH D007EGYPTIAN HIEROGLYPH D008EGYPTIAN HIEROGLYPH D008AE" +
"GYPTIAN HIEROGLYPH D009EGYPTIAN HIEROGLYPH D010EGYPTIAN HIEROGLYPH D011E" +
"GYPTIAN HIEROGLYPH D012EGYPTIAN HIEROGLYPH D013EGYPTIAN HIEROGLYPH D014E" +
"GYPTIAN HIEROGLYPH D015EGYPTIAN HIEROGLYPH D016EGYPTIAN HIEROGLYPH D017E" +
"GYPTIAN HIEROGLYPH D018EGYPTIAN HIEROGLYPH D019EGYPTIAN HIEROGLYPH D020E" +
"GYPTIAN HIEROGLYPH D021EGYPTIAN HIEROGLYPH D022EGYPTIAN HIEROGLYPH D023E" +
"GYPTIAN HIEROGLYPH D024EGYPTIAN HIEROGLYPH D025EGYPTIAN HIEROGLYPH D026E" +
"GYPTIAN HIEROGLYPH D027EGYPTIAN HIEROGLYPH D027AEGYPTIAN HIEROGLYPH D028" +
"EGYPTIAN HIEROGLYPH D029EGYPTIAN HIEROGLYPH D030EGYPTIAN HIEROGLYPH D031" +
"EGYPTIAN HIEROGLYPH D031AEGYPTIAN HIEROGLYPH D032EGYPTIAN HIEROGLYPH D03" +
"3EGYPTIAN HIEROGLYPH D034EGYPTIAN HIEROGLYPH D034AEGYPTIAN HIEROGLYPH D0" +
"35EGYPTIAN HIEROGLYPH D036EGYPTIAN HIEROGLYPH D037EGYPTIAN HIEROGLYPH D0" +
"38EGYPTIAN HIEROGLYPH D039EGYPTIAN HIEROGLYPH D040EGYPTIAN HIEROGLYPH D0" +
"41EGYPTIAN HIEROGLYPH D042EGYPTIAN HIEROGLYPH D043EGYPTIAN HIEROGLYPH D0") + ("" +
"44EGYPTIAN HIEROGLYPH D045EGYPTIAN HIEROGLYPH D046EGYPTIAN HIEROGLYPH D0" +
"46AEGYPTIAN HIEROGLYPH D047EGYPTIAN HIEROGLYPH D048EGYPTIAN HIEROGLYPH D" +
"048AEGYPTIAN HIEROGLYPH D049EGYPTIAN HIEROGLYPH D050EGYPTIAN HIEROGLYPH " +
"D050AEGYPTIAN HIEROGLYPH D050BEGYPTIAN HIEROGLYPH D050CEGYPTIAN HIEROGLY" +
"PH D050DEGYPTIAN HIEROGLYPH D050EEGYPTIAN HIEROGLYPH D050FEGYPTIAN HIERO" +
"GLYPH D050GEGYPTIAN HIEROGLYPH D050HEGYPTIAN HIEROGLYPH D050IEGYPTIAN HI" +
"EROGLYPH D051EGYPTIAN HIEROGLYPH D052EGYPTIAN HIEROGLYPH D052AEGYPTIAN H" +
"IEROGLYPH D053EGYPTIAN HIEROGLYPH D054EGYPTIAN HIEROGLYPH D054AEGYPTIAN " +
"HIEROGLYPH D055EGYPTIAN HIEROGLYPH D056EGYPTIAN HIEROGLYPH D057EGYPTIAN " +
"HIEROGLYPH D058EGYPTIAN HIEROGLYPH D059EGYPTIAN HIEROGLYPH D060EGYPTIAN " +
"HIEROGLYPH D061EGYPTIAN HIEROGLYPH D062EGYPTIAN HIEROGLYPH D063EGYPTIAN " +
"HIEROGLYPH D064EGYPTIAN HIEROGLYPH D065EGYPTIAN HIEROGLYPH D066EGYPTIAN " +
"HIEROGLYPH D067EGYPTIAN HIEROGLYPH D067AEGYPTIAN HIEROGLYPH D067BEGYPTIA" +
"N HIEROGLYPH D067CEGYPTIAN HIEROGLYPH D067DEGYPTIAN HIEROGLYPH D067EEGYP" +
"TIAN HIEROGLYPH D067FEGYPTIAN HIEROGLYPH D067GEGYPTIAN HIEROGLYPH D067HE" +
"GYPTIAN HIEROGLYPH E001EGYPTIAN HIEROGLYPH E002EGYPTIAN HIEROGLYPH E003E" +
"GYPTIAN HIEROGLYPH E004EGYPTIAN HIEROGLYPH E005EGYPTIAN HIEROGLYPH E006E" +
"GYPTIAN HIEROGLYPH E007EGYPTIAN HIEROGLYPH E008EGYPTIAN HIEROGLYPH E008A" +
"EGYPTIAN HIEROGLYPH E009EGYPTIAN HIEROGLYPH E009AEGYPTIAN HIEROGLYPH E01" +
"0EGYPTIAN HIEROGLYPH E011EGYPTIAN HIEROGLYPH E012EGYPTIAN HIEROGLYPH E01" +
"3EGYPTIAN HIEROGLYPH E014EGYPTIAN HIEROGLYPH E015EGYPTIAN HIEROGLYPH E01" +
"6EGYPTIAN HIEROGLYPH E016AEGYPTIAN HIEROGLYPH E017EGYPTIAN HIEROGLYPH E0" +
"17AEGYPTIAN HIEROGLYPH E018EGYPTIAN HIEROGLYPH E019EGYPTIAN HIEROGLYPH E" +
"020EGYPTIAN HIEROGLYPH E020AEGYPTIAN HIEROGLYPH E021EGYPTIAN HIEROGLYPH " +
"E022EGYPTIAN HIEROGLYPH E023EGYPTIAN HIEROGLYPH E024EGYPTIAN HIEROGLYPH " +
"E025EGYPTIAN HIEROGLYPH E026EGYPTIAN HIEROGLYPH E027EGYPTIAN HIEROGLYPH " +
"E028EGYPTIAN HIEROGLYPH E028AEGYPTIAN HIEROGLYPH E029EGYPTIAN HIEROGLYPH" +
" E030EGYPTIAN HIEROGLYPH E031EGYPTIAN HIEROGLYPH E032EGYPTIAN HIEROGLYPH" +
" E033EGYPTIAN HIEROGLYPH E034EGYPTIAN HIEROGLYPH E034AEGYPTIAN HIEROGLYP" +
"H E036EGYPTIAN HIEROGLYPH E037EGYPTIAN HIEROGLYPH E038EGYPTIAN HIEROGLYP" +
"H F001EGYPTIAN HIEROGLYPH F001AEGYPTIAN HIEROGLYPH F002EGYPTIAN HIEROGLY" +
"PH F003EGYPTIAN HIEROGLYPH F004EGYPTIAN HIEROGLYPH F005EGYPTIAN HIEROGLY" +
"PH F006EGYPTIAN HIEROGLYPH F007EGYPTIAN HIEROGLYPH F008EGYPTIAN HIEROGLY" +
"PH F009EGYPTIAN HIEROGLYPH F010EGYPTIAN HIEROGLYPH F011EGYPTIAN HIEROGLY" +
"PH F012EGYPTIAN HIEROGLYPH F013EGYPTIAN HIEROGLYPH F013AEGYPTIAN HIEROGL" +
"YPH F014EGYPTIAN HIEROGLYPH F015EGYPTIAN HIEROGLYPH F016EGYPTIAN HIEROGL" +
"YPH F017EGYPTIAN HIEROGLYPH F018EGYPTIAN HIEROGLYPH F019EGYPTIAN HIEROGL" +
"YPH F020EGYPTIAN HIEROGLYPH F021EGYPTIAN HIEROGLYPH F021AEGYPTIAN HIEROG" +
"LYPH F022EGYPTIAN HIEROGLYPH F023EGYPTIAN HIEROGLYPH F024EGYPTIAN HIEROG" +
"LYPH F025EGYPTIAN HIEROGLYPH F026EGYPTIAN HIEROGLYPH F027EGYPTIAN HIEROG" +
"LYPH F028EGYPTIAN HIEROGLYPH F029EGYPTIAN HIEROGLYPH F030EGYPTIAN HIEROG" +
"LYPH F031EGYPTIAN HIEROGLYPH F031AEGYPTIAN HIEROGLYPH F032EGYPTIAN HIERO" +
"GLYPH F033EGYPTIAN HIEROGLYPH F034EGYPTIAN HIEROGLYPH F035EGYPTIAN HIERO" +
"GLYPH F036EGYPTIAN HIEROGLYPH F037EGYPTIAN HIEROGLYPH F037AEGYPTIAN HIER" +
"OGLYPH F038EGYPTIAN HIEROGLYPH F038AEGYPTIAN HIEROGLYPH F039EGYPTIAN HIE" +
"ROGLYPH F040EGYPTIAN HIEROGLYPH F041EGYPTIAN HIEROGLYPH F042EGYPTIAN HIE" +
"ROGLYPH F043EGYPTIAN HIEROGLYPH F044EGYPTIAN HIEROGLYPH F045EGYPTIAN HIE" +
"ROGLYPH F045AEGYPTIAN HIEROGLYPH F046EGYPTIAN HIEROGLYPH F046AEGYPTIAN H" +
"IEROGLYPH F047EGYPTIAN HIEROGLYPH F047AEGYPTIAN HIEROGLYPH F048EGYPTIAN " +
"HIEROGLYPH F049EGYPTIAN HIEROGLYPH F050EGYPTIAN HIEROGLYPH F051EGYPTIAN " +
"HIEROGLYPH F051AEGYPTIAN HIEROGLYPH F051BEGYPTIAN HIEROGLYPH F051CEGYPTI" +
"AN HIEROGLYPH F052EGYPTIAN HIEROGLYPH F053EGYPTIAN HIEROGLYPH G001EGYPTI" +
"AN HIEROGLYPH G002EGYPTIAN HIEROGLYPH G003EGYPTIAN HIEROGLYPH G004EGYPTI" +
"AN HIEROGLYPH G005EGYPTIAN HIEROGLYPH G006EGYPTIAN HIEROGLYPH G006AEGYPT" +
"IAN HIEROGLYPH G007EGYPTIAN HIEROGLYPH G007AEGYPTIAN HIEROGLYPH G007BEGY" +
"PTIAN HIEROGLYPH G008EGYPTIAN HIEROGLYPH G009EGYPTIAN HIEROGLYPH G010EGY" +
"PTIAN HIEROGLYPH G011EGYPTIAN HIEROGLYPH G011AEGYPTIAN HIEROGLYPH G012EG" +
"YPTIAN HIEROGLYPH G013EGYPTIAN HIEROGLYPH G014EGYPTIAN HIEROGLYPH G015EG" +
"YPTIAN HIEROGLYPH G016EGYPTIAN HIEROGLYPH G017EGYPTIAN HIEROGLYPH G018EG" +
"YPTIAN HIEROGLYPH G019EGYPTIAN HIEROGLYPH G020EGYPTIAN HIEROGLYPH G020AE" +
"GYPTIAN HIEROGLYPH G021EGYPTIAN HIEROGLYPH G022EGYPTIAN HIEROGLYPH G023E" +
"GYPTIAN HIEROGLYPH G024EGYPTIAN HIEROGLYPH G025EGYPTIAN HIEROGLYPH G026E" +
"GYPTIAN HIEROGLYPH G026AEGYPTIAN HIEROGLYPH G027EGYPTIAN HIEROGLYPH G028" +
"EGYPTIAN HIEROGLYPH G029EGYPTIAN HIEROGLYPH G030EGYPTIAN HIEROGLYPH G031") + ("" +
"EGYPTIAN HIEROGLYPH G032EGYPTIAN HIEROGLYPH G033EGYPTIAN HIEROGLYPH G034" +
"EGYPTIAN HIEROGLYPH G035EGYPTIAN HIEROGLYPH G036EGYPTIAN HIEROGLYPH G036" +
"AEGYPTIAN HIEROGLYPH G037EGYPTIAN HIEROGLYPH G037AEGYPTIAN HIEROGLYPH G0" +
"38EGYPTIAN HIEROGLYPH G039EGYPTIAN HIEROGLYPH G040EGYPTIAN HIEROGLYPH G0" +
"41EGYPTIAN HIEROGLYPH G042EGYPTIAN HIEROGLYPH G043EGYPTIAN HIEROGLYPH G0" +
"43AEGYPTIAN HIEROGLYPH G044EGYPTIAN HIEROGLYPH G045EGYPTIAN HIEROGLYPH G" +
"045AEGYPTIAN 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" +
" H008EGYPTIAN HIEROGLYPH I001EGYPTIAN HIEROGLYPH I002EGYPTIAN HIEROGLYPH" +
" I003EGYPTIAN HIEROGLYPH I004EGYPTIAN HIEROGLYPH I005EGYPTIAN HIEROGLYPH" +
" I005AEGYPTIAN HIEROGLYPH I006EGYPTIAN HIEROGLYPH I007EGYPTIAN HIEROGLYP" +
"H I008EGYPTIAN HIEROGLYPH I009EGYPTIAN HIEROGLYPH I009AEGYPTIAN HIEROGLY" +
"PH I010EGYPTIAN HIEROGLYPH I010AEGYPTIAN HIEROGLYPH I011EGYPTIAN HIEROGL" +
"YPH I011AEGYPTIAN HIEROGLYPH I012EGYPTIAN HIEROGLYPH I013EGYPTIAN HIEROG" +
"LYPH I014EGYPTIAN HIEROGLYPH I015EGYPTIAN HIEROGLYPH K001EGYPTIAN HIEROG" +
"LYPH K002EGYPTIAN HIEROGLYPH K003EGYPTIAN HIEROGLYPH K004EGYPTIAN HIEROG" +
"LYPH K005EGYPTIAN HIEROGLYPH K006EGYPTIAN HIEROGLYPH K007EGYPTIAN HIEROG" +
"LYPH K008EGYPTIAN HIEROGLYPH L001EGYPTIAN HIEROGLYPH L002EGYPTIAN HIEROG" +
"LYPH L002AEGYPTIAN HIEROGLYPH L003EGYPTIAN HIEROGLYPH L004EGYPTIAN HIERO" +
"GLYPH L005EGYPTIAN HIEROGLYPH L006EGYPTIAN HIEROGLYPH L006AEGYPTIAN HIER" +
"OGLYPH L007EGYPTIAN HIEROGLYPH L008EGYPTIAN HIEROGLYPH M001EGYPTIAN HIER" +
"OGLYPH M001AEGYPTIAN HIEROGLYPH M001BEGYPTIAN HIEROGLYPH M002EGYPTIAN HI" +
"EROGLYPH M003EGYPTIAN HIEROGLYPH M003AEGYPTIAN HIEROGLYPH M004EGYPTIAN H" +
"IEROGLYPH M005EGYPTIAN HIEROGLYPH M006EGYPTIAN HIEROGLYPH M007EGYPTIAN H" +
"IEROGLYPH M008EGYPTIAN HIEROGLYPH M009EGYPTIAN HIEROGLYPH M010EGYPTIAN H" +
"IEROGLYPH M010AEGYPTIAN HIEROGLYPH M011EGYPTIAN HIEROGLYPH M012EGYPTIAN " +
"HIEROGLYPH M012AEGYPTIAN HIEROGLYPH M012BEGYPTIAN HIEROGLYPH M012CEGYPTI" +
"AN HIEROGLYPH M012DEGYPTIAN HIEROGLYPH M012EEGYPTIAN HIEROGLYPH M012FEGY" +
"PTIAN HIEROGLYPH M012GEGYPTIAN HIEROGLYPH M012HEGYPTIAN HIEROGLYPH M013E" +
"GYPTIAN HIEROGLYPH M014EGYPTIAN HIEROGLYPH M015EGYPTIAN HIEROGLYPH M015A" +
"EGYPTIAN HIEROGLYPH M016EGYPTIAN HIEROGLYPH M016AEGYPTIAN HIEROGLYPH M01" +
"7EGYPTIAN HIEROGLYPH M017AEGYPTIAN HIEROGLYPH M018EGYPTIAN HIEROGLYPH M0" +
"19EGYPTIAN HIEROGLYPH M020EGYPTIAN HIEROGLYPH M021EGYPTIAN HIEROGLYPH M0" +
"22EGYPTIAN HIEROGLYPH M022AEGYPTIAN HIEROGLYPH M023EGYPTIAN HIEROGLYPH M" +
"024EGYPTIAN HIEROGLYPH M024AEGYPTIAN HIEROGLYPH M025EGYPTIAN HIEROGLYPH " +
"M026EGYPTIAN HIEROGLYPH M027EGYPTIAN HIEROGLYPH M028EGYPTIAN HIEROGLYPH " +
"M028AEGYPTIAN HIEROGLYPH M029EGYPTIAN HIEROGLYPH M030EGYPTIAN HIEROGLYPH" +
" M031EGYPTIAN HIEROGLYPH M031AEGYPTIAN HIEROGLYPH M032EGYPTIAN HIEROGLYP" +
"H M033EGYPTIAN HIEROGLYPH M033AEGYPTIAN HIEROGLYPH M033BEGYPTIAN HIEROGL" +
"YPH M034EGYPTIAN HIEROGLYPH M035EGYPTIAN HIEROGLYPH M036EGYPTIAN HIEROGL" +
"YPH M037EGYPTIAN HIEROGLYPH M038EGYPTIAN HIEROGLYPH M039EGYPTIAN HIEROGL" +
"YPH M040EGYPTIAN HIEROGLYPH M040AEGYPTIAN HIEROGLYPH M041EGYPTIAN HIEROG" +
"LYPH M042EGYPTIAN HIEROGLYPH M043EGYPTIAN HIEROGLYPH M044EGYPTIAN HIEROG" +
"LYPH N001EGYPTIAN HIEROGLYPH N002EGYPTIAN HIEROGLYPH N003EGYPTIAN HIEROG" +
"LYPH N004EGYPTIAN HIEROGLYPH N005EGYPTIAN HIEROGLYPH N006EGYPTIAN HIEROG" +
"LYPH N007EGYPTIAN HIEROGLYPH N008EGYPTIAN HIEROGLYPH N009EGYPTIAN HIEROG" +
"LYPH N010EGYPTIAN HIEROGLYPH N011EGYPTIAN HIEROGLYPH N012EGYPTIAN HIEROG" +
"LYPH N013EGYPTIAN HIEROGLYPH N014EGYPTIAN HIEROGLYPH N015EGYPTIAN HIEROG" +
"LYPH N016EGYPTIAN HIEROGLYPH N017EGYPTIAN HIEROGLYPH N018EGYPTIAN HIEROG" +
"LYPH N018AEGYPTIAN HIEROGLYPH N018BEGYPTIAN HIEROGLYPH N019EGYPTIAN HIER" +
"OGLYPH N020EGYPTIAN HIEROGLYPH N021EGYPTIAN HIEROGLYPH N022EGYPTIAN HIER" +
"OGLYPH N023EGYPTIAN HIEROGLYPH N024EGYPTIAN HIEROGLYPH N025EGYPTIAN HIER" +
"OGLYPH N025AEGYPTIAN HIEROGLYPH N026EGYPTIAN HIEROGLYPH N027EGYPTIAN HIE" +
"ROGLYPH N028EGYPTIAN HIEROGLYPH N029EGYPTIAN HIEROGLYPH N030EGYPTIAN HIE" +
"ROGLYPH N031EGYPTIAN HIEROGLYPH N032EGYPTIAN HIEROGLYPH N033EGYPTIAN HIE" +
"ROGLYPH N033AEGYPTIAN HIEROGLYPH N034EGYPTIAN HIEROGLYPH N034AEGYPTIAN H" +
"IEROGLYPH N035EGYPTIAN HIEROGLYPH N035AEGYPTIAN HIEROGLYPH N036EGYPTIAN " +
"HIEROGLYPH N037EGYPTIAN HIEROGLYPH N037AEGYPTIAN HIEROGLYPH N038EGYPTIAN" +
" HIEROGLYPH N039EGYPTIAN HIEROGLYPH N040EGYPTIAN HIEROGLYPH N041EGYPTIAN" +
" HIEROGLYPH N042EGYPTIAN HIEROGLYPH NL001EGYPTIAN HIEROGLYPH NL002EGYPTI") + ("" +
"AN HIEROGLYPH NL003EGYPTIAN HIEROGLYPH NL004EGYPTIAN HIEROGLYPH NL005EGY" +
"PTIAN HIEROGLYPH NL005AEGYPTIAN HIEROGLYPH NL006EGYPTIAN HIEROGLYPH NL00" +
"7EGYPTIAN HIEROGLYPH NL008EGYPTIAN HIEROGLYPH NL009EGYPTIAN HIEROGLYPH N" +
"L010EGYPTIAN HIEROGLYPH NL011EGYPTIAN HIEROGLYPH NL012EGYPTIAN HIEROGLYP" +
"H NL013EGYPTIAN HIEROGLYPH NL014EGYPTIAN HIEROGLYPH NL015EGYPTIAN HIEROG" +
"LYPH NL016EGYPTIAN HIEROGLYPH NL017EGYPTIAN HIEROGLYPH NL017AEGYPTIAN HI" +
"EROGLYPH NL018EGYPTIAN HIEROGLYPH NL019EGYPTIAN HIEROGLYPH NL020EGYPTIAN" +
" HIEROGLYPH NU001EGYPTIAN HIEROGLYPH NU002EGYPTIAN HIEROGLYPH NU003EGYPT" +
"IAN HIEROGLYPH NU004EGYPTIAN HIEROGLYPH NU005EGYPTIAN HIEROGLYPH NU006EG" +
"YPTIAN HIEROGLYPH NU007EGYPTIAN HIEROGLYPH NU008EGYPTIAN HIEROGLYPH NU00" +
"9EGYPTIAN HIEROGLYPH NU010EGYPTIAN HIEROGLYPH NU010AEGYPTIAN HIEROGLYPH " +
"NU011EGYPTIAN HIEROGLYPH NU011AEGYPTIAN HIEROGLYPH NU012EGYPTIAN HIEROGL" +
"YPH NU013EGYPTIAN HIEROGLYPH NU014EGYPTIAN HIEROGLYPH NU015EGYPTIAN HIER" +
"OGLYPH NU016EGYPTIAN HIEROGLYPH NU017EGYPTIAN HIEROGLYPH NU018EGYPTIAN H" +
"IEROGLYPH NU018AEGYPTIAN HIEROGLYPH NU019EGYPTIAN HIEROGLYPH NU020EGYPTI" +
"AN HIEROGLYPH NU021EGYPTIAN HIEROGLYPH NU022EGYPTIAN HIEROGLYPH NU022AEG" +
"YPTIAN HIEROGLYPH O001EGYPTIAN HIEROGLYPH O001AEGYPTIAN HIEROGLYPH O002E" +
"GYPTIAN HIEROGLYPH O003EGYPTIAN HIEROGLYPH O004EGYPTIAN HIEROGLYPH O005E" +
"GYPTIAN HIEROGLYPH O005AEGYPTIAN HIEROGLYPH O006EGYPTIAN HIEROGLYPH O006" +
"AEGYPTIAN HIEROGLYPH O006BEGYPTIAN HIEROGLYPH O006CEGYPTIAN HIEROGLYPH O" +
"006DEGYPTIAN HIEROGLYPH O006EEGYPTIAN HIEROGLYPH O006FEGYPTIAN HIEROGLYP" +
"H O007EGYPTIAN HIEROGLYPH O008EGYPTIAN HIEROGLYPH O009EGYPTIAN HIEROGLYP" +
"H O010EGYPTIAN HIEROGLYPH O010AEGYPTIAN HIEROGLYPH O010BEGYPTIAN HIEROGL" +
"YPH O010CEGYPTIAN HIEROGLYPH O011EGYPTIAN HIEROGLYPH O012EGYPTIAN HIEROG" +
"LYPH O013EGYPTIAN HIEROGLYPH O014EGYPTIAN HIEROGLYPH O015EGYPTIAN HIEROG" +
"LYPH O016EGYPTIAN HIEROGLYPH O017EGYPTIAN HIEROGLYPH O018EGYPTIAN HIEROG" +
"LYPH O019EGYPTIAN HIEROGLYPH O019AEGYPTIAN HIEROGLYPH O020EGYPTIAN HIERO" +
"GLYPH O020AEGYPTIAN HIEROGLYPH O021EGYPTIAN HIEROGLYPH O022EGYPTIAN HIER" +
"OGLYPH O023EGYPTIAN HIEROGLYPH O024EGYPTIAN HIEROGLYPH O024AEGYPTIAN HIE" +
"ROGLYPH O025EGYPTIAN HIEROGLYPH O025AEGYPTIAN HIEROGLYPH O026EGYPTIAN HI" +
"EROGLYPH O027EGYPTIAN HIEROGLYPH O028EGYPTIAN HIEROGLYPH O029EGYPTIAN HI" +
"EROGLYPH O029AEGYPTIAN HIEROGLYPH O030EGYPTIAN HIEROGLYPH O030AEGYPTIAN " +
"HIEROGLYPH O031EGYPTIAN HIEROGLYPH O032EGYPTIAN HIEROGLYPH O033EGYPTIAN " +
"HIEROGLYPH O033AEGYPTIAN HIEROGLYPH O034EGYPTIAN HIEROGLYPH O035EGYPTIAN" +
" HIEROGLYPH O036EGYPTIAN HIEROGLYPH O036AEGYPTIAN HIEROGLYPH O036BEGYPTI" +
"AN HIEROGLYPH O036CEGYPTIAN HIEROGLYPH O036DEGYPTIAN HIEROGLYPH O037EGYP" +
"TIAN HIEROGLYPH O038EGYPTIAN HIEROGLYPH O039EGYPTIAN HIEROGLYPH O040EGYP" +
"TIAN HIEROGLYPH O041EGYPTIAN HIEROGLYPH O042EGYPTIAN HIEROGLYPH O043EGYP" +
"TIAN HIEROGLYPH O044EGYPTIAN HIEROGLYPH O045EGYPTIAN HIEROGLYPH O046EGYP" +
"TIAN HIEROGLYPH O047EGYPTIAN HIEROGLYPH O048EGYPTIAN HIEROGLYPH O049EGYP" +
"TIAN HIEROGLYPH O050EGYPTIAN HIEROGLYPH O050AEGYPTIAN HIEROGLYPH O050BEG" +
"YPTIAN HIEROGLYPH O051EGYPTIAN HIEROGLYPH P001EGYPTIAN HIEROGLYPH P001AE" +
"GYPTIAN HIEROGLYPH P002EGYPTIAN HIEROGLYPH P003EGYPTIAN HIEROGLYPH P003A" +
"EGYPTIAN HIEROGLYPH P004EGYPTIAN HIEROGLYPH P005EGYPTIAN HIEROGLYPH P006" +
"EGYPTIAN HIEROGLYPH P007EGYPTIAN HIEROGLYPH P008EGYPTIAN HIEROGLYPH P009" +
"EGYPTIAN HIEROGLYPH P010EGYPTIAN HIEROGLYPH P011EGYPTIAN HIEROGLYPH Q001" +
"EGYPTIAN HIEROGLYPH Q002EGYPTIAN HIEROGLYPH Q003EGYPTIAN HIEROGLYPH Q004" +
"EGYPTIAN HIEROGLYPH Q005EGYPTIAN HIEROGLYPH Q006EGYPTIAN HIEROGLYPH Q007" +
"EGYPTIAN HIEROGLYPH R001EGYPTIAN HIEROGLYPH R002EGYPTIAN HIEROGLYPH R002" +
"AEGYPTIAN HIEROGLYPH R003EGYPTIAN HIEROGLYPH R003AEGYPTIAN HIEROGLYPH R0" +
"03BEGYPTIAN HIEROGLYPH R004EGYPTIAN HIEROGLYPH R005EGYPTIAN HIEROGLYPH R" +
"006EGYPTIAN HIEROGLYPH R007EGYPTIAN HIEROGLYPH R008EGYPTIAN HIEROGLYPH R" +
"009EGYPTIAN HIEROGLYPH R010EGYPTIAN HIEROGLYPH R010AEGYPTIAN HIEROGLYPH " +
"R011EGYPTIAN HIEROGLYPH R012EGYPTIAN HIEROGLYPH R013EGYPTIAN HIEROGLYPH " +
"R014EGYPTIAN HIEROGLYPH R015EGYPTIAN HIEROGLYPH R016EGYPTIAN HIEROGLYPH " +
"R016AEGYPTIAN HIEROGLYPH R017EGYPTIAN HIEROGLYPH R018EGYPTIAN HIEROGLYPH" +
" R019EGYPTIAN HIEROGLYPH R020EGYPTIAN HIEROGLYPH R021EGYPTIAN HIEROGLYPH" +
" R022EGYPTIAN HIEROGLYPH R023EGYPTIAN HIEROGLYPH R024EGYPTIAN HIEROGLYPH" +
" R025EGYPTIAN HIEROGLYPH R026EGYPTIAN HIEROGLYPH R027EGYPTIAN HIEROGLYPH" +
" R028EGYPTIAN HIEROGLYPH R029EGYPTIAN HIEROGLYPH S001EGYPTIAN HIEROGLYPH" +
" S002EGYPTIAN HIEROGLYPH S002AEGYPTIAN HIEROGLYPH S003EGYPTIAN HIEROGLYP" +
"H S004EGYPTIAN HIEROGLYPH S005EGYPTIAN HIEROGLYPH S006EGYPTIAN HIEROGLYP" +
"H S006AEGYPTIAN HIEROGLYPH S007EGYPTIAN HIEROGLYPH S008EGYPTIAN HIEROGLY" +
"PH S009EGYPTIAN HIEROGLYPH S010EGYPTIAN HIEROGLYPH S011EGYPTIAN HIEROGLY") + ("" +
"PH S012EGYPTIAN HIEROGLYPH S013EGYPTIAN HIEROGLYPH S014EGYPTIAN HIEROGLY" +
"PH S014AEGYPTIAN HIEROGLYPH S014BEGYPTIAN HIEROGLYPH S015EGYPTIAN HIEROG" +
"LYPH S016EGYPTIAN HIEROGLYPH S017EGYPTIAN HIEROGLYPH S017AEGYPTIAN HIERO" +
"GLYPH S018EGYPTIAN HIEROGLYPH S019EGYPTIAN HIEROGLYPH S020EGYPTIAN HIERO" +
"GLYPH S021EGYPTIAN HIEROGLYPH S022EGYPTIAN HIEROGLYPH S023EGYPTIAN HIERO" +
"GLYPH S024EGYPTIAN HIEROGLYPH S025EGYPTIAN HIEROGLYPH S026EGYPTIAN HIERO" +
"GLYPH S026AEGYPTIAN HIEROGLYPH S026BEGYPTIAN HIEROGLYPH S027EGYPTIAN HIE" +
"ROGLYPH S028EGYPTIAN HIEROGLYPH S029EGYPTIAN HIEROGLYPH S030EGYPTIAN HIE" +
"ROGLYPH S031EGYPTIAN HIEROGLYPH S032EGYPTIAN HIEROGLYPH S033EGYPTIAN HIE" +
"ROGLYPH S034EGYPTIAN HIEROGLYPH S035EGYPTIAN HIEROGLYPH S035AEGYPTIAN HI" +
"EROGLYPH S036EGYPTIAN HIEROGLYPH S037EGYPTIAN HIEROGLYPH S038EGYPTIAN HI" +
"EROGLYPH S039EGYPTIAN HIEROGLYPH S040EGYPTIAN HIEROGLYPH S041EGYPTIAN HI" +
"EROGLYPH S042EGYPTIAN HIEROGLYPH S043EGYPTIAN HIEROGLYPH S044EGYPTIAN HI" +
"EROGLYPH S045EGYPTIAN HIEROGLYPH S046EGYPTIAN HIEROGLYPH T001EGYPTIAN HI" +
"EROGLYPH T002EGYPTIAN HIEROGLYPH T003EGYPTIAN HIEROGLYPH T003AEGYPTIAN H" +
"IEROGLYPH T004EGYPTIAN HIEROGLYPH T005EGYPTIAN HIEROGLYPH T006EGYPTIAN H" +
"IEROGLYPH T007EGYPTIAN HIEROGLYPH T007AEGYPTIAN HIEROGLYPH T008EGYPTIAN " +
"HIEROGLYPH T008AEGYPTIAN HIEROGLYPH T009EGYPTIAN HIEROGLYPH T009AEGYPTIA" +
"N HIEROGLYPH T010EGYPTIAN HIEROGLYPH T011EGYPTIAN HIEROGLYPH T011AEGYPTI" +
"AN HIEROGLYPH T012EGYPTIAN HIEROGLYPH T013EGYPTIAN HIEROGLYPH T014EGYPTI" +
"AN HIEROGLYPH T015EGYPTIAN HIEROGLYPH T016EGYPTIAN HIEROGLYPH T016AEGYPT" +
"IAN HIEROGLYPH T017EGYPTIAN HIEROGLYPH T018EGYPTIAN HIEROGLYPH T019EGYPT" +
"IAN HIEROGLYPH T020EGYPTIAN HIEROGLYPH T021EGYPTIAN HIEROGLYPH T022EGYPT" +
"IAN HIEROGLYPH T023EGYPTIAN HIEROGLYPH T024EGYPTIAN HIEROGLYPH T025EGYPT" +
"IAN HIEROGLYPH T026EGYPTIAN HIEROGLYPH T027EGYPTIAN HIEROGLYPH T028EGYPT" +
"IAN HIEROGLYPH T029EGYPTIAN HIEROGLYPH T030EGYPTIAN HIEROGLYPH T031EGYPT" +
"IAN HIEROGLYPH T032EGYPTIAN HIEROGLYPH T032AEGYPTIAN HIEROGLYPH T033EGYP" +
"TIAN HIEROGLYPH T033AEGYPTIAN HIEROGLYPH T034EGYPTIAN HIEROGLYPH T035EGY" +
"PTIAN HIEROGLYPH T036EGYPTIAN HIEROGLYPH U001EGYPTIAN HIEROGLYPH U002EGY" +
"PTIAN HIEROGLYPH U003EGYPTIAN HIEROGLYPH U004EGYPTIAN HIEROGLYPH U005EGY" +
"PTIAN HIEROGLYPH U006EGYPTIAN HIEROGLYPH U006AEGYPTIAN HIEROGLYPH U006BE" +
"GYPTIAN HIEROGLYPH U007EGYPTIAN HIEROGLYPH U008EGYPTIAN HIEROGLYPH U009E" +
"GYPTIAN HIEROGLYPH U010EGYPTIAN HIEROGLYPH U011EGYPTIAN HIEROGLYPH U012E" +
"GYPTIAN HIEROGLYPH U013EGYPTIAN HIEROGLYPH U014EGYPTIAN HIEROGLYPH U015E" +
"GYPTIAN HIEROGLYPH U016EGYPTIAN HIEROGLYPH U017EGYPTIAN HIEROGLYPH U018E" +
"GYPTIAN HIEROGLYPH U019EGYPTIAN HIEROGLYPH U020EGYPTIAN HIEROGLYPH U021E" +
"GYPTIAN HIEROGLYPH U022EGYPTIAN HIEROGLYPH U023EGYPTIAN HIEROGLYPH U023A" +
"EGYPTIAN HIEROGLYPH U024EGYPTIAN HIEROGLYPH U025EGYPTIAN HIEROGLYPH U026" +
"EGYPTIAN HIEROGLYPH U027EGYPTIAN HIEROGLYPH U028EGYPTIAN HIEROGLYPH U029" +
"EGYPTIAN HIEROGLYPH U029AEGYPTIAN HIEROGLYPH U030EGYPTIAN HIEROGLYPH U03" +
"1EGYPTIAN HIEROGLYPH U032EGYPTIAN HIEROGLYPH U032AEGYPTIAN HIEROGLYPH U0" +
"33EGYPTIAN HIEROGLYPH U034EGYPTIAN HIEROGLYPH U035EGYPTIAN HIEROGLYPH U0" +
"36EGYPTIAN HIEROGLYPH U037EGYPTIAN HIEROGLYPH U038EGYPTIAN HIEROGLYPH U0" +
"39EGYPTIAN HIEROGLYPH U040EGYPTIAN HIEROGLYPH U041EGYPTIAN HIEROGLYPH U0" +
"42EGYPTIAN HIEROGLYPH V001EGYPTIAN HIEROGLYPH V001AEGYPTIAN HIEROGLYPH V" +
"001BEGYPTIAN HIEROGLYPH V001CEGYPTIAN HIEROGLYPH V001DEGYPTIAN HIEROGLYP" +
"H V001EEGYPTIAN HIEROGLYPH V001FEGYPTIAN HIEROGLYPH V001GEGYPTIAN HIEROG" +
"LYPH V001HEGYPTIAN HIEROGLYPH V001IEGYPTIAN HIEROGLYPH V002EGYPTIAN HIER" +
"OGLYPH V002AEGYPTIAN HIEROGLYPH V003EGYPTIAN HIEROGLYPH V004EGYPTIAN HIE" +
"ROGLYPH V005EGYPTIAN HIEROGLYPH V006EGYPTIAN HIEROGLYPH V007EGYPTIAN HIE" +
"ROGLYPH V007AEGYPTIAN HIEROGLYPH V007BEGYPTIAN HIEROGLYPH V008EGYPTIAN H" +
"IEROGLYPH V009EGYPTIAN HIEROGLYPH V010EGYPTIAN HIEROGLYPH V011EGYPTIAN H" +
"IEROGLYPH V011AEGYPTIAN HIEROGLYPH V011BEGYPTIAN HIEROGLYPH V011CEGYPTIA" +
"N HIEROGLYPH V012EGYPTIAN HIEROGLYPH V012AEGYPTIAN HIEROGLYPH V012BEGYPT" +
"IAN HIEROGLYPH V013EGYPTIAN HIEROGLYPH V014EGYPTIAN HIEROGLYPH V015EGYPT" +
"IAN HIEROGLYPH V016EGYPTIAN HIEROGLYPH V017EGYPTIAN HIEROGLYPH V018EGYPT" +
"IAN HIEROGLYPH V019EGYPTIAN HIEROGLYPH V020EGYPTIAN HIEROGLYPH V020AEGYP" +
"TIAN HIEROGLYPH V020BEGYPTIAN HIEROGLYPH V020CEGYPTIAN HIEROGLYPH V020DE" +
"GYPTIAN HIEROGLYPH V020EEGYPTIAN HIEROGLYPH V020FEGYPTIAN HIEROGLYPH V02" +
"0GEGYPTIAN HIEROGLYPH V020HEGYPTIAN HIEROGLYPH V020IEGYPTIAN HIEROGLYPH " +
"V020JEGYPTIAN HIEROGLYPH V020KEGYPTIAN HIEROGLYPH V020LEGYPTIAN HIEROGLY" +
"PH V021EGYPTIAN HIEROGLYPH V022EGYPTIAN HIEROGLYPH V023EGYPTIAN HIEROGLY" +
"PH V023AEGYPTIAN HIEROGLYPH V024EGYPTIAN HIEROGLYPH V025EGYPTIAN HIEROGL" +
"YPH V026EGYPTIAN HIEROGLYPH V027EGYPTIAN HIEROGLYPH V028EGYPTIAN HIEROGL") + ("" +
"YPH V028AEGYPTIAN HIEROGLYPH V029EGYPTIAN HIEROGLYPH V029AEGYPTIAN HIERO" +
"GLYPH V030EGYPTIAN HIEROGLYPH V030AEGYPTIAN HIEROGLYPH V031EGYPTIAN HIER" +
"OGLYPH V031AEGYPTIAN HIEROGLYPH V032EGYPTIAN HIEROGLYPH V033EGYPTIAN HIE" +
"ROGLYPH V033AEGYPTIAN HIEROGLYPH V034EGYPTIAN HIEROGLYPH V035EGYPTIAN HI" +
"EROGLYPH V036EGYPTIAN HIEROGLYPH V037EGYPTIAN HIEROGLYPH V037AEGYPTIAN H" +
"IEROGLYPH V038EGYPTIAN HIEROGLYPH V039EGYPTIAN HIEROGLYPH V040EGYPTIAN H" +
"IEROGLYPH V040AEGYPTIAN HIEROGLYPH W001EGYPTIAN HIEROGLYPH W002EGYPTIAN " +
"HIEROGLYPH W003EGYPTIAN HIEROGLYPH W003AEGYPTIAN HIEROGLYPH W004EGYPTIAN" +
" HIEROGLYPH W005EGYPTIAN HIEROGLYPH W006EGYPTIAN HIEROGLYPH W007EGYPTIAN" +
" HIEROGLYPH W008EGYPTIAN HIEROGLYPH W009EGYPTIAN HIEROGLYPH W009AEGYPTIA" +
"N HIEROGLYPH W010EGYPTIAN HIEROGLYPH W010AEGYPTIAN HIEROGLYPH W011EGYPTI" +
"AN HIEROGLYPH W012EGYPTIAN HIEROGLYPH W013EGYPTIAN HIEROGLYPH W014EGYPTI" +
"AN HIEROGLYPH W014AEGYPTIAN HIEROGLYPH W015EGYPTIAN HIEROGLYPH W016EGYPT" +
"IAN HIEROGLYPH W017EGYPTIAN HIEROGLYPH W017AEGYPTIAN HIEROGLYPH W018EGYP" +
"TIAN HIEROGLYPH W018AEGYPTIAN HIEROGLYPH W019EGYPTIAN HIEROGLYPH W020EGY" +
"PTIAN HIEROGLYPH W021EGYPTIAN HIEROGLYPH W022EGYPTIAN HIEROGLYPH W023EGY" +
"PTIAN HIEROGLYPH W024EGYPTIAN HIEROGLYPH W024AEGYPTIAN HIEROGLYPH W025EG" +
"YPTIAN HIEROGLYPH X001EGYPTIAN HIEROGLYPH X002EGYPTIAN HIEROGLYPH X003EG" +
"YPTIAN HIEROGLYPH X004EGYPTIAN HIEROGLYPH X004AEGYPTIAN HIEROGLYPH X004B" +
"EGYPTIAN HIEROGLYPH X005EGYPTIAN HIEROGLYPH X006EGYPTIAN HIEROGLYPH X006" +
"AEGYPTIAN HIEROGLYPH X007EGYPTIAN HIEROGLYPH X008EGYPTIAN HIEROGLYPH X00" +
"8AEGYPTIAN HIEROGLYPH Y001EGYPTIAN HIEROGLYPH Y001AEGYPTIAN HIEROGLYPH Y" +
"002EGYPTIAN HIEROGLYPH Y003EGYPTIAN HIEROGLYPH Y004EGYPTIAN HIEROGLYPH Y" +
"005EGYPTIAN HIEROGLYPH Y006EGYPTIAN HIEROGLYPH Y007EGYPTIAN HIEROGLYPH Y" +
"008EGYPTIAN HIEROGLYPH Z001EGYPTIAN HIEROGLYPH Z002EGYPTIAN HIEROGLYPH Z" +
"002AEGYPTIAN HIEROGLYPH Z002BEGYPTIAN HIEROGLYPH Z002CEGYPTIAN HIEROGLYP" +
"H Z002DEGYPTIAN HIEROGLYPH Z003EGYPTIAN HIEROGLYPH Z003AEGYPTIAN HIEROGL" +
"YPH Z003BEGYPTIAN HIEROGLYPH Z004EGYPTIAN HIEROGLYPH Z004AEGYPTIAN HIERO" +
"GLYPH Z005EGYPTIAN HIEROGLYPH Z005AEGYPTIAN HIEROGLYPH Z006EGYPTIAN HIER" +
"OGLYPH Z007EGYPTIAN HIEROGLYPH Z008EGYPTIAN HIEROGLYPH Z009EGYPTIAN HIER" +
"OGLYPH Z010EGYPTIAN HIEROGLYPH Z011EGYPTIAN HIEROGLYPH Z012EGYPTIAN HIER" +
"OGLYPH Z013EGYPTIAN HIEROGLYPH Z014EGYPTIAN HIEROGLYPH Z015EGYPTIAN HIER" +
"OGLYPH Z015AEGYPTIAN HIEROGLYPH Z015BEGYPTIAN HIEROGLYPH Z015CEGYPTIAN H" +
"IEROGLYPH Z015DEGYPTIAN HIEROGLYPH Z015EEGYPTIAN HIEROGLYPH Z015FEGYPTIA" +
"N HIEROGLYPH Z015GEGYPTIAN HIEROGLYPH Z015HEGYPTIAN HIEROGLYPH Z015IEGYP" +
"TIAN HIEROGLYPH Z016EGYPTIAN HIEROGLYPH Z016AEGYPTIAN HIEROGLYPH Z016BEG" +
"YPTIAN HIEROGLYPH Z016CEGYPTIAN HIEROGLYPH Z016DEGYPTIAN HIEROGLYPH Z016" +
"EEGYPTIAN HIEROGLYPH Z016FEGYPTIAN HIEROGLYPH Z016GEGYPTIAN HIEROGLYPH Z" +
"016HEGYPTIAN HIEROGLYPH AA001EGYPTIAN HIEROGLYPH AA002EGYPTIAN HIEROGLYP" +
"H AA003EGYPTIAN HIEROGLYPH AA004EGYPTIAN HIEROGLYPH AA005EGYPTIAN HIEROG" +
"LYPH AA006EGYPTIAN HIEROGLYPH AA007EGYPTIAN HIEROGLYPH AA007AEGYPTIAN HI" +
"EROGLYPH AA007BEGYPTIAN HIEROGLYPH AA008EGYPTIAN HIEROGLYPH AA009EGYPTIA" +
"N HIEROGLYPH AA010EGYPTIAN HIEROGLYPH AA011EGYPTIAN HIEROGLYPH AA012EGYP" +
"TIAN HIEROGLYPH AA013EGYPTIAN HIEROGLYPH AA014EGYPTIAN HIEROGLYPH AA015E" +
"GYPTIAN HIEROGLYPH AA016EGYPTIAN HIEROGLYPH AA017EGYPTIAN HIEROGLYPH AA0" +
"18EGYPTIAN HIEROGLYPH AA019EGYPTIAN HIEROGLYPH AA020EGYPTIAN HIEROGLYPH " +
"AA021EGYPTIAN HIEROGLYPH AA022EGYPTIAN HIEROGLYPH AA023EGYPTIAN HIEROGLY" +
"PH AA024EGYPTIAN HIEROGLYPH AA025EGYPTIAN HIEROGLYPH AA026EGYPTIAN HIERO" +
"GLYPH AA027EGYPTIAN HIEROGLYPH AA028EGYPTIAN HIEROGLYPH AA029EGYPTIAN HI" +
"EROGLYPH AA030EGYPTIAN HIEROGLYPH AA031EGYPTIAN HIEROGLYPH AA032EGYPTIAN" +
" HIEROGLYPH V011DEGYPTIAN HIEROGLYPH VERTICAL JOINEREGYPTIAN HIEROGLYPH " +
"HORIZONTAL JOINEREGYPTIAN HIEROGLYPH INSERT AT TOP STARTEGYPTIAN HIEROGL" +
"YPH INSERT AT BOTTOM STARTEGYPTIAN HIEROGLYPH INSERT AT TOP ENDEGYPTIAN " +
"HIEROGLYPH INSERT AT BOTTOM ENDEGYPTIAN HIEROGLYPH OVERLAY MIDDLEEGYPTIA" +
"N HIEROGLYPH BEGIN SEGMENTEGYPTIAN HIEROGLYPH END SEGMENTEGYPTIAN HIEROG" +
"LYPH INSERT AT MIDDLEEGYPTIAN HIEROGLYPH INSERT AT TOPEGYPTIAN HIEROGLYP" +
"H INSERT AT BOTTOMEGYPTIAN HIEROGLYPH BEGIN ENCLOSUREEGYPTIAN HIEROGLYPH" +
" END ENCLOSUREEGYPTIAN HIEROGLYPH BEGIN WALLED ENCLOSUREEGYPTIAN HIEROGL" +
"YPH END WALLED ENCLOSUREEGYPTIAN HIEROGLYPH MIRROR HORIZONTALLYEGYPTIAN " +
"HIEROGLYPH FULL BLANKEGYPTIAN HIEROGLYPH HALF BLANKEGYPTIAN HIEROGLYPH L" +
"OST SIGNEGYPTIAN HIEROGLYPH HALF LOST SIGNEGYPTIAN HIEROGLYPH TALL LOST " +
"SIGNEGYPTIAN HIEROGLYPH WIDE LOST SIGNEGYPTIAN HIEROGLYPH MODIFIER DAMAG" +
"ED AT TOP STARTEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOM STARTEGYPT" +
"IAN HIEROGLYPH MODIFIER DAMAGED AT STARTEGYPTIAN HIEROGLYPH MODIFIER DAM") + ("" +
"AGED AT TOP ENDEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOPEGYPTIAN HIERO" +
"GLYPH MODIFIER DAMAGED AT BOTTOM START AND TOP ENDEGYPTIAN HIEROGLYPH MO" +
"DIFIER DAMAGED AT START AND TOPEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT B" +
"OTTOM ENDEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START AND BOTTOM EN" +
"DEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT BOTTOMEGYPTIAN HIEROGLYPH MODIF" +
"IER DAMAGED AT START AND BOTTOMEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT E" +
"NDEGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP AND ENDEGYPTIAN HIEROGLYPH" +
" MODIFIER DAMAGED AT BOTTOM AND ENDEGYPTIAN HIEROGLYPH MODIFIER DAMAGEDE" +
"GYPTIAN HIEROGLYPH-13460EGYPTIAN HIEROGLYPH-13461EGYPTIAN HIEROGLYPH-134" +
"62EGYPTIAN HIEROGLYPH-13463EGYPTIAN HIEROGLYPH-13464EGYPTIAN HIEROGLYPH-" +
"13465EGYPTIAN HIEROGLYPH-13466EGYPTIAN HIEROGLYPH-13467EGYPTIAN HIEROGLY" +
"PH-13468EGYPTIAN HIEROGLYPH-13469EGYPTIAN HIEROGLYPH-1346AEGYPTIAN HIERO" +
"GLYPH-1346BEGYPTIAN HIEROGLYPH-1346CEGYPTIAN HIEROGLYPH-1346DEGYPTIAN HI" +
"EROGLYPH-1346EEGYPTIAN HIEROGLYPH-1346FEGYPTIAN HIEROGLYPH-13470EGYPTIAN" +
" HIEROGLYPH-13471EGYPTIAN HIEROGLYPH-13472EGYPTIAN HIEROGLYPH-13473EGYPT" +
"IAN HIEROGLYPH-13474EGYPTIAN HIEROGLYPH-13475EGYPTIAN HIEROGLYPH-13476EG" +
"YPTIAN HIEROGLYPH-13477EGYPTIAN HIEROGLYPH-13478EGYPTIAN HIEROGLYPH-1347" +
"9EGYPTIAN HIEROGLYPH-1347AEGYPTIAN HIEROGLYPH-1347BEGYPTIAN HIEROGLYPH-1" +
"347CEGYPTIAN HIEROGLYPH-1347DEGYPTIAN HIEROGLYPH-1347EEGYPTIAN HIEROGLYP" +
"H-1347FEGYPTIAN HIEROGLYPH-13480EGYPTIAN HIEROGLYPH-13481EGYPTIAN HIEROG" +
"LYPH-13482EGYPTIAN HIEROGLYPH-13483EGYPTIAN HIEROGLYPH-13484EGYPTIAN HIE" +
"ROGLYPH-13485EGYPTIAN HIEROGLYPH-13486EGYPTIAN HIEROGLYPH-13487EGYPTIAN " +
"HIEROGLYPH-13488EGYPTIAN HIEROGLYPH-13489EGYPTIAN HIEROGLYPH-1348AEGYPTI" +
"AN HIEROGLYPH-1348BEGYPTIAN HIEROGLYPH-1348CEGYPTIAN HIEROGLYPH-1348DEGY" +
"PTIAN HIEROGLYPH-1348EEGYPTIAN HIEROGLYPH-1348FEGYPTIAN HIEROGLYPH-13490" +
"EGYPTIAN HIEROGLYPH-13491EGYPTIAN HIEROGLYPH-13492EGYPTIAN HIEROGLYPH-13" +
"493EGYPTIAN HIEROGLYPH-13494EGYPTIAN HIEROGLYPH-13495EGYPTIAN HIEROGLYPH" +
"-13496EGYPTIAN HIEROGLYPH-13497EGYPTIAN HIEROGLYPH-13498EGYPTIAN HIEROGL" +
"YPH-13499EGYPTIAN HIEROGLYPH-1349AEGYPTIAN HIEROGLYPH-1349BEGYPTIAN HIER" +
"OGLYPH-1349CEGYPTIAN HIEROGLYPH-1349DEGYPTIAN HIEROGLYPH-1349EEGYPTIAN H" +
"IEROGLYPH-1349FEGYPTIAN HIEROGLYPH-134A0EGYPTIAN HIEROGLYPH-134A1EGYPTIA" +
"N HIEROGLYPH-134A2EGYPTIAN HIEROGLYPH-134A3EGYPTIAN HIEROGLYPH-134A4EGYP" +
"TIAN HIEROGLYPH-134A5EGYPTIAN HIEROGLYPH-134A6EGYPTIAN HIEROGLYPH-134A7E" +
"GYPTIAN HIEROGLYPH-134A8EGYPTIAN HIEROGLYPH-134A9EGYPTIAN HIEROGLYPH-134" +
"AAEGYPTIAN HIEROGLYPH-134ABEGYPTIAN HIEROGLYPH-134ACEGYPTIAN HIEROGLYPH-" +
"134ADEGYPTIAN HIEROGLYPH-134AEEGYPTIAN HIEROGLYPH-134AFEGYPTIAN HIEROGLY" +
"PH-134B0EGYPTIAN HIEROGLYPH-134B1EGYPTIAN HIEROGLYPH-134B2EGYPTIAN HIERO" +
"GLYPH-134B3EGYPTIAN HIEROGLYPH-134B4EGYPTIAN HIEROGLYPH-134B5EGYPTIAN HI" +
"EROGLYPH-134B6EGYPTIAN HIEROGLYPH-134B7EGYPTIAN HIEROGLYPH-134B8EGYPTIAN" +
" HIEROGLYPH-134B9EGYPTIAN HIEROGLYPH-134BAEGYPTIAN HIEROGLYPH-134BBEGYPT" +
"IAN HIEROGLYPH-134BCEGYPTIAN HIEROGLYPH-134BDEGYPTIAN HIEROGLYPH-134BEEG" +
"YPTIAN HIEROGLYPH-134BFEGYPTIAN HIEROGLYPH-134C0EGYPTIAN HIEROGLYPH-134C" +
"1EGYPTIAN HIEROGLYPH-134C2EGYPTIAN HIEROGLYPH-134C3EGYPTIAN HIEROGLYPH-1" +
"34C4EGYPTIAN HIEROGLYPH-134C5EGYPTIAN HIEROGLYPH-134C6EGYPTIAN HIEROGLYP" +
"H-134C7EGYPTIAN HIEROGLYPH-134C8EGYPTIAN HIEROGLYPH-134C9EGYPTIAN HIEROG" +
"LYPH-134CAEGYPTIAN HIEROGLYPH-134CBEGYPTIAN HIEROGLYPH-134CCEGYPTIAN HIE" +
"ROGLYPH-134CDEGYPTIAN HIEROGLYPH-134CEEGYPTIAN HIEROGLYPH-134CFEGYPTIAN " +
"HIEROGLYPH-134D0EGYPTIAN HIEROGLYPH-134D1EGYPTIAN HIEROGLYPH-134D2EGYPTI" +
"AN HIEROGLYPH-134D3EGYPTIAN HIEROGLYPH-134D4EGYPTIAN HIEROGLYPH-134D5EGY" +
"PTIAN HIEROGLYPH-134D6EGYPTIAN HIEROGLYPH-134D7EGYPTIAN HIEROGLYPH-134D8" +
"EGYPTIAN HIEROGLYPH-134D9EGYPTIAN HIEROGLYPH-134DAEGYPTIAN HIEROGLYPH-13" +
"4DBEGYPTIAN HIEROGLYPH-134DCEGYPTIAN HIEROGLYPH-134DDEGYPTIAN HIEROGLYPH" +
"-134DEEGYPTIAN HIEROGLYPH-134DFEGYPTIAN HIEROGLYPH-134E0EGYPTIAN HIEROGL" +
"YPH-134E1EGYPTIAN HIEROGLYPH-134E2EGYPTIAN HIEROGLYPH-134E3EGYPTIAN HIER" +
"OGLYPH-134E4EGYPTIAN HIEROGLYPH-134E5EGYPTIAN HIEROGLYPH-134E6EGYPTIAN H" +
"IEROGLYPH-134E7EGYPTIAN HIEROGLYPH-134E8EGYPTIAN HIEROGLYPH-134E9EGYPTIA" +
"N HIEROGLYPH-134EAEGYPTIAN HIEROGLYPH-134EBEGYPTIAN HIEROGLYPH-134ECEGYP" +
"TIAN HIEROGLYPH-134EDEGYPTIAN HIEROGLYPH-134EEEGYPTIAN HIEROGLYPH-134EFE" +
"GYPTIAN HIEROGLYPH-134F0EGYPTIAN HIEROGLYPH-134F1EGYPTIAN HIEROGLYPH-134" +
"F2EGYPTIAN HIEROGLYPH-134F3EGYPTIAN HIEROGLYPH-134F4EGYPTIAN HIEROGLYPH-" +
"134F5EGYPTIAN HIEROGLYPH-134F6EGYPTIAN HIEROGLYPH-134F7EGYPTIAN HIEROGLY" +
"PH-134F8EGYPTIAN HIEROGLYPH-134F9EGYPTIAN HIEROGLYPH-134FAEGYPTIAN HIERO" +
"GLYPH-134FBEGYPTIAN HIEROGLYPH-134FCEGYPTIAN HIEROGLYPH-134FDEGYPTIAN HI" +
"EROGLYPH-134FEEGYPTIAN HIEROGLYPH-134FFEGYPTIAN HIEROGLYPH-13500EGYPTIAN") + ("" +
" HIEROGLYPH-13501EGYPTIAN HIEROGLYPH-13502EGYPTIAN HIEROGLYPH-13503EGYPT" +
"IAN HIEROGLYPH-13504EGYPTIAN HIEROGLYPH-13505EGYPTIAN HIEROGLYPH-13506EG" +
"YPTIAN HIEROGLYPH-13507EGYPTIAN HIEROGLYPH-13508EGYPTIAN HIEROGLYPH-1350" +
"9EGYPTIAN HIEROGLYPH-1350AEGYPTIAN HIEROGLYPH-1350BEGYPTIAN HIEROGLYPH-1" +
"350CEGYPTIAN HIEROGLYPH-1350DEGYPTIAN HIEROGLYPH-1350EEGYPTIAN HIEROGLYP" +
"H-1350FEGYPTIAN HIEROGLYPH-13510EGYPTIAN HIEROGLYPH-13511EGYPTIAN HIEROG" +
"LYPH-13512EGYPTIAN HIEROGLYPH-13513EGYPTIAN HIEROGLYPH-13514EGYPTIAN HIE" +
"ROGLYPH-13515EGYPTIAN HIEROGLYPH-13516EGYPTIAN HIEROGLYPH-13517EGYPTIAN " +
"HIEROGLYPH-13518EGYPTIAN HIEROGLYPH-13519EGYPTIAN HIEROGLYPH-1351AEGYPTI" +
"AN HIEROGLYPH-1351BEGYPTIAN HIEROGLYPH-1351CEGYPTIAN HIEROGLYPH-1351DEGY" +
"PTIAN HIEROGLYPH-1351EEGYPTIAN HIEROGLYPH-1351FEGYPTIAN HIEROGLYPH-13520" +
"EGYPTIAN HIEROGLYPH-13521EGYPTIAN HIEROGLYPH-13522EGYPTIAN HIEROGLYPH-13" +
"523EGYPTIAN HIEROGLYPH-13524EGYPTIAN HIEROGLYPH-13525EGYPTIAN HIEROGLYPH" +
"-13526EGYPTIAN HIEROGLYPH-13527EGYPTIAN HIEROGLYPH-13528EGYPTIAN HIEROGL" +
"YPH-13529EGYPTIAN HIEROGLYPH-1352AEGYPTIAN HIEROGLYPH-1352BEGYPTIAN HIER" +
"OGLYPH-1352CEGYPTIAN HIEROGLYPH-1352DEGYPTIAN HIEROGLYPH-1352EEGYPTIAN H" +
"IEROGLYPH-1352FEGYPTIAN HIEROGLYPH-13530EGYPTIAN HIEROGLYPH-13531EGYPTIA" +
"N HIEROGLYPH-13532EGYPTIAN HIEROGLYPH-13533EGYPTIAN HIEROGLYPH-13534EGYP" +
"TIAN HIEROGLYPH-13535EGYPTIAN HIEROGLYPH-13536EGYPTIAN HIEROGLYPH-13537E" +
"GYPTIAN HIEROGLYPH-13538EGYPTIAN HIEROGLYPH-13539EGYPTIAN HIEROGLYPH-135" +
"3AEGYPTIAN HIEROGLYPH-1353BEGYPTIAN HIEROGLYPH-1353CEGYPTIAN HIEROGLYPH-" +
"1353DEGYPTIAN HIEROGLYPH-1353EEGYPTIAN HIEROGLYPH-1353FEGYPTIAN HIEROGLY" +
"PH-13540EGYPTIAN HIEROGLYPH-13541EGYPTIAN HIEROGLYPH-13542EGYPTIAN HIERO" +
"GLYPH-13543EGYPTIAN HIEROGLYPH-13544EGYPTIAN HIEROGLYPH-13545EGYPTIAN HI" +
"EROGLYPH-13546EGYPTIAN HIEROGLYPH-13547EGYPTIAN HIEROGLYPH-13548EGYPTIAN" +
" HIEROGLYPH-13549EGYPTIAN HIEROGLYPH-1354AEGYPTIAN HIEROGLYPH-1354BEGYPT" +
"IAN HIEROGLYPH-1354CEGYPTIAN HIEROGLYPH-1354DEGYPTIAN HIEROGLYPH-1354EEG" +
"YPTIAN HIEROGLYPH-1354FEGYPTIAN HIEROGLYPH-13550EGYPTIAN HIEROGLYPH-1355" +
"1EGYPTIAN HIEROGLYPH-13552EGYPTIAN HIEROGLYPH-13553EGYPTIAN HIEROGLYPH-1" +
"3554EGYPTIAN HIEROGLYPH-13555EGYPTIAN HIEROGLYPH-13556EGYPTIAN HIEROGLYP" +
"H-13557EGYPTIAN HIEROGLYPH-13558EGYPTIAN HIEROGLYPH-13559EGYPTIAN HIEROG" +
"LYPH-1355AEGYPTIAN HIEROGLYPH-1355BEGYPTIAN HIEROGLYPH-1355CEGYPTIAN HIE" +
"ROGLYPH-1355DEGYPTIAN HIEROGLYPH-1355EEGYPTIAN HIEROGLYPH-1355FEGYPTIAN " +
"HIEROGLYPH-13560EGYPTIAN HIEROGLYPH-13561EGYPTIAN HIEROGLYPH-13562EGYPTI" +
"AN HIEROGLYPH-13563EGYPTIAN HIEROGLYPH-13564EGYPTIAN HIEROGLYPH-13565EGY" +
"PTIAN HIEROGLYPH-13566EGYPTIAN HIEROGLYPH-13567EGYPTIAN HIEROGLYPH-13568" +
"EGYPTIAN HIEROGLYPH-13569EGYPTIAN HIEROGLYPH-1356AEGYPTIAN HIEROGLYPH-13" +
"56BEGYPTIAN HIEROGLYPH-1356CEGYPTIAN HIEROGLYPH-1356DEGYPTIAN HIEROGLYPH" +
"-1356EEGYPTIAN HIEROGLYPH-1356FEGYPTIAN HIEROGLYPH-13570EGYPTIAN HIEROGL" +
"YPH-13571EGYPTIAN HIEROGLYPH-13572EGYPTIAN HIEROGLYPH-13573EGYPTIAN HIER" +
"OGLYPH-13574EGYPTIAN HIEROGLYPH-13575EGYPTIAN HIEROGLYPH-13576EGYPTIAN H" +
"IEROGLYPH-13577EGYPTIAN HIEROGLYPH-13578EGYPTIAN HIEROGLYPH-13579EGYPTIA" +
"N HIEROGLYPH-1357AEGYPTIAN HIEROGLYPH-1357BEGYPTIAN HIEROGLYPH-1357CEGYP" +
"TIAN HIEROGLYPH-1357DEGYPTIAN HIEROGLYPH-1357EEGYPTIAN HIEROGLYPH-1357FE" +
"GYPTIAN HIEROGLYPH-13580EGYPTIAN HIEROGLYPH-13581EGYPTIAN HIEROGLYPH-135" +
"82EGYPTIAN HIEROGLYPH-13583EGYPTIAN HIEROGLYPH-13584EGYPTIAN HIEROGLYPH-" +
"13585EGYPTIAN HIEROGLYPH-13586EGYPTIAN HIEROGLYPH-13587EGYPTIAN HIEROGLY" +
"PH-13588EGYPTIAN HIEROGLYPH-13589EGYPTIAN HIEROGLYPH-1358AEGYPTIAN HIERO" +
"GLYPH-1358BEGYPTIAN HIEROGLYPH-1358CEGYPTIAN HIEROGLYPH-1358DEGYPTIAN HI" +
"EROGLYPH-1358EEGYPTIAN HIEROGLYPH-1358FEGYPTIAN HIEROGLYPH-13590EGYPTIAN" +
" HIEROGLYPH-13591EGYPTIAN HIEROGLYPH-13592EGYPTIAN HIEROGLYPH-13593EGYPT" +
"IAN HIEROGLYPH-13594EGYPTIAN HIEROGLYPH-13595EGYPTIAN HIEROGLYPH-13596EG" +
"YPTIAN HIEROGLYPH-13597EGYPTIAN HIEROGLYPH-13598EGYPTIAN HIEROGLYPH-1359" +
"9EGYPTIAN HIEROGLYPH-1359AEGYPTIAN HIEROGLYPH-1359BEGYPTIAN HIEROGLYPH-1" +
"359CEGYPTIAN HIEROGLYPH-1359DEGYPTIAN HIEROGLYPH-1359EEGYPTIAN HIEROGLYP" +
"H-1359FEGYPTIAN HIEROGLYPH-135A0EGYPTIAN HIEROGLYPH-135A1EGYPTIAN HIEROG" +
"LYPH-135A2EGYPTIAN HIEROGLYPH-135A3EGYPTIAN HIEROGLYPH-135A4EGYPTIAN HIE" +
"ROGLYPH-135A5EGYPTIAN HIEROGLYPH-135A6EGYPTIAN HIEROGLYPH-135A7EGYPTIAN " +
"HIEROGLYPH-135A8EGYPTIAN HIEROGLYPH-135A9EGYPTIAN HIEROGLYPH-135AAEGYPTI" +
"AN HIEROGLYPH-135ABEGYPTIAN HIEROGLYPH-135ACEGYPTIAN HIEROGLYPH-135ADEGY" +
"PTIAN HIEROGLYPH-135AEEGYPTIAN HIEROGLYPH-135AFEGYPTIAN HIEROGLYPH-135B0" +
"EGYPTIAN HIEROGLYPH-135B1EGYPTIAN HIEROGLYPH-135B2EGYPTIAN HIEROGLYPH-13" +
"5B3EGYPTIAN HIEROGLYPH-135B4EGYPTIAN HIEROGLYPH-135B5EGYPTIAN HIEROGLYPH" +
"-135B6EGYPTIAN HIEROGLYPH-135B7EGYPTIAN HIEROGLYPH-135B8EGYPTIAN HIEROGL") + ("" +
"YPH-135B9EGYPTIAN HIEROGLYPH-135BAEGYPTIAN HIEROGLYPH-135BBEGYPTIAN HIER" +
"OGLYPH-135BCEGYPTIAN HIEROGLYPH-135BDEGYPTIAN HIEROGLYPH-135BEEGYPTIAN H" +
"IEROGLYPH-135BFEGYPTIAN HIEROGLYPH-135C0EGYPTIAN HIEROGLYPH-135C1EGYPTIA" +
"N HIEROGLYPH-135C2EGYPTIAN HIEROGLYPH-135C3EGYPTIAN HIEROGLYPH-135C4EGYP" +
"TIAN HIEROGLYPH-135C5EGYPTIAN HIEROGLYPH-135C6EGYPTIAN HIEROGLYPH-135C7E" +
"GYPTIAN HIEROGLYPH-135C8EGYPTIAN HIEROGLYPH-135C9EGYPTIAN HIEROGLYPH-135" +
"CAEGYPTIAN HIEROGLYPH-135CBEGYPTIAN HIEROGLYPH-135CCEGYPTIAN HIEROGLYPH-" +
"135CDEGYPTIAN HIEROGLYPH-135CEEGYPTIAN HIEROGLYPH-135CFEGYPTIAN HIEROGLY" +
"PH-135D0EGYPTIAN HIEROGLYPH-135D1EGYPTIAN HIEROGLYPH-135D2EGYPTIAN HIERO" +
"GLYPH-135D3EGYPTIAN HIEROGLYPH-135D4EGYPTIAN HIEROGLYPH-135D5EGYPTIAN HI" +
"EROGLYPH-135D6EGYPTIAN HIEROGLYPH-135D7EGYPTIAN HIEROGLYPH-135D8EGYPTIAN" +
" HIEROGLYPH-135D9EGYPTIAN HIEROGLYPH-135DAEGYPTIAN HIEROGLYPH-135DBEGYPT" +
"IAN HIEROGLYPH-135DCEGYPTIAN HIEROGLYPH-135DDEGYPTIAN HIEROGLYPH-135DEEG" +
"YPTIAN HIEROGLYPH-135DFEGYPTIAN HIEROGLYPH-135E0EGYPTIAN HIEROGLYPH-135E" +
"1EGYPTIAN HIEROGLYPH-135E2EGYPTIAN HIEROGLYPH-135E3EGYPTIAN HIEROGLYPH-1" +
"35E4EGYPTIAN HIEROGLYPH-135E5EGYPTIAN HIEROGLYPH-135E6EGYPTIAN HIEROGLYP" +
"H-135E7EGYPTIAN HIEROGLYPH-135E8EGYPTIAN HIEROGLYPH-135E9EGYPTIAN HIEROG" +
"LYPH-135EAEGYPTIAN HIEROGLYPH-135EBEGYPTIAN HIEROGLYPH-135ECEGYPTIAN HIE" +
"ROGLYPH-135EDEGYPTIAN HIEROGLYPH-135EEEGYPTIAN HIEROGLYPH-135EFEGYPTIAN " +
"HIEROGLYPH-135F0EGYPTIAN HIEROGLYPH-135F1EGYPTIAN HIEROGLYPH-135F2EGYPTI" +
"AN HIEROGLYPH-135F3EGYPTIAN HIEROGLYPH-135F4EGYPTIAN HIEROGLYPH-135F5EGY" +
"PTIAN HIEROGLYPH-135F6EGYPTIAN HIEROGLYPH-135F7EGYPTIAN HIEROGLYPH-135F8" +
"EGYPTIAN HIEROGLYPH-135F9EGYPTIAN HIEROGLYPH-135FAEGYPTIAN HIEROGLYPH-13" +
"5FBEGYPTIAN HIEROGLYPH-135FCEGYPTIAN HIEROGLYPH-135FDEGYPTIAN HIEROGLYPH" +
"-135FEEGYPTIAN HIEROGLYPH-135FFEGYPTIAN HIEROGLYPH-13600EGYPTIAN HIEROGL" +
"YPH-13601EGYPTIAN HIEROGLYPH-13602EGYPTIAN HIEROGLYPH-13603EGYPTIAN HIER" +
"OGLYPH-13604EGYPTIAN HIEROGLYPH-13605EGYPTIAN HIEROGLYPH-13606EGYPTIAN H" +
"IEROGLYPH-13607EGYPTIAN HIEROGLYPH-13608EGYPTIAN HIEROGLYPH-13609EGYPTIA" +
"N HIEROGLYPH-1360AEGYPTIAN HIEROGLYPH-1360BEGYPTIAN HIEROGLYPH-1360CEGYP" +
"TIAN HIEROGLYPH-1360DEGYPTIAN HIEROGLYPH-1360EEGYPTIAN HIEROGLYPH-1360FE" +
"GYPTIAN HIEROGLYPH-13610EGYPTIAN HIEROGLYPH-13611EGYPTIAN HIEROGLYPH-136" +
"12EGYPTIAN HIEROGLYPH-13613EGYPTIAN HIEROGLYPH-13614EGYPTIAN HIEROGLYPH-" +
"13615EGYPTIAN HIEROGLYPH-13616EGYPTIAN HIEROGLYPH-13617EGYPTIAN HIEROGLY" +
"PH-13618EGYPTIAN HIEROGLYPH-13619EGYPTIAN HIEROGLYPH-1361AEGYPTIAN HIERO" +
"GLYPH-1361BEGYPTIAN HIEROGLYPH-1361CEGYPTIAN HIEROGLYPH-1361DEGYPTIAN HI" +
"EROGLYPH-1361EEGYPTIAN HIEROGLYPH-1361FEGYPTIAN HIEROGLYPH-13620EGYPTIAN" +
" HIEROGLYPH-13621EGYPTIAN HIEROGLYPH-13622EGYPTIAN HIEROGLYPH-13623EGYPT" +
"IAN HIEROGLYPH-13624EGYPTIAN HIEROGLYPH-13625EGYPTIAN HIEROGLYPH-13626EG" +
"YPTIAN HIEROGLYPH-13627EGYPTIAN HIEROGLYPH-13628EGYPTIAN HIEROGLYPH-1362" +
"9EGYPTIAN HIEROGLYPH-1362AEGYPTIAN HIEROGLYPH-1362BEGYPTIAN HIEROGLYPH-1" +
"362CEGYPTIAN HIEROGLYPH-1362DEGYPTIAN HIEROGLYPH-1362EEGYPTIAN HIEROGLYP" +
"H-1362FEGYPTIAN HIEROGLYPH-13630EGYPTIAN HIEROGLYPH-13631EGYPTIAN HIEROG" +
"LYPH-13632EGYPTIAN HIEROGLYPH-13633EGYPTIAN HIEROGLYPH-13634EGYPTIAN HIE" +
"ROGLYPH-13635EGYPTIAN HIEROGLYPH-13636EGYPTIAN HIEROGLYPH-13637EGYPTIAN " +
"HIEROGLYPH-13638EGYPTIAN HIEROGLYPH-13639EGYPTIAN HIEROGLYPH-1363AEGYPTI" +
"AN HIEROGLYPH-1363BEGYPTIAN HIEROGLYPH-1363CEGYPTIAN HIEROGLYPH-1363DEGY" +
"PTIAN HIEROGLYPH-1363EEGYPTIAN HIEROGLYPH-1363FEGYPTIAN HIEROGLYPH-13640" +
"EGYPTIAN HIEROGLYPH-13641EGYPTIAN HIEROGLYPH-13642EGYPTIAN HIEROGLYPH-13" +
"643EGYPTIAN HIEROGLYPH-13644EGYPTIAN HIEROGLYPH-13645EGYPTIAN HIEROGLYPH" +
"-13646EGYPTIAN HIEROGLYPH-13647EGYPTIAN HIEROGLYPH-13648EGYPTIAN HIEROGL" +
"YPH-13649EGYPTIAN HIEROGLYPH-1364AEGYPTIAN HIEROGLYPH-1364BEGYPTIAN HIER" +
"OGLYPH-1364CEGYPTIAN HIEROGLYPH-1364DEGYPTIAN HIEROGLYPH-1364EEGYPTIAN H" +
"IEROGLYPH-1364FEGYPTIAN HIEROGLYPH-13650EGYPTIAN HIEROGLYPH-13651EGYPTIA" +
"N HIEROGLYPH-13652EGYPTIAN HIEROGLYPH-13653EGYPTIAN HIEROGLYPH-13654EGYP" +
"TIAN HIEROGLYPH-13655EGYPTIAN HIEROGLYPH-13656EGYPTIAN HIEROGLYPH-13657E" +
"GYPTIAN HIEROGLYPH-13658EGYPTIAN HIEROGLYPH-13659EGYPTIAN HIEROGLYPH-136" +
"5AEGYPTIAN HIEROGLYPH-1365BEGYPTIAN HIEROGLYPH-1365CEGYPTIAN HIEROGLYPH-" +
"1365DEGYPTIAN HIEROGLYPH-1365EEGYPTIAN HIEROGLYPH-1365FEGYPTIAN HIEROGLY" +
"PH-13660EGYPTIAN HIEROGLYPH-13661EGYPTIAN HIEROGLYPH-13662EGYPTIAN HIERO" +
"GLYPH-13663EGYPTIAN HIEROGLYPH-13664EGYPTIAN HIEROGLYPH-13665EGYPTIAN HI" +
"EROGLYPH-13666EGYPTIAN HIEROGLYPH-13667EGYPTIAN HIEROGLYPH-13668EGYPTIAN" +
" HIEROGLYPH-13669EGYPTIAN HIEROGLYPH-1366AEGYPTIAN HIEROGLYPH-1366BEGYPT" +
"IAN HIEROGLYPH-1366CEGYPTIAN HIEROGLYPH-1366DEGYPTIAN HIEROGLYPH-1366EEG" +
"YPTIAN HIEROGLYPH-1366FEGYPTIAN HIEROGLYPH-13670EGYPTIAN HIEROGLYPH-1367") + ("" +
"1EGYPTIAN HIEROGLYPH-13672EGYPTIAN HIEROGLYPH-13673EGYPTIAN HIEROGLYPH-1" +
"3674EGYPTIAN HIEROGLYPH-13675EGYPTIAN HIEROGLYPH-13676EGYPTIAN HIEROGLYP" +
"H-13677EGYPTIAN HIEROGLYPH-13678EGYPTIAN HIEROGLYPH-13679EGYPTIAN HIEROG" +
"LYPH-1367AEGYPTIAN HIEROGLYPH-1367BEGYPTIAN HIEROGLYPH-1367CEGYPTIAN HIE" +
"ROGLYPH-1367DEGYPTIAN HIEROGLYPH-1367EEGYPTIAN HIEROGLYPH-1367FEGYPTIAN " +
"HIEROGLYPH-13680EGYPTIAN HIEROGLYPH-13681EGYPTIAN HIEROGLYPH-13682EGYPTI" +
"AN HIEROGLYPH-13683EGYPTIAN HIEROGLYPH-13684EGYPTIAN HIEROGLYPH-13685EGY" +
"PTIAN HIEROGLYPH-13686EGYPTIAN HIEROGLYPH-13687EGYPTIAN HIEROGLYPH-13688" +
"EGYPTIAN HIEROGLYPH-13689EGYPTIAN HIEROGLYPH-1368AEGYPTIAN HIEROGLYPH-13" +
"68BEGYPTIAN HIEROGLYPH-1368CEGYPTIAN HIEROGLYPH-1368DEGYPTIAN HIEROGLYPH" +
"-1368EEGYPTIAN HIEROGLYPH-1368FEGYPTIAN HIEROGLYPH-13690EGYPTIAN HIEROGL" +
"YPH-13691EGYPTIAN HIEROGLYPH-13692EGYPTIAN HIEROGLYPH-13693EGYPTIAN HIER" +
"OGLYPH-13694EGYPTIAN HIEROGLYPH-13695EGYPTIAN HIEROGLYPH-13696EGYPTIAN H" +
"IEROGLYPH-13697EGYPTIAN HIEROGLYPH-13698EGYPTIAN HIEROGLYPH-13699EGYPTIA" +
"N HIEROGLYPH-1369AEGYPTIAN HIEROGLYPH-1369BEGYPTIAN HIEROGLYPH-1369CEGYP" +
"TIAN HIEROGLYPH-1369DEGYPTIAN HIEROGLYPH-1369EEGYPTIAN HIEROGLYPH-1369FE" +
"GYPTIAN HIEROGLYPH-136A0EGYPTIAN HIEROGLYPH-136A1EGYPTIAN HIEROGLYPH-136" +
"A2EGYPTIAN HIEROGLYPH-136A3EGYPTIAN HIEROGLYPH-136A4EGYPTIAN HIEROGLYPH-" +
"136A5EGYPTIAN HIEROGLYPH-136A6EGYPTIAN HIEROGLYPH-136A7EGYPTIAN HIEROGLY" +
"PH-136A8EGYPTIAN HIEROGLYPH-136A9EGYPTIAN HIEROGLYPH-136AAEGYPTIAN HIERO" +
"GLYPH-136ABEGYPTIAN HIEROGLYPH-136ACEGYPTIAN HIEROGLYPH-136ADEGYPTIAN HI" +
"EROGLYPH-136AEEGYPTIAN HIEROGLYPH-136AFEGYPTIAN HIEROGLYPH-136B0EGYPTIAN" +
" HIEROGLYPH-136B1EGYPTIAN HIEROGLYPH-136B2EGYPTIAN HIEROGLYPH-136B3EGYPT" +
"IAN HIEROGLYPH-136B4EGYPTIAN HIEROGLYPH-136B5EGYPTIAN HIEROGLYPH-136B6EG" +
"YPTIAN HIEROGLYPH-136B7EGYPTIAN HIEROGLYPH-136B8EGYPTIAN HIEROGLYPH-136B" +
"9EGYPTIAN HIEROGLYPH-136BAEGYPTIAN HIEROGLYPH-136BBEGYPTIAN HIEROGLYPH-1" +
"36BCEGYPTIAN HIEROGLYPH-136BDEGYPTIAN HIEROGLYPH-136BEEGYPTIAN HIEROGLYP" +
"H-136BFEGYPTIAN HIEROGLYPH-136C0EGYPTIAN HIEROGLYPH-136C1EGYPTIAN HIEROG" +
"LYPH-136C2EGYPTIAN HIEROGLYPH-136C3EGYPTIAN HIEROGLYPH-136C4EGYPTIAN HIE" +
"ROGLYPH-136C5EGYPTIAN HIEROGLYPH-136C6EGYPTIAN HIEROGLYPH-136C7EGYPTIAN " +
"HIEROGLYPH-136C8EGYPTIAN HIEROGLYPH-136C9EGYPTIAN HIEROGLYPH-136CAEGYPTI" +
"AN HIEROGLYPH-136CBEGYPTIAN HIEROGLYPH-136CCEGYPTIAN HIEROGLYPH-136CDEGY" +
"PTIAN HIEROGLYPH-136CEEGYPTIAN HIEROGLYPH-136CFEGYPTIAN HIEROGLYPH-136D0" +
"EGYPTIAN HIEROGLYPH-136D1EGYPTIAN HIEROGLYPH-136D2EGYPTIAN HIEROGLYPH-13" +
"6D3EGYPTIAN HIEROGLYPH-136D4EGYPTIAN HIEROGLYPH-136D5EGYPTIAN HIEROGLYPH" +
"-136D6EGYPTIAN HIEROGLYPH-136D7EGYPTIAN HIEROGLYPH-136D8EGYPTIAN HIEROGL" +
"YPH-136D9EGYPTIAN HIEROGLYPH-136DAEGYPTIAN HIEROGLYPH-136DBEGYPTIAN HIER" +
"OGLYPH-136DCEGYPTIAN HIEROGLYPH-136DDEGYPTIAN HIEROGLYPH-136DEEGYPTIAN H" +
"IEROGLYPH-136DFEGYPTIAN HIEROGLYPH-136E0EGYPTIAN HIEROGLYPH-136E1EGYPTIA" +
"N HIEROGLYPH-136E2EGYPTIAN HIEROGLYPH-136E3EGYPTIAN HIEROGLYPH-136E4EGYP" +
"TIAN HIEROGLYPH-136E5EGYPTIAN HIEROGLYPH-136E6EGYPTIAN HIEROGLYPH-136E7E" +
"GYPTIAN HIEROGLYPH-136E8EGYPTIAN HIEROGLYPH-136E9EGYPTIAN HIEROGLYPH-136" +
"EAEGYPTIAN HIEROGLYPH-136EBEGYPTIAN HIEROGLYPH-136ECEGYPTIAN HIEROGLYPH-" +
"136EDEGYPTIAN HIEROGLYPH-136EEEGYPTIAN HIEROGLYPH-136EFEGYPTIAN HIEROGLY" +
"PH-136F0EGYPTIAN HIEROGLYPH-136F1EGYPTIAN HIEROGLYPH-136F2EGYPTIAN HIERO" +
"GLYPH-136F3EGYPTIAN HIEROGLYPH-136F4EGYPTIAN HIEROGLYPH-136F5EGYPTIAN HI" +
"EROGLYPH-136F6EGYPTIAN HIEROGLYPH-136F7EGYPTIAN HIEROGLYPH-136F8EGYPTIAN" +
" HIEROGLYPH-136F9EGYPTIAN HIEROGLYPH-136FAEGYPTIAN HIEROGLYPH-136FBEGYPT" +
"IAN HIEROGLYPH-136FCEGYPTIAN HIEROGLYPH-136FDEGYPTIAN HIEROGLYPH-136FEEG" +
"YPTIAN HIEROGLYPH-136FFEGYPTIAN HIEROGLYPH-13700EGYPTIAN HIEROGLYPH-1370" +
"1EGYPTIAN HIEROGLYPH-13702EGYPTIAN HIEROGLYPH-13703EGYPTIAN HIEROGLYPH-1" +
"3704EGYPTIAN HIEROGLYPH-13705EGYPTIAN HIEROGLYPH-13706EGYPTIAN HIEROGLYP" +
"H-13707EGYPTIAN HIEROGLYPH-13708EGYPTIAN HIEROGLYPH-13709EGYPTIAN HIEROG" +
"LYPH-1370AEGYPTIAN HIEROGLYPH-1370BEGYPTIAN HIEROGLYPH-1370CEGYPTIAN HIE" +
"ROGLYPH-1370DEGYPTIAN HIEROGLYPH-1370EEGYPTIAN HIEROGLYPH-1370FEGYPTIAN " +
"HIEROGLYPH-13710EGYPTIAN HIEROGLYPH-13711EGYPTIAN HIEROGLYPH-13712EGYPTI" +
"AN HIEROGLYPH-13713EGYPTIAN HIEROGLYPH-13714EGYPTIAN HIEROGLYPH-13715EGY" +
"PTIAN HIEROGLYPH-13716EGYPTIAN HIEROGLYPH-13717EGYPTIAN HIEROGLYPH-13718" +
"EGYPTIAN HIEROGLYPH-13719EGYPTIAN HIEROGLYPH-1371AEGYPTIAN HIEROGLYPH-13" +
"71BEGYPTIAN HIEROGLYPH-1371CEGYPTIAN HIEROGLYPH-1371DEGYPTIAN HIEROGLYPH" +
"-1371EEGYPTIAN HIEROGLYPH-1371FEGYPTIAN HIEROGLYPH-13720EGYPTIAN HIEROGL" +
"YPH-13721EGYPTIAN HIEROGLYPH-13722EGYPTIAN HIEROGLYPH-13723EGYPTIAN HIER" +
"OGLYPH-13724EGYPTIAN HIEROGLYPH-13725EGYPTIAN HIEROGLYPH-13726EGYPTIAN H" +
"IEROGLYPH-13727EGYPTIAN HIEROGLYPH-13728EGYPTIAN HIEROGLYPH-13729EGYPTIA") + ("" +
"N HIEROGLYPH-1372AEGYPTIAN HIEROGLYPH-1372BEGYPTIAN HIEROGLYPH-1372CEGYP" +
"TIAN HIEROGLYPH-1372DEGYPTIAN HIEROGLYPH-1372EEGYPTIAN HIEROGLYPH-1372FE" +
"GYPTIAN HIEROGLYPH-13730EGYPTIAN HIEROGLYPH-13731EGYPTIAN HIEROGLYPH-137" +
"32EGYPTIAN HIEROGLYPH-13733EGYPTIAN HIEROGLYPH-13734EGYPTIAN HIEROGLYPH-" +
"13735EGYPTIAN HIEROGLYPH-13736EGYPTIAN HIEROGLYPH-13737EGYPTIAN HIEROGLY" +
"PH-13738EGYPTIAN HIEROGLYPH-13739EGYPTIAN HIEROGLYPH-1373AEGYPTIAN HIERO" +
"GLYPH-1373BEGYPTIAN HIEROGLYPH-1373CEGYPTIAN HIEROGLYPH-1373DEGYPTIAN HI" +
"EROGLYPH-1373EEGYPTIAN HIEROGLYPH-1373FEGYPTIAN HIEROGLYPH-13740EGYPTIAN" +
" HIEROGLYPH-13741EGYPTIAN HIEROGLYPH-13742EGYPTIAN HIEROGLYPH-13743EGYPT" +
"IAN HIEROGLYPH-13744EGYPTIAN HIEROGLYPH-13745EGYPTIAN HIEROGLYPH-13746EG" +
"YPTIAN HIEROGLYPH-13747EGYPTIAN HIEROGLYPH-13748EGYPTIAN HIEROGLYPH-1374" +
"9EGYPTIAN HIEROGLYPH-1374AEGYPTIAN HIEROGLYPH-1374BEGYPTIAN HIEROGLYPH-1" +
"374CEGYPTIAN HIEROGLYPH-1374DEGYPTIAN HIEROGLYPH-1374EEGYPTIAN HIEROGLYP" +
"H-1374FEGYPTIAN HIEROGLYPH-13750EGYPTIAN HIEROGLYPH-13751EGYPTIAN HIEROG" +
"LYPH-13752EGYPTIAN HIEROGLYPH-13753EGYPTIAN HIEROGLYPH-13754EGYPTIAN HIE" +
"ROGLYPH-13755EGYPTIAN HIEROGLYPH-13756EGYPTIAN HIEROGLYPH-13757EGYPTIAN " +
"HIEROGLYPH-13758EGYPTIAN HIEROGLYPH-13759EGYPTIAN HIEROGLYPH-1375AEGYPTI" +
"AN HIEROGLYPH-1375BEGYPTIAN HIEROGLYPH-1375CEGYPTIAN HIEROGLYPH-1375DEGY" +
"PTIAN HIEROGLYPH-1375EEGYPTIAN HIEROGLYPH-1375FEGYPTIAN HIEROGLYPH-13760" +
"EGYPTIAN HIEROGLYPH-13761EGYPTIAN HIEROGLYPH-13762EGYPTIAN HIEROGLYPH-13" +
"763EGYPTIAN HIEROGLYPH-13764EGYPTIAN HIEROGLYPH-13765EGYPTIAN HIEROGLYPH" +
"-13766EGYPTIAN HIEROGLYPH-13767EGYPTIAN HIEROGLYPH-13768EGYPTIAN HIEROGL" +
"YPH-13769EGYPTIAN HIEROGLYPH-1376AEGYPTIAN HIEROGLYPH-1376BEGYPTIAN HIER" +
"OGLYPH-1376CEGYPTIAN HIEROGLYPH-1376DEGYPTIAN HIEROGLYPH-1376EEGYPTIAN H" +
"IEROGLYPH-1376FEGYPTIAN HIEROGLYPH-13770EGYPTIAN HIEROGLYPH-13771EGYPTIA" +
"N HIEROGLYPH-13772EGYPTIAN HIEROGLYPH-13773EGYPTIAN HIEROGLYPH-13774EGYP" +
"TIAN HIEROGLYPH-13775EGYPTIAN HIEROGLYPH-13776EGYPTIAN HIEROGLYPH-13777E" +
"GYPTIAN HIEROGLYPH-13778EGYPTIAN HIEROGLYPH-13779EGYPTIAN HIEROGLYPH-137" +
"7AEGYPTIAN HIEROGLYPH-1377BEGYPTIAN HIEROGLYPH-1377CEGYPTIAN HIEROGLYPH-" +
"1377DEGYPTIAN HIEROGLYPH-1377EEGYPTIAN HIEROGLYPH-1377FEGYPTIAN HIEROGLY" +
"PH-13780EGYPTIAN HIEROGLYPH-13781EGYPTIAN HIEROGLYPH-13782EGYPTIAN HIERO" +
"GLYPH-13783EGYPTIAN HIEROGLYPH-13784EGYPTIAN HIEROGLYPH-13785EGYPTIAN HI" +
"EROGLYPH-13786EGYPTIAN HIEROGLYPH-13787EGYPTIAN HIEROGLYPH-13788EGYPTIAN" +
" HIEROGLYPH-13789EGYPTIAN HIEROGLYPH-1378AEGYPTIAN HIEROGLYPH-1378BEGYPT" +
"IAN HIEROGLYPH-1378CEGYPTIAN HIEROGLYPH-1378DEGYPTIAN HIEROGLYPH-1378EEG" +
"YPTIAN HIEROGLYPH-1378FEGYPTIAN HIEROGLYPH-13790EGYPTIAN HIEROGLYPH-1379" +
"1EGYPTIAN HIEROGLYPH-13792EGYPTIAN HIEROGLYPH-13793EGYPTIAN HIEROGLYPH-1" +
"3794EGYPTIAN HIEROGLYPH-13795EGYPTIAN HIEROGLYPH-13796EGYPTIAN HIEROGLYP" +
"H-13797EGYPTIAN HIEROGLYPH-13798EGYPTIAN HIEROGLYPH-13799EGYPTIAN HIEROG" +
"LYPH-1379AEGYPTIAN HIEROGLYPH-1379BEGYPTIAN HIEROGLYPH-1379CEGYPTIAN HIE" +
"ROGLYPH-1379DEGYPTIAN HIEROGLYPH-1379EEGYPTIAN HIEROGLYPH-1379FEGYPTIAN " +
"HIEROGLYPH-137A0EGYPTIAN HIEROGLYPH-137A1EGYPTIAN HIEROGLYPH-137A2EGYPTI" +
"AN HIEROGLYPH-137A3EGYPTIAN HIEROGLYPH-137A4EGYPTIAN HIEROGLYPH-137A5EGY" +
"PTIAN HIEROGLYPH-137A6EGYPTIAN HIEROGLYPH-137A7EGYPTIAN HIEROGLYPH-137A8" +
"EGYPTIAN HIEROGLYPH-137A9EGYPTIAN HIEROGLYPH-137AAEGYPTIAN HIEROGLYPH-13" +
"7ABEGYPTIAN HIEROGLYPH-137ACEGYPTIAN HIEROGLYPH-137ADEGYPTIAN HIEROGLYPH" +
"-137AEEGYPTIAN HIEROGLYPH-137AFEGYPTIAN HIEROGLYPH-137B0EGYPTIAN HIEROGL" +
"YPH-137B1EGYPTIAN HIEROGLYPH-137B2EGYPTIAN HIEROGLYPH-137B3EGYPTIAN HIER" +
"OGLYPH-137B4EGYPTIAN HIEROGLYPH-137B5EGYPTIAN HIEROGLYPH-137B6EGYPTIAN H" +
"IEROGLYPH-137B7EGYPTIAN HIEROGLYPH-137B8EGYPTIAN HIEROGLYPH-137B9EGYPTIA" +
"N HIEROGLYPH-137BAEGYPTIAN HIEROGLYPH-137BBEGYPTIAN HIEROGLYPH-137BCEGYP" +
"TIAN HIEROGLYPH-137BDEGYPTIAN HIEROGLYPH-137BEEGYPTIAN HIEROGLYPH-137BFE" +
"GYPTIAN HIEROGLYPH-137C0EGYPTIAN HIEROGLYPH-137C1EGYPTIAN HIEROGLYPH-137" +
"C2EGYPTIAN HIEROGLYPH-137C3EGYPTIAN HIEROGLYPH-137C4EGYPTIAN HIEROGLYPH-" +
"137C5EGYPTIAN HIEROGLYPH-137C6EGYPTIAN HIEROGLYPH-137C7EGYPTIAN HIEROGLY" +
"PH-137C8EGYPTIAN HIEROGLYPH-137C9EGYPTIAN HIEROGLYPH-137CAEGYPTIAN HIERO" +
"GLYPH-137CBEGYPTIAN HIEROGLYPH-137CCEGYPTIAN HIEROGLYPH-137CDEGYPTIAN HI" +
"EROGLYPH-137CEEGYPTIAN HIEROGLYPH-137CFEGYPTIAN HIEROGLYPH-137D0EGYPTIAN" +
" HIEROGLYPH-137D1EGYPTIAN HIEROGLYPH-137D2EGYPTIAN HIEROGLYPH-137D3EGYPT" +
"IAN HIEROGLYPH-137D4EGYPTIAN HIEROGLYPH-137D5EGYPTIAN HIEROGLYPH-137D6EG" +
"YPTIAN HIEROGLYPH-137D7EGYPTIAN HIEROGLYPH-137D8EGYPTIAN HIEROGLYPH-137D" +
"9EGYPTIAN HIEROGLYPH-137DAEGYPTIAN HIEROGLYPH-137DBEGYPTIAN HIEROGLYPH-1" +
"37DCEGYPTIAN HIEROGLYPH-137DDEGYPTIAN HIEROGLYPH-137DEEGYPTIAN HIEROGLYP" +
"H-137DFEGYPTIAN HIEROGLYPH-137E0EGYPTIAN HIEROGLYPH-137E1EGYPTIAN HIEROG") + ("" +
"LYPH-137E2EGYPTIAN HIEROGLYPH-137E3EGYPTIAN HIEROGLYPH-137E4EGYPTIAN HIE" +
"ROGLYPH-137E5EGYPTIAN HIEROGLYPH-137E6EGYPTIAN HIEROGLYPH-137E7EGYPTIAN " +
"HIEROGLYPH-137E8EGYPTIAN HIEROGLYPH-137E9EGYPTIAN HIEROGLYPH-137EAEGYPTI" +
"AN HIEROGLYPH-137EBEGYPTIAN HIEROGLYPH-137ECEGYPTIAN HIEROGLYPH-137EDEGY" +
"PTIAN HIEROGLYPH-137EEEGYPTIAN HIEROGLYPH-137EFEGYPTIAN HIEROGLYPH-137F0" +
"EGYPTIAN HIEROGLYPH-137F1EGYPTIAN HIEROGLYPH-137F2EGYPTIAN HIEROGLYPH-13" +
"7F3EGYPTIAN HIEROGLYPH-137F4EGYPTIAN HIEROGLYPH-137F5EGYPTIAN HIEROGLYPH" +
"-137F6EGYPTIAN HIEROGLYPH-137F7EGYPTIAN HIEROGLYPH-137F8EGYPTIAN HIEROGL" +
"YPH-137F9EGYPTIAN HIEROGLYPH-137FAEGYPTIAN HIEROGLYPH-137FBEGYPTIAN HIER" +
"OGLYPH-137FCEGYPTIAN HIEROGLYPH-137FDEGYPTIAN HIEROGLYPH-137FEEGYPTIAN H" +
"IEROGLYPH-137FFEGYPTIAN HIEROGLYPH-13800EGYPTIAN HIEROGLYPH-13801EGYPTIA" +
"N HIEROGLYPH-13802EGYPTIAN HIEROGLYPH-13803EGYPTIAN HIEROGLYPH-13804EGYP" +
"TIAN HIEROGLYPH-13805EGYPTIAN HIEROGLYPH-13806EGYPTIAN HIEROGLYPH-13807E" +
"GYPTIAN HIEROGLYPH-13808EGYPTIAN HIEROGLYPH-13809EGYPTIAN HIEROGLYPH-138" +
"0AEGYPTIAN HIEROGLYPH-1380BEGYPTIAN HIEROGLYPH-1380CEGYPTIAN HIEROGLYPH-" +
"1380DEGYPTIAN HIEROGLYPH-1380EEGYPTIAN HIEROGLYPH-1380FEGYPTIAN HIEROGLY" +
"PH-13810EGYPTIAN HIEROGLYPH-13811EGYPTIAN HIEROGLYPH-13812EGYPTIAN HIERO" +
"GLYPH-13813EGYPTIAN HIEROGLYPH-13814EGYPTIAN HIEROGLYPH-13815EGYPTIAN HI" +
"EROGLYPH-13816EGYPTIAN HIEROGLYPH-13817EGYPTIAN HIEROGLYPH-13818EGYPTIAN" +
" HIEROGLYPH-13819EGYPTIAN HIEROGLYPH-1381AEGYPTIAN HIEROGLYPH-1381BEGYPT" +
"IAN HIEROGLYPH-1381CEGYPTIAN HIEROGLYPH-1381DEGYPTIAN HIEROGLYPH-1381EEG" +
"YPTIAN HIEROGLYPH-1381FEGYPTIAN HIEROGLYPH-13820EGYPTIAN HIEROGLYPH-1382" +
"1EGYPTIAN HIEROGLYPH-13822EGYPTIAN HIEROGLYPH-13823EGYPTIAN HIEROGLYPH-1" +
"3824EGYPTIAN HIEROGLYPH-13825EGYPTIAN HIEROGLYPH-13826EGYPTIAN HIEROGLYP" +
"H-13827EGYPTIAN HIEROGLYPH-13828EGYPTIAN HIEROGLYPH-13829EGYPTIAN HIEROG" +
"LYPH-1382AEGYPTIAN HIEROGLYPH-1382BEGYPTIAN HIEROGLYPH-1382CEGYPTIAN HIE" +
"ROGLYPH-1382DEGYPTIAN HIEROGLYPH-1382EEGYPTIAN HIEROGLYPH-1382FEGYPTIAN " +
"HIEROGLYPH-13830EGYPTIAN HIEROGLYPH-13831EGYPTIAN HIEROGLYPH-13832EGYPTI" +
"AN HIEROGLYPH-13833EGYPTIAN HIEROGLYPH-13834EGYPTIAN HIEROGLYPH-13835EGY" +
"PTIAN HIEROGLYPH-13836EGYPTIAN HIEROGLYPH-13837EGYPTIAN HIEROGLYPH-13838" +
"EGYPTIAN HIEROGLYPH-13839EGYPTIAN HIEROGLYPH-1383AEGYPTIAN HIEROGLYPH-13" +
"83BEGYPTIAN HIEROGLYPH-1383CEGYPTIAN HIEROGLYPH-1383DEGYPTIAN HIEROGLYPH" +
"-1383EEGYPTIAN HIEROGLYPH-1383FEGYPTIAN HIEROGLYPH-13840EGYPTIAN HIEROGL" +
"YPH-13841EGYPTIAN HIEROGLYPH-13842EGYPTIAN HIEROGLYPH-13843EGYPTIAN HIER" +
"OGLYPH-13844EGYPTIAN HIEROGLYPH-13845EGYPTIAN HIEROGLYPH-13846EGYPTIAN H" +
"IEROGLYPH-13847EGYPTIAN HIEROGLYPH-13848EGYPTIAN HIEROGLYPH-13849EGYPTIA" +
"N HIEROGLYPH-1384AEGYPTIAN HIEROGLYPH-1384BEGYPTIAN HIEROGLYPH-1384CEGYP" +
"TIAN HIEROGLYPH-1384DEGYPTIAN HIEROGLYPH-1384EEGYPTIAN HIEROGLYPH-1384FE" +
"GYPTIAN HIEROGLYPH-13850EGYPTIAN HIEROGLYPH-13851EGYPTIAN HIEROGLYPH-138" +
"52EGYPTIAN HIEROGLYPH-13853EGYPTIAN HIEROGLYPH-13854EGYPTIAN HIEROGLYPH-" +
"13855EGYPTIAN HIEROGLYPH-13856EGYPTIAN HIEROGLYPH-13857EGYPTIAN HIEROGLY" +
"PH-13858EGYPTIAN HIEROGLYPH-13859EGYPTIAN HIEROGLYPH-1385AEGYPTIAN HIERO" +
"GLYPH-1385BEGYPTIAN HIEROGLYPH-1385CEGYPTIAN HIEROGLYPH-1385DEGYPTIAN HI" +
"EROGLYPH-1385EEGYPTIAN HIEROGLYPH-1385FEGYPTIAN HIEROGLYPH-13860EGYPTIAN" +
" HIEROGLYPH-13861EGYPTIAN HIEROGLYPH-13862EGYPTIAN HIEROGLYPH-13863EGYPT" +
"IAN HIEROGLYPH-13864EGYPTIAN HIEROGLYPH-13865EGYPTIAN HIEROGLYPH-13866EG" +
"YPTIAN HIEROGLYPH-13867EGYPTIAN HIEROGLYPH-13868EGYPTIAN HIEROGLYPH-1386" +
"9EGYPTIAN HIEROGLYPH-1386AEGYPTIAN HIEROGLYPH-1386BEGYPTIAN HIEROGLYPH-1" +
"386CEGYPTIAN HIEROGLYPH-1386DEGYPTIAN HIEROGLYPH-1386EEGYPTIAN HIEROGLYP" +
"H-1386FEGYPTIAN HIEROGLYPH-13870EGYPTIAN HIEROGLYPH-13871EGYPTIAN HIEROG" +
"LYPH-13872EGYPTIAN HIEROGLYPH-13873EGYPTIAN HIEROGLYPH-13874EGYPTIAN HIE" +
"ROGLYPH-13875EGYPTIAN HIEROGLYPH-13876EGYPTIAN HIEROGLYPH-13877EGYPTIAN " +
"HIEROGLYPH-13878EGYPTIAN HIEROGLYPH-13879EGYPTIAN HIEROGLYPH-1387AEGYPTI" +
"AN HIEROGLYPH-1387BEGYPTIAN HIEROGLYPH-1387CEGYPTIAN HIEROGLYPH-1387DEGY" +
"PTIAN HIEROGLYPH-1387EEGYPTIAN HIEROGLYPH-1387FEGYPTIAN HIEROGLYPH-13880" +
"EGYPTIAN HIEROGLYPH-13881EGYPTIAN HIEROGLYPH-13882EGYPTIAN HIEROGLYPH-13" +
"883EGYPTIAN HIEROGLYPH-13884EGYPTIAN HIEROGLYPH-13885EGYPTIAN HIEROGLYPH" +
"-13886EGYPTIAN HIEROGLYPH-13887EGYPTIAN HIEROGLYPH-13888EGYPTIAN HIEROGL" +
"YPH-13889EGYPTIAN HIEROGLYPH-1388AEGYPTIAN HIEROGLYPH-1388BEGYPTIAN HIER" +
"OGLYPH-1388CEGYPTIAN HIEROGLYPH-1388DEGYPTIAN HIEROGLYPH-1388EEGYPTIAN H" +
"IEROGLYPH-1388FEGYPTIAN HIEROGLYPH-13890EGYPTIAN HIEROGLYPH-13891EGYPTIA" +
"N HIEROGLYPH-13892EGYPTIAN HIEROGLYPH-13893EGYPTIAN HIEROGLYPH-13894EGYP" +
"TIAN HIEROGLYPH-13895EGYPTIAN HIEROGLYPH-13896EGYPTIAN HIEROGLYPH-13897E" +
"GYPTIAN HIEROGLYPH-13898EGYPTIAN HIEROGLYPH-13899EGYPTIAN HIEROGLYPH-138") + ("" +
"9AEGYPTIAN HIEROGLYPH-1389BEGYPTIAN HIEROGLYPH-1389CEGYPTIAN HIEROGLYPH-" +
"1389DEGYPTIAN HIEROGLYPH-1389EEGYPTIAN HIEROGLYPH-1389FEGYPTIAN HIEROGLY" +
"PH-138A0EGYPTIAN HIEROGLYPH-138A1EGYPTIAN HIEROGLYPH-138A2EGYPTIAN HIERO" +
"GLYPH-138A3EGYPTIAN HIEROGLYPH-138A4EGYPTIAN HIEROGLYPH-138A5EGYPTIAN HI" +
"EROGLYPH-138A6EGYPTIAN HIEROGLYPH-138A7EGYPTIAN HIEROGLYPH-138A8EGYPTIAN" +
" HIEROGLYPH-138A9EGYPTIAN HIEROGLYPH-138AAEGYPTIAN HIEROGLYPH-138ABEGYPT" +
"IAN HIEROGLYPH-138ACEGYPTIAN HIEROGLYPH-138ADEGYPTIAN HIEROGLYPH-138AEEG" +
"YPTIAN HIEROGLYPH-138AFEGYPTIAN HIEROGLYPH-138B0EGYPTIAN HIEROGLYPH-138B" +
"1EGYPTIAN HIEROGLYPH-138B2EGYPTIAN HIEROGLYPH-138B3EGYPTIAN HIEROGLYPH-1" +
"38B4EGYPTIAN HIEROGLYPH-138B5EGYPTIAN HIEROGLYPH-138B6EGYPTIAN HIEROGLYP" +
"H-138B7EGYPTIAN HIEROGLYPH-138B8EGYPTIAN HIEROGLYPH-138B9EGYPTIAN HIEROG" +
"LYPH-138BAEGYPTIAN HIEROGLYPH-138BBEGYPTIAN HIEROGLYPH-138BCEGYPTIAN HIE" +
"ROGLYPH-138BDEGYPTIAN HIEROGLYPH-138BEEGYPTIAN HIEROGLYPH-138BFEGYPTIAN " +
"HIEROGLYPH-138C0EGYPTIAN HIEROGLYPH-138C1EGYPTIAN HIEROGLYPH-138C2EGYPTI" +
"AN HIEROGLYPH-138C3EGYPTIAN HIEROGLYPH-138C4EGYPTIAN HIEROGLYPH-138C5EGY" +
"PTIAN HIEROGLYPH-138C6EGYPTIAN HIEROGLYPH-138C7EGYPTIAN HIEROGLYPH-138C8" +
"EGYPTIAN HIEROGLYPH-138C9EGYPTIAN HIEROGLYPH-138CAEGYPTIAN HIEROGLYPH-13" +
"8CBEGYPTIAN HIEROGLYPH-138CCEGYPTIAN HIEROGLYPH-138CDEGYPTIAN HIEROGLYPH" +
"-138CEEGYPTIAN HIEROGLYPH-138CFEGYPTIAN HIEROGLYPH-138D0EGYPTIAN HIEROGL" +
"YPH-138D1EGYPTIAN HIEROGLYPH-138D2EGYPTIAN HIEROGLYPH-138D3EGYPTIAN HIER" +
"OGLYPH-138D4EGYPTIAN HIEROGLYPH-138D5EGYPTIAN HIEROGLYPH-138D6EGYPTIAN H" +
"IEROGLYPH-138D7EGYPTIAN HIEROGLYPH-138D8EGYPTIAN HIEROGLYPH-138D9EGYPTIA" +
"N HIEROGLYPH-138DAEGYPTIAN HIEROGLYPH-138DBEGYPTIAN HIEROGLYPH-138DCEGYP" +
"TIAN HIEROGLYPH-138DDEGYPTIAN HIEROGLYPH-138DEEGYPTIAN HIEROGLYPH-138DFE" +
"GYPTIAN HIEROGLYPH-138E0EGYPTIAN HIEROGLYPH-138E1EGYPTIAN HIEROGLYPH-138" +
"E2EGYPTIAN HIEROGLYPH-138E3EGYPTIAN HIEROGLYPH-138E4EGYPTIAN HIEROGLYPH-" +
"138E5EGYPTIAN HIEROGLYPH-138E6EGYPTIAN HIEROGLYPH-138E7EGYPTIAN HIEROGLY" +
"PH-138E8EGYPTIAN HIEROGLYPH-138E9EGYPTIAN HIEROGLYPH-138EAEGYPTIAN HIERO" +
"GLYPH-138EBEGYPTIAN HIEROGLYPH-138ECEGYPTIAN HIEROGLYPH-138EDEGYPTIAN HI" +
"EROGLYPH-138EEEGYPTIAN HIEROGLYPH-138EFEGYPTIAN HIEROGLYPH-138F0EGYPTIAN" +
" HIEROGLYPH-138F1EGYPTIAN HIEROGLYPH-138F2EGYPTIAN HIEROGLYPH-138F3EGYPT" +
"IAN HIEROGLYPH-138F4EGYPTIAN HIEROGLYPH-138F5EGYPTIAN HIEROGLYPH-138F6EG" +
"YPTIAN HIEROGLYPH-138F7EGYPTIAN HIEROGLYPH-138F8EGYPTIAN HIEROGLYPH-138F" +
"9EGYPTIAN HIEROGLYPH-138FAEGYPTIAN HIEROGLYPH-138FBEGYPTIAN HIEROGLYPH-1" +
"38FCEGYPTIAN HIEROGLYPH-138FDEGYPTIAN HIEROGLYPH-138FEEGYPTIAN HIEROGLYP" +
"H-138FFEGYPTIAN HIEROGLYPH-13900EGYPTIAN HIEROGLYPH-13901EGYPTIAN HIEROG" +
"LYPH-13902EGYPTIAN HIEROGLYPH-13903EGYPTIAN HIEROGLYPH-13904EGYPTIAN HIE" +
"ROGLYPH-13905EGYPTIAN HIEROGLYPH-13906EGYPTIAN HIEROGLYPH-13907EGYPTIAN " +
"HIEROGLYPH-13908EGYPTIAN HIEROGLYPH-13909EGYPTIAN HIEROGLYPH-1390AEGYPTI" +
"AN HIEROGLYPH-1390BEGYPTIAN HIEROGLYPH-1390CEGYPTIAN HIEROGLYPH-1390DEGY" +
"PTIAN HIEROGLYPH-1390EEGYPTIAN HIEROGLYPH-1390FEGYPTIAN HIEROGLYPH-13910" +
"EGYPTIAN HIEROGLYPH-13911EGYPTIAN HIEROGLYPH-13912EGYPTIAN HIEROGLYPH-13" +
"913EGYPTIAN HIEROGLYPH-13914EGYPTIAN HIEROGLYPH-13915EGYPTIAN HIEROGLYPH" +
"-13916EGYPTIAN HIEROGLYPH-13917EGYPTIAN HIEROGLYPH-13918EGYPTIAN HIEROGL" +
"YPH-13919EGYPTIAN HIEROGLYPH-1391AEGYPTIAN HIEROGLYPH-1391BEGYPTIAN HIER" +
"OGLYPH-1391CEGYPTIAN HIEROGLYPH-1391DEGYPTIAN HIEROGLYPH-1391EEGYPTIAN H" +
"IEROGLYPH-1391FEGYPTIAN HIEROGLYPH-13920EGYPTIAN HIEROGLYPH-13921EGYPTIA" +
"N HIEROGLYPH-13922EGYPTIAN HIEROGLYPH-13923EGYPTIAN HIEROGLYPH-13924EGYP" +
"TIAN HIEROGLYPH-13925EGYPTIAN HIEROGLYPH-13926EGYPTIAN HIEROGLYPH-13927E" +
"GYPTIAN HIEROGLYPH-13928EGYPTIAN HIEROGLYPH-13929EGYPTIAN HIEROGLYPH-139" +
"2AEGYPTIAN HIEROGLYPH-1392BEGYPTIAN HIEROGLYPH-1392CEGYPTIAN HIEROGLYPH-" +
"1392DEGYPTIAN HIEROGLYPH-1392EEGYPTIAN HIEROGLYPH-1392FEGYPTIAN HIEROGLY" +
"PH-13930EGYPTIAN HIEROGLYPH-13931EGYPTIAN HIEROGLYPH-13932EGYPTIAN HIERO" +
"GLYPH-13933EGYPTIAN HIEROGLYPH-13934EGYPTIAN HIEROGLYPH-13935EGYPTIAN HI" +
"EROGLYPH-13936EGYPTIAN HIEROGLYPH-13937EGYPTIAN HIEROGLYPH-13938EGYPTIAN" +
" HIEROGLYPH-13939EGYPTIAN HIEROGLYPH-1393AEGYPTIAN HIEROGLYPH-1393BEGYPT" +
"IAN HIEROGLYPH-1393CEGYPTIAN HIEROGLYPH-1393DEGYPTIAN HIEROGLYPH-1393EEG" +
"YPTIAN HIEROGLYPH-1393FEGYPTIAN HIEROGLYPH-13940EGYPTIAN HIEROGLYPH-1394" +
"1EGYPTIAN HIEROGLYPH-13942EGYPTIAN HIEROGLYPH-13943EGYPTIAN HIEROGLYPH-1" +
"3944EGYPTIAN HIEROGLYPH-13945EGYPTIAN HIEROGLYPH-13946EGYPTIAN HIEROGLYP" +
"H-13947EGYPTIAN HIEROGLYPH-13948EGYPTIAN HIEROGLYPH-13949EGYPTIAN HIEROG" +
"LYPH-1394AEGYPTIAN HIEROGLYPH-1394BEGYPTIAN HIEROGLYPH-1394CEGYPTIAN HIE" +
"ROGLYPH-1394DEGYPTIAN HIEROGLYPH-1394EEGYPTIAN HIEROGLYPH-1394FEGYPTIAN " +
"HIEROGLYPH-13950EGYPTIAN HIEROGLYPH-13951EGYPTIAN HIEROGLYPH-13952EGYPTI") + ("" +
"AN HIEROGLYPH-13953EGYPTIAN HIEROGLYPH-13954EGYPTIAN HIEROGLYPH-13955EGY" +
"PTIAN HIEROGLYPH-13956EGYPTIAN HIEROGLYPH-13957EGYPTIAN HIEROGLYPH-13958" +
"EGYPTIAN HIEROGLYPH-13959EGYPTIAN HIEROGLYPH-1395AEGYPTIAN HIEROGLYPH-13" +
"95BEGYPTIAN HIEROGLYPH-1395CEGYPTIAN HIEROGLYPH-1395DEGYPTIAN HIEROGLYPH" +
"-1395EEGYPTIAN HIEROGLYPH-1395FEGYPTIAN HIEROGLYPH-13960EGYPTIAN HIEROGL" +
"YPH-13961EGYPTIAN HIEROGLYPH-13962EGYPTIAN HIEROGLYPH-13963EGYPTIAN HIER" +
"OGLYPH-13964EGYPTIAN HIEROGLYPH-13965EGYPTIAN HIEROGLYPH-13966EGYPTIAN H" +
"IEROGLYPH-13967EGYPTIAN HIEROGLYPH-13968EGYPTIAN HIEROGLYPH-13969EGYPTIA" +
"N HIEROGLYPH-1396AEGYPTIAN HIEROGLYPH-1396BEGYPTIAN HIEROGLYPH-1396CEGYP" +
"TIAN HIEROGLYPH-1396DEGYPTIAN HIEROGLYPH-1396EEGYPTIAN HIEROGLYPH-1396FE" +
"GYPTIAN HIEROGLYPH-13970EGYPTIAN HIEROGLYPH-13971EGYPTIAN HIEROGLYPH-139" +
"72EGYPTIAN HIEROGLYPH-13973EGYPTIAN HIEROGLYPH-13974EGYPTIAN HIEROGLYPH-" +
"13975EGYPTIAN HIEROGLYPH-13976EGYPTIAN HIEROGLYPH-13977EGYPTIAN HIEROGLY" +
"PH-13978EGYPTIAN HIEROGLYPH-13979EGYPTIAN HIEROGLYPH-1397AEGYPTIAN HIERO" +
"GLYPH-1397BEGYPTIAN HIEROGLYPH-1397CEGYPTIAN HIEROGLYPH-1397DEGYPTIAN HI" +
"EROGLYPH-1397EEGYPTIAN HIEROGLYPH-1397FEGYPTIAN HIEROGLYPH-13980EGYPTIAN" +
" HIEROGLYPH-13981EGYPTIAN HIEROGLYPH-13982EGYPTIAN HIEROGLYPH-13983EGYPT" +
"IAN HIEROGLYPH-13984EGYPTIAN HIEROGLYPH-13985EGYPTIAN HIEROGLYPH-13986EG" +
"YPTIAN HIEROGLYPH-13987EGYPTIAN HIEROGLYPH-13988EGYPTIAN HIEROGLYPH-1398" +
"9EGYPTIAN HIEROGLYPH-1398AEGYPTIAN HIEROGLYPH-1398BEGYPTIAN HIEROGLYPH-1" +
"398CEGYPTIAN HIEROGLYPH-1398DEGYPTIAN HIEROGLYPH-1398EEGYPTIAN HIEROGLYP" +
"H-1398FEGYPTIAN HIEROGLYPH-13990EGYPTIAN HIEROGLYPH-13991EGYPTIAN HIEROG" +
"LYPH-13992EGYPTIAN HIEROGLYPH-13993EGYPTIAN HIEROGLYPH-13994EGYPTIAN HIE" +
"ROGLYPH-13995EGYPTIAN HIEROGLYPH-13996EGYPTIAN HIEROGLYPH-13997EGYPTIAN " +
"HIEROGLYPH-13998EGYPTIAN HIEROGLYPH-13999EGYPTIAN HIEROGLYPH-1399AEGYPTI" +
"AN HIEROGLYPH-1399BEGYPTIAN HIEROGLYPH-1399CEGYPTIAN HIEROGLYPH-1399DEGY" +
"PTIAN HIEROGLYPH-1399EEGYPTIAN HIEROGLYPH-1399FEGYPTIAN HIEROGLYPH-139A0" +
"EGYPTIAN HIEROGLYPH-139A1EGYPTIAN HIEROGLYPH-139A2EGYPTIAN HIEROGLYPH-13" +
"9A3EGYPTIAN HIEROGLYPH-139A4EGYPTIAN HIEROGLYPH-139A5EGYPTIAN HIEROGLYPH" +
"-139A6EGYPTIAN HIEROGLYPH-139A7EGYPTIAN HIEROGLYPH-139A8EGYPTIAN HIEROGL" +
"YPH-139A9EGYPTIAN HIEROGLYPH-139AAEGYPTIAN HIEROGLYPH-139ABEGYPTIAN HIER" +
"OGLYPH-139ACEGYPTIAN HIEROGLYPH-139ADEGYPTIAN HIEROGLYPH-139AEEGYPTIAN H" +
"IEROGLYPH-139AFEGYPTIAN HIEROGLYPH-139B0EGYPTIAN HIEROGLYPH-139B1EGYPTIA" +
"N HIEROGLYPH-139B2EGYPTIAN HIEROGLYPH-139B3EGYPTIAN HIEROGLYPH-139B4EGYP" +
"TIAN HIEROGLYPH-139B5EGYPTIAN HIEROGLYPH-139B6EGYPTIAN HIEROGLYPH-139B7E" +
"GYPTIAN HIEROGLYPH-139B8EGYPTIAN HIEROGLYPH-139B9EGYPTIAN HIEROGLYPH-139" +
"BAEGYPTIAN HIEROGLYPH-139BBEGYPTIAN HIEROGLYPH-139BCEGYPTIAN HIEROGLYPH-" +
"139BDEGYPTIAN HIEROGLYPH-139BEEGYPTIAN HIEROGLYPH-139BFEGYPTIAN HIEROGLY" +
"PH-139C0EGYPTIAN HIEROGLYPH-139C1EGYPTIAN HIEROGLYPH-139C2EGYPTIAN HIERO" +
"GLYPH-139C3EGYPTIAN HIEROGLYPH-139C4EGYPTIAN HIEROGLYPH-139C5EGYPTIAN HI" +
"EROGLYPH-139C6EGYPTIAN HIEROGLYPH-139C7EGYPTIAN HIEROGLYPH-139C8EGYPTIAN" +
" HIEROGLYPH-139C9EGYPTIAN HIEROGLYPH-139CAEGYPTIAN HIEROGLYPH-139CBEGYPT" +
"IAN HIEROGLYPH-139CCEGYPTIAN HIEROGLYPH-139CDEGYPTIAN HIEROGLYPH-139CEEG" +
"YPTIAN HIEROGLYPH-139CFEGYPTIAN HIEROGLYPH-139D0EGYPTIAN HIEROGLYPH-139D" +
"1EGYPTIAN HIEROGLYPH-139D2EGYPTIAN HIEROGLYPH-139D3EGYPTIAN HIEROGLYPH-1" +
"39D4EGYPTIAN HIEROGLYPH-139D5EGYPTIAN HIEROGLYPH-139D6EGYPTIAN HIEROGLYP" +
"H-139D7EGYPTIAN HIEROGLYPH-139D8EGYPTIAN HIEROGLYPH-139D9EGYPTIAN HIEROG" +
"LYPH-139DAEGYPTIAN HIEROGLYPH-139DBEGYPTIAN HIEROGLYPH-139DCEGYPTIAN HIE" +
"ROGLYPH-139DDEGYPTIAN HIEROGLYPH-139DEEGYPTIAN HIEROGLYPH-139DFEGYPTIAN " +
"HIEROGLYPH-139E0EGYPTIAN HIEROGLYPH-139E1EGYPTIAN HIEROGLYPH-139E2EGYPTI" +
"AN HIEROGLYPH-139E3EGYPTIAN HIEROGLYPH-139E4EGYPTIAN HIEROGLYPH-139E5EGY" +
"PTIAN HIEROGLYPH-139E6EGYPTIAN HIEROGLYPH-139E7EGYPTIAN HIEROGLYPH-139E8" +
"EGYPTIAN HIEROGLYPH-139E9EGYPTIAN HIEROGLYPH-139EAEGYPTIAN HIEROGLYPH-13" +
"9EBEGYPTIAN HIEROGLYPH-139ECEGYPTIAN HIEROGLYPH-139EDEGYPTIAN HIEROGLYPH" +
"-139EEEGYPTIAN HIEROGLYPH-139EFEGYPTIAN HIEROGLYPH-139F0EGYPTIAN HIEROGL" +
"YPH-139F1EGYPTIAN HIEROGLYPH-139F2EGYPTIAN HIEROGLYPH-139F3EGYPTIAN HIER" +
"OGLYPH-139F4EGYPTIAN HIEROGLYPH-139F5EGYPTIAN HIEROGLYPH-139F6EGYPTIAN H" +
"IEROGLYPH-139F7EGYPTIAN HIEROGLYPH-139F8EGYPTIAN HIEROGLYPH-139F9EGYPTIA" +
"N HIEROGLYPH-139FAEGYPTIAN HIEROGLYPH-139FBEGYPTIAN HIEROGLYPH-139FCEGYP" +
"TIAN HIEROGLYPH-139FDEGYPTIAN HIEROGLYPH-139FEEGYPTIAN HIEROGLYPH-139FFE" +
"GYPTIAN HIEROGLYPH-13A00EGYPTIAN HIEROGLYPH-13A01EGYPTIAN HIEROGLYPH-13A" +
"02EGYPTIAN HIEROGLYPH-13A03EGYPTIAN HIEROGLYPH-13A04EGYPTIAN HIEROGLYPH-" +
"13A05EGYPTIAN HIEROGLYPH-13A06EGYPTIAN HIEROGLYPH-13A07EGYPTIAN HIEROGLY" +
"PH-13A08EGYPTIAN HIEROGLYPH-13A09EGYPTIAN HIEROGLYPH-13A0AEGYPTIAN HIERO") + ("" +
"GLYPH-13A0BEGYPTIAN HIEROGLYPH-13A0CEGYPTIAN HIEROGLYPH-13A0DEGYPTIAN HI" +
"EROGLYPH-13A0EEGYPTIAN HIEROGLYPH-13A0FEGYPTIAN HIEROGLYPH-13A10EGYPTIAN" +
" HIEROGLYPH-13A11EGYPTIAN HIEROGLYPH-13A12EGYPTIAN HIEROGLYPH-13A13EGYPT" +
"IAN HIEROGLYPH-13A14EGYPTIAN HIEROGLYPH-13A15EGYPTIAN HIEROGLYPH-13A16EG" +
"YPTIAN HIEROGLYPH-13A17EGYPTIAN HIEROGLYPH-13A18EGYPTIAN HIEROGLYPH-13A1" +
"9EGYPTIAN HIEROGLYPH-13A1AEGYPTIAN HIEROGLYPH-13A1BEGYPTIAN HIEROGLYPH-1" +
"3A1CEGYPTIAN HIEROGLYPH-13A1DEGYPTIAN HIEROGLYPH-13A1EEGYPTIAN HIEROGLYP" +
"H-13A1FEGYPTIAN HIEROGLYPH-13A20EGYPTIAN HIEROGLYPH-13A21EGYPTIAN HIEROG" +
"LYPH-13A22EGYPTIAN HIEROGLYPH-13A23EGYPTIAN HIEROGLYPH-13A24EGYPTIAN HIE" +
"ROGLYPH-13A25EGYPTIAN HIEROGLYPH-13A26EGYPTIAN HIEROGLYPH-13A27EGYPTIAN " +
"HIEROGLYPH-13A28EGYPTIAN HIEROGLYPH-13A29EGYPTIAN HIEROGLYPH-13A2AEGYPTI" +
"AN HIEROGLYPH-13A2BEGYPTIAN HIEROGLYPH-13A2CEGYPTIAN HIEROGLYPH-13A2DEGY" +
"PTIAN HIEROGLYPH-13A2EEGYPTIAN HIEROGLYPH-13A2FEGYPTIAN HIEROGLYPH-13A30" +
"EGYPTIAN HIEROGLYPH-13A31EGYPTIAN HIEROGLYPH-13A32EGYPTIAN HIEROGLYPH-13" +
"A33EGYPTIAN HIEROGLYPH-13A34EGYPTIAN HIEROGLYPH-13A35EGYPTIAN HIEROGLYPH" +
"-13A36EGYPTIAN HIEROGLYPH-13A37EGYPTIAN HIEROGLYPH-13A38EGYPTIAN HIEROGL" +
"YPH-13A39EGYPTIAN HIEROGLYPH-13A3AEGYPTIAN HIEROGLYPH-13A3BEGYPTIAN HIER" +
"OGLYPH-13A3CEGYPTIAN HIEROGLYPH-13A3DEGYPTIAN HIEROGLYPH-13A3EEGYPTIAN H" +
"IEROGLYPH-13A3FEGYPTIAN HIEROGLYPH-13A40EGYPTIAN HIEROGLYPH-13A41EGYPTIA" +
"N HIEROGLYPH-13A42EGYPTIAN HIEROGLYPH-13A43EGYPTIAN HIEROGLYPH-13A44EGYP" +
"TIAN HIEROGLYPH-13A45EGYPTIAN HIEROGLYPH-13A46EGYPTIAN HIEROGLYPH-13A47E" +
"GYPTIAN HIEROGLYPH-13A48EGYPTIAN HIEROGLYPH-13A49EGYPTIAN HIEROGLYPH-13A" +
"4AEGYPTIAN HIEROGLYPH-13A4BEGYPTIAN HIEROGLYPH-13A4CEGYPTIAN HIEROGLYPH-" +
"13A4DEGYPTIAN HIEROGLYPH-13A4EEGYPTIAN HIEROGLYPH-13A4FEGYPTIAN HIEROGLY" +
"PH-13A50EGYPTIAN HIEROGLYPH-13A51EGYPTIAN HIEROGLYPH-13A52EGYPTIAN HIERO" +
"GLYPH-13A53EGYPTIAN HIEROGLYPH-13A54EGYPTIAN HIEROGLYPH-13A55EGYPTIAN HI" +
"EROGLYPH-13A56EGYPTIAN HIEROGLYPH-13A57EGYPTIAN HIEROGLYPH-13A58EGYPTIAN" +
" HIEROGLYPH-13A59EGYPTIAN HIEROGLYPH-13A5AEGYPTIAN HIEROGLYPH-13A5BEGYPT" +
"IAN HIEROGLYPH-13A5CEGYPTIAN HIEROGLYPH-13A5DEGYPTIAN HIEROGLYPH-13A5EEG" +
"YPTIAN HIEROGLYPH-13A5FEGYPTIAN HIEROGLYPH-13A60EGYPTIAN HIEROGLYPH-13A6" +
"1EGYPTIAN HIEROGLYPH-13A62EGYPTIAN HIEROGLYPH-13A63EGYPTIAN HIEROGLYPH-1" +
"3A64EGYPTIAN HIEROGLYPH-13A65EGYPTIAN HIEROGLYPH-13A66EGYPTIAN HIEROGLYP" +
"H-13A67EGYPTIAN HIEROGLYPH-13A68EGYPTIAN HIEROGLYPH-13A69EGYPTIAN HIEROG" +
"LYPH-13A6AEGYPTIAN HIEROGLYPH-13A6BEGYPTIAN HIEROGLYPH-13A6CEGYPTIAN HIE" +
"ROGLYPH-13A6DEGYPTIAN HIEROGLYPH-13A6EEGYPTIAN HIEROGLYPH-13A6FEGYPTIAN " +
"HIEROGLYPH-13A70EGYPTIAN HIEROGLYPH-13A71EGYPTIAN HIEROGLYPH-13A72EGYPTI" +
"AN HIEROGLYPH-13A73EGYPTIAN HIEROGLYPH-13A74EGYPTIAN HIEROGLYPH-13A75EGY" +
"PTIAN HIEROGLYPH-13A76EGYPTIAN HIEROGLYPH-13A77EGYPTIAN HIEROGLYPH-13A78" +
"EGYPTIAN HIEROGLYPH-13A79EGYPTIAN HIEROGLYPH-13A7AEGYPTIAN HIEROGLYPH-13" +
"A7BEGYPTIAN HIEROGLYPH-13A7CEGYPTIAN HIEROGLYPH-13A7DEGYPTIAN HIEROGLYPH" +
"-13A7EEGYPTIAN HIEROGLYPH-13A7FEGYPTIAN HIEROGLYPH-13A80EGYPTIAN HIEROGL" +
"YPH-13A81EGYPTIAN HIEROGLYPH-13A82EGYPTIAN HIEROGLYPH-13A83EGYPTIAN HIER" +
"OGLYPH-13A84EGYPTIAN HIEROGLYPH-13A85EGYPTIAN HIEROGLYPH-13A86EGYPTIAN H" +
"IEROGLYPH-13A87EGYPTIAN HIEROGLYPH-13A88EGYPTIAN HIEROGLYPH-13A89EGYPTIA" +
"N HIEROGLYPH-13A8AEGYPTIAN HIEROGLYPH-13A8BEGYPTIAN HIEROGLYPH-13A8CEGYP" +
"TIAN HIEROGLYPH-13A8DEGYPTIAN HIEROGLYPH-13A8EEGYPTIAN HIEROGLYPH-13A8FE" +
"GYPTIAN HIEROGLYPH-13A90EGYPTIAN HIEROGLYPH-13A91EGYPTIAN HIEROGLYPH-13A" +
"92EGYPTIAN HIEROGLYPH-13A93EGYPTIAN HIEROGLYPH-13A94EGYPTIAN HIEROGLYPH-" +
"13A95EGYPTIAN HIEROGLYPH-13A96EGYPTIAN HIEROGLYPH-13A97EGYPTIAN HIEROGLY" +
"PH-13A98EGYPTIAN HIEROGLYPH-13A99EGYPTIAN HIEROGLYPH-13A9AEGYPTIAN HIERO" +
"GLYPH-13A9BEGYPTIAN HIEROGLYPH-13A9CEGYPTIAN HIEROGLYPH-13A9DEGYPTIAN HI" +
"EROGLYPH-13A9EEGYPTIAN HIEROGLYPH-13A9FEGYPTIAN HIEROGLYPH-13AA0EGYPTIAN" +
" HIEROGLYPH-13AA1EGYPTIAN HIEROGLYPH-13AA2EGYPTIAN HIEROGLYPH-13AA3EGYPT" +
"IAN HIEROGLYPH-13AA4EGYPTIAN HIEROGLYPH-13AA5EGYPTIAN HIEROGLYPH-13AA6EG" +
"YPTIAN HIEROGLYPH-13AA7EGYPTIAN HIEROGLYPH-13AA8EGYPTIAN HIEROGLYPH-13AA" +
"9EGYPTIAN HIEROGLYPH-13AAAEGYPTIAN HIEROGLYPH-13AABEGYPTIAN HIEROGLYPH-1" +
"3AACEGYPTIAN HIEROGLYPH-13AADEGYPTIAN HIEROGLYPH-13AAEEGYPTIAN HIEROGLYP" +
"H-13AAFEGYPTIAN HIEROGLYPH-13AB0EGYPTIAN HIEROGLYPH-13AB1EGYPTIAN HIEROG" +
"LYPH-13AB2EGYPTIAN HIEROGLYPH-13AB3EGYPTIAN HIEROGLYPH-13AB4EGYPTIAN HIE" +
"ROGLYPH-13AB5EGYPTIAN HIEROGLYPH-13AB6EGYPTIAN HIEROGLYPH-13AB7EGYPTIAN " +
"HIEROGLYPH-13AB8EGYPTIAN HIEROGLYPH-13AB9EGYPTIAN HIEROGLYPH-13ABAEGYPTI" +
"AN HIEROGLYPH-13ABBEGYPTIAN HIEROGLYPH-13ABCEGYPTIAN HIEROGLYPH-13ABDEGY" +
"PTIAN HIEROGLYPH-13ABEEGYPTIAN HIEROGLYPH-13ABFEGYPTIAN HIEROGLYPH-13AC0" +
"EGYPTIAN HIEROGLYPH-13AC1EGYPTIAN HIEROGLYPH-13AC2EGYPTIAN HIEROGLYPH-13") + ("" +
"AC3EGYPTIAN HIEROGLYPH-13AC4EGYPTIAN HIEROGLYPH-13AC5EGYPTIAN HIEROGLYPH" +
"-13AC6EGYPTIAN HIEROGLYPH-13AC7EGYPTIAN HIEROGLYPH-13AC8EGYPTIAN HIEROGL" +
"YPH-13AC9EGYPTIAN HIEROGLYPH-13ACAEGYPTIAN HIEROGLYPH-13ACBEGYPTIAN HIER" +
"OGLYPH-13ACCEGYPTIAN HIEROGLYPH-13ACDEGYPTIAN HIEROGLYPH-13ACEEGYPTIAN H" +
"IEROGLYPH-13ACFEGYPTIAN HIEROGLYPH-13AD0EGYPTIAN HIEROGLYPH-13AD1EGYPTIA" +
"N HIEROGLYPH-13AD2EGYPTIAN HIEROGLYPH-13AD3EGYPTIAN HIEROGLYPH-13AD4EGYP" +
"TIAN HIEROGLYPH-13AD5EGYPTIAN HIEROGLYPH-13AD6EGYPTIAN HIEROGLYPH-13AD7E" +
"GYPTIAN HIEROGLYPH-13AD8EGYPTIAN HIEROGLYPH-13AD9EGYPTIAN HIEROGLYPH-13A" +
"DAEGYPTIAN HIEROGLYPH-13ADBEGYPTIAN HIEROGLYPH-13ADCEGYPTIAN HIEROGLYPH-" +
"13ADDEGYPTIAN HIEROGLYPH-13ADEEGYPTIAN HIEROGLYPH-13ADFEGYPTIAN HIEROGLY" +
"PH-13AE0EGYPTIAN HIEROGLYPH-13AE1EGYPTIAN HIEROGLYPH-13AE2EGYPTIAN HIERO" +
"GLYPH-13AE3EGYPTIAN HIEROGLYPH-13AE4EGYPTIAN HIEROGLYPH-13AE5EGYPTIAN HI" +
"EROGLYPH-13AE6EGYPTIAN HIEROGLYPH-13AE7EGYPTIAN HIEROGLYPH-13AE8EGYPTIAN" +
" HIEROGLYPH-13AE9EGYPTIAN HIEROGLYPH-13AEAEGYPTIAN HIEROGLYPH-13AEBEGYPT" +
"IAN HIEROGLYPH-13AECEGYPTIAN HIEROGLYPH-13AEDEGYPTIAN HIEROGLYPH-13AEEEG" +
"YPTIAN HIEROGLYPH-13AEFEGYPTIAN HIEROGLYPH-13AF0EGYPTIAN HIEROGLYPH-13AF" +
"1EGYPTIAN HIEROGLYPH-13AF2EGYPTIAN HIEROGLYPH-13AF3EGYPTIAN HIEROGLYPH-1" +
"3AF4EGYPTIAN HIEROGLYPH-13AF5EGYPTIAN HIEROGLYPH-13AF6EGYPTIAN HIEROGLYP" +
"H-13AF7EGYPTIAN HIEROGLYPH-13AF8EGYPTIAN HIEROGLYPH-13AF9EGYPTIAN HIEROG" +
"LYPH-13AFAEGYPTIAN HIEROGLYPH-13AFBEGYPTIAN HIEROGLYPH-13AFCEGYPTIAN HIE" +
"ROGLYPH-13AFDEGYPTIAN HIEROGLYPH-13AFEEGYPTIAN HIEROGLYPH-13AFFEGYPTIAN " +
"HIEROGLYPH-13B00EGYPTIAN HIEROGLYPH-13B01EGYPTIAN HIEROGLYPH-13B02EGYPTI" +
"AN HIEROGLYPH-13B03EGYPTIAN HIEROGLYPH-13B04EGYPTIAN HIEROGLYPH-13B05EGY" +
"PTIAN HIEROGLYPH-13B06EGYPTIAN HIEROGLYPH-13B07EGYPTIAN HIEROGLYPH-13B08" +
"EGYPTIAN HIEROGLYPH-13B09EGYPTIAN HIEROGLYPH-13B0AEGYPTIAN HIEROGLYPH-13" +
"B0BEGYPTIAN HIEROGLYPH-13B0CEGYPTIAN HIEROGLYPH-13B0DEGYPTIAN HIEROGLYPH" +
"-13B0EEGYPTIAN HIEROGLYPH-13B0FEGYPTIAN HIEROGLYPH-13B10EGYPTIAN HIEROGL" +
"YPH-13B11EGYPTIAN HIEROGLYPH-13B12EGYPTIAN HIEROGLYPH-13B13EGYPTIAN HIER" +
"OGLYPH-13B14EGYPTIAN HIEROGLYPH-13B15EGYPTIAN HIEROGLYPH-13B16EGYPTIAN H" +
"IEROGLYPH-13B17EGYPTIAN HIEROGLYPH-13B18EGYPTIAN HIEROGLYPH-13B19EGYPTIA" +
"N HIEROGLYPH-13B1AEGYPTIAN HIEROGLYPH-13B1BEGYPTIAN HIEROGLYPH-13B1CEGYP" +
"TIAN HIEROGLYPH-13B1DEGYPTIAN HIEROGLYPH-13B1EEGYPTIAN HIEROGLYPH-13B1FE" +
"GYPTIAN HIEROGLYPH-13B20EGYPTIAN HIEROGLYPH-13B21EGYPTIAN HIEROGLYPH-13B" +
"22EGYPTIAN HIEROGLYPH-13B23EGYPTIAN HIEROGLYPH-13B24EGYPTIAN HIEROGLYPH-" +
"13B25EGYPTIAN HIEROGLYPH-13B26EGYPTIAN HIEROGLYPH-13B27EGYPTIAN HIEROGLY" +
"PH-13B28EGYPTIAN HIEROGLYPH-13B29EGYPTIAN HIEROGLYPH-13B2AEGYPTIAN HIERO" +
"GLYPH-13B2BEGYPTIAN HIEROGLYPH-13B2CEGYPTIAN HIEROGLYPH-13B2DEGYPTIAN HI" +
"EROGLYPH-13B2EEGYPTIAN HIEROGLYPH-13B2FEGYPTIAN HIEROGLYPH-13B30EGYPTIAN" +
" HIEROGLYPH-13B31EGYPTIAN HIEROGLYPH-13B32EGYPTIAN HIEROGLYPH-13B33EGYPT" +
"IAN HIEROGLYPH-13B34EGYPTIAN HIEROGLYPH-13B35EGYPTIAN HIEROGLYPH-13B36EG" +
"YPTIAN HIEROGLYPH-13B37EGYPTIAN HIEROGLYPH-13B38EGYPTIAN HIEROGLYPH-13B3" +
"9EGYPTIAN HIEROGLYPH-13B3AEGYPTIAN HIEROGLYPH-13B3BEGYPTIAN HIEROGLYPH-1" +
"3B3CEGYPTIAN HIEROGLYPH-13B3DEGYPTIAN HIEROGLYPH-13B3EEGYPTIAN HIEROGLYP" +
"H-13B3FEGYPTIAN HIEROGLYPH-13B40EGYPTIAN HIEROGLYPH-13B41EGYPTIAN HIEROG" +
"LYPH-13B42EGYPTIAN HIEROGLYPH-13B43EGYPTIAN HIEROGLYPH-13B44EGYPTIAN HIE" +
"ROGLYPH-13B45EGYPTIAN HIEROGLYPH-13B46EGYPTIAN HIEROGLYPH-13B47EGYPTIAN " +
"HIEROGLYPH-13B48EGYPTIAN HIEROGLYPH-13B49EGYPTIAN HIEROGLYPH-13B4AEGYPTI" +
"AN HIEROGLYPH-13B4BEGYPTIAN HIEROGLYPH-13B4CEGYPTIAN HIEROGLYPH-13B4DEGY" +
"PTIAN HIEROGLYPH-13B4EEGYPTIAN HIEROGLYPH-13B4FEGYPTIAN HIEROGLYPH-13B50" +
"EGYPTIAN HIEROGLYPH-13B51EGYPTIAN HIEROGLYPH-13B52EGYPTIAN HIEROGLYPH-13" +
"B53EGYPTIAN HIEROGLYPH-13B54EGYPTIAN HIEROGLYPH-13B55EGYPTIAN HIEROGLYPH" +
"-13B56EGYPTIAN HIEROGLYPH-13B57EGYPTIAN HIEROGLYPH-13B58EGYPTIAN HIEROGL" +
"YPH-13B59EGYPTIAN HIEROGLYPH-13B5AEGYPTIAN HIEROGLYPH-13B5BEGYPTIAN HIER" +
"OGLYPH-13B5CEGYPTIAN HIEROGLYPH-13B5DEGYPTIAN HIEROGLYPH-13B5EEGYPTIAN H" +
"IEROGLYPH-13B5FEGYPTIAN HIEROGLYPH-13B60EGYPTIAN HIEROGLYPH-13B61EGYPTIA" +
"N HIEROGLYPH-13B62EGYPTIAN HIEROGLYPH-13B63EGYPTIAN HIEROGLYPH-13B64EGYP" +
"TIAN HIEROGLYPH-13B65EGYPTIAN HIEROGLYPH-13B66EGYPTIAN HIEROGLYPH-13B67E" +
"GYPTIAN HIEROGLYPH-13B68EGYPTIAN HIEROGLYPH-13B69EGYPTIAN HIEROGLYPH-13B" +
"6AEGYPTIAN HIEROGLYPH-13B6BEGYPTIAN HIEROGLYPH-13B6CEGYPTIAN HIEROGLYPH-" +
"13B6DEGYPTIAN HIEROGLYPH-13B6EEGYPTIAN HIEROGLYPH-13B6FEGYPTIAN HIEROGLY" +
"PH-13B70EGYPTIAN HIEROGLYPH-13B71EGYPTIAN HIEROGLYPH-13B72EGYPTIAN HIERO" +
"GLYPH-13B73EGYPTIAN HIEROGLYPH-13B74EGYPTIAN HIEROGLYPH-13B75EGYPTIAN HI" +
"EROGLYPH-13B76EGYPTIAN HIEROGLYPH-13B77EGYPTIAN HIEROGLYPH-13B78EGYPTIAN" +
" HIEROGLYPH-13B79EGYPTIAN HIEROGLYPH-13B7AEGYPTIAN HIEROGLYPH-13B7BEGYPT") + ("" +
"IAN HIEROGLYPH-13B7CEGYPTIAN HIEROGLYPH-13B7DEGYPTIAN HIEROGLYPH-13B7EEG" +
"YPTIAN HIEROGLYPH-13B7FEGYPTIAN HIEROGLYPH-13B80EGYPTIAN HIEROGLYPH-13B8" +
"1EGYPTIAN HIEROGLYPH-13B82EGYPTIAN HIEROGLYPH-13B83EGYPTIAN HIEROGLYPH-1" +
"3B84EGYPTIAN HIEROGLYPH-13B85EGYPTIAN HIEROGLYPH-13B86EGYPTIAN HIEROGLYP" +
"H-13B87EGYPTIAN HIEROGLYPH-13B88EGYPTIAN HIEROGLYPH-13B89EGYPTIAN HIEROG" +
"LYPH-13B8AEGYPTIAN HIEROGLYPH-13B8BEGYPTIAN HIEROGLYPH-13B8CEGYPTIAN HIE" +
"ROGLYPH-13B8DEGYPTIAN HIEROGLYPH-13B8EEGYPTIAN HIEROGLYPH-13B8FEGYPTIAN " +
"HIEROGLYPH-13B90EGYPTIAN HIEROGLYPH-13B91EGYPTIAN HIEROGLYPH-13B92EGYPTI" +
"AN HIEROGLYPH-13B93EGYPTIAN HIEROGLYPH-13B94EGYPTIAN HIEROGLYPH-13B95EGY" +
"PTIAN HIEROGLYPH-13B96EGYPTIAN HIEROGLYPH-13B97EGYPTIAN HIEROGLYPH-13B98" +
"EGYPTIAN HIEROGLYPH-13B99EGYPTIAN HIEROGLYPH-13B9AEGYPTIAN HIEROGLYPH-13" +
"B9BEGYPTIAN HIEROGLYPH-13B9CEGYPTIAN HIEROGLYPH-13B9DEGYPTIAN HIEROGLYPH" +
"-13B9EEGYPTIAN HIEROGLYPH-13B9FEGYPTIAN HIEROGLYPH-13BA0EGYPTIAN HIEROGL" +
"YPH-13BA1EGYPTIAN HIEROGLYPH-13BA2EGYPTIAN HIEROGLYPH-13BA3EGYPTIAN HIER" +
"OGLYPH-13BA4EGYPTIAN HIEROGLYPH-13BA5EGYPTIAN HIEROGLYPH-13BA6EGYPTIAN H" +
"IEROGLYPH-13BA7EGYPTIAN HIEROGLYPH-13BA8EGYPTIAN HIEROGLYPH-13BA9EGYPTIA" +
"N HIEROGLYPH-13BAAEGYPTIAN HIEROGLYPH-13BABEGYPTIAN HIEROGLYPH-13BACEGYP" +
"TIAN HIEROGLYPH-13BADEGYPTIAN HIEROGLYPH-13BAEEGYPTIAN HIEROGLYPH-13BAFE" +
"GYPTIAN HIEROGLYPH-13BB0EGYPTIAN HIEROGLYPH-13BB1EGYPTIAN HIEROGLYPH-13B" +
"B2EGYPTIAN HIEROGLYPH-13BB3EGYPTIAN HIEROGLYPH-13BB4EGYPTIAN HIEROGLYPH-" +
"13BB5EGYPTIAN HIEROGLYPH-13BB6EGYPTIAN HIEROGLYPH-13BB7EGYPTIAN HIEROGLY" +
"PH-13BB8EGYPTIAN HIEROGLYPH-13BB9EGYPTIAN HIEROGLYPH-13BBAEGYPTIAN HIERO" +
"GLYPH-13BBBEGYPTIAN HIEROGLYPH-13BBCEGYPTIAN HIEROGLYPH-13BBDEGYPTIAN HI" +
"EROGLYPH-13BBEEGYPTIAN HIEROGLYPH-13BBFEGYPTIAN HIEROGLYPH-13BC0EGYPTIAN" +
" HIEROGLYPH-13BC1EGYPTIAN HIEROGLYPH-13BC2EGYPTIAN HIEROGLYPH-13BC3EGYPT" +
"IAN HIEROGLYPH-13BC4EGYPTIAN HIEROGLYPH-13BC5EGYPTIAN HIEROGLYPH-13BC6EG" +
"YPTIAN HIEROGLYPH-13BC7EGYPTIAN HIEROGLYPH-13BC8EGYPTIAN HIEROGLYPH-13BC" +
"9EGYPTIAN HIEROGLYPH-13BCAEGYPTIAN HIEROGLYPH-13BCBEGYPTIAN HIEROGLYPH-1" +
"3BCCEGYPTIAN HIEROGLYPH-13BCDEGYPTIAN HIEROGLYPH-13BCEEGYPTIAN HIEROGLYP" +
"H-13BCFEGYPTIAN HIEROGLYPH-13BD0EGYPTIAN HIEROGLYPH-13BD1EGYPTIAN HIEROG" +
"LYPH-13BD2EGYPTIAN HIEROGLYPH-13BD3EGYPTIAN HIEROGLYPH-13BD4EGYPTIAN HIE" +
"ROGLYPH-13BD5EGYPTIAN HIEROGLYPH-13BD6EGYPTIAN HIEROGLYPH-13BD7EGYPTIAN " +
"HIEROGLYPH-13BD8EGYPTIAN HIEROGLYPH-13BD9EGYPTIAN HIEROGLYPH-13BDAEGYPTI" +
"AN HIEROGLYPH-13BDBEGYPTIAN HIEROGLYPH-13BDCEGYPTIAN HIEROGLYPH-13BDDEGY" +
"PTIAN HIEROGLYPH-13BDEEGYPTIAN HIEROGLYPH-13BDFEGYPTIAN HIEROGLYPH-13BE0" +
"EGYPTIAN HIEROGLYPH-13BE1EGYPTIAN HIEROGLYPH-13BE2EGYPTIAN HIEROGLYPH-13" +
"BE3EGYPTIAN HIEROGLYPH-13BE4EGYPTIAN HIEROGLYPH-13BE5EGYPTIAN HIEROGLYPH" +
"-13BE6EGYPTIAN HIEROGLYPH-13BE7EGYPTIAN HIEROGLYPH-13BE8EGYPTIAN HIEROGL" +
"YPH-13BE9EGYPTIAN HIEROGLYPH-13BEAEGYPTIAN HIEROGLYPH-13BEBEGYPTIAN HIER" +
"OGLYPH-13BECEGYPTIAN HIEROGLYPH-13BEDEGYPTIAN HIEROGLYPH-13BEEEGYPTIAN H" +
"IEROGLYPH-13BEFEGYPTIAN HIEROGLYPH-13BF0EGYPTIAN HIEROGLYPH-13BF1EGYPTIA" +
"N HIEROGLYPH-13BF2EGYPTIAN HIEROGLYPH-13BF3EGYPTIAN HIEROGLYPH-13BF4EGYP" +
"TIAN HIEROGLYPH-13BF5EGYPTIAN HIEROGLYPH-13BF6EGYPTIAN HIEROGLYPH-13BF7E" +
"GYPTIAN HIEROGLYPH-13BF8EGYPTIAN HIEROGLYPH-13BF9EGYPTIAN HIEROGLYPH-13B" +
"FAEGYPTIAN HIEROGLYPH-13BFBEGYPTIAN HIEROGLYPH-13BFCEGYPTIAN HIEROGLYPH-" +
"13BFDEGYPTIAN HIEROGLYPH-13BFEEGYPTIAN HIEROGLYPH-13BFFEGYPTIAN HIEROGLY" +
"PH-13C00EGYPTIAN HIEROGLYPH-13C01EGYPTIAN HIEROGLYPH-13C02EGYPTIAN HIERO" +
"GLYPH-13C03EGYPTIAN HIEROGLYPH-13C04EGYPTIAN HIEROGLYPH-13C05EGYPTIAN HI" +
"EROGLYPH-13C06EGYPTIAN HIEROGLYPH-13C07EGYPTIAN HIEROGLYPH-13C08EGYPTIAN" +
" HIEROGLYPH-13C09EGYPTIAN HIEROGLYPH-13C0AEGYPTIAN HIEROGLYPH-13C0BEGYPT" +
"IAN HIEROGLYPH-13C0CEGYPTIAN HIEROGLYPH-13C0DEGYPTIAN HIEROGLYPH-13C0EEG" +
"YPTIAN HIEROGLYPH-13C0FEGYPTIAN HIEROGLYPH-13C10EGYPTIAN HIEROGLYPH-13C1" +
"1EGYPTIAN HIEROGLYPH-13C12EGYPTIAN HIEROGLYPH-13C13EGYPTIAN HIEROGLYPH-1" +
"3C14EGYPTIAN HIEROGLYPH-13C15EGYPTIAN HIEROGLYPH-13C16EGYPTIAN HIEROGLYP" +
"H-13C17EGYPTIAN HIEROGLYPH-13C18EGYPTIAN HIEROGLYPH-13C19EGYPTIAN HIEROG" +
"LYPH-13C1AEGYPTIAN HIEROGLYPH-13C1BEGYPTIAN HIEROGLYPH-13C1CEGYPTIAN HIE" +
"ROGLYPH-13C1DEGYPTIAN HIEROGLYPH-13C1EEGYPTIAN HIEROGLYPH-13C1FEGYPTIAN " +
"HIEROGLYPH-13C20EGYPTIAN HIEROGLYPH-13C21EGYPTIAN HIEROGLYPH-13C22EGYPTI" +
"AN HIEROGLYPH-13C23EGYPTIAN HIEROGLYPH-13C24EGYPTIAN HIEROGLYPH-13C25EGY" +
"PTIAN HIEROGLYPH-13C26EGYPTIAN HIEROGLYPH-13C27EGYPTIAN HIEROGLYPH-13C28" +
"EGYPTIAN HIEROGLYPH-13C29EGYPTIAN HIEROGLYPH-13C2AEGYPTIAN HIEROGLYPH-13" +
"C2BEGYPTIAN HIEROGLYPH-13C2CEGYPTIAN HIEROGLYPH-13C2DEGYPTIAN HIEROGLYPH" +
"-13C2EEGYPTIAN HIEROGLYPH-13C2FEGYPTIAN HIEROGLYPH-13C30EGYPTIAN HIEROGL" +
"YPH-13C31EGYPTIAN HIEROGLYPH-13C32EGYPTIAN HIEROGLYPH-13C33EGYPTIAN HIER") + ("" +
"OGLYPH-13C34EGYPTIAN HIEROGLYPH-13C35EGYPTIAN HIEROGLYPH-13C36EGYPTIAN H" +
"IEROGLYPH-13C37EGYPTIAN HIEROGLYPH-13C38EGYPTIAN HIEROGLYPH-13C39EGYPTIA" +
"N HIEROGLYPH-13C3AEGYPTIAN HIEROGLYPH-13C3BEGYPTIAN HIEROGLYPH-13C3CEGYP" +
"TIAN HIEROGLYPH-13C3DEGYPTIAN HIEROGLYPH-13C3EEGYPTIAN HIEROGLYPH-13C3FE" +
"GYPTIAN HIEROGLYPH-13C40EGYPTIAN HIEROGLYPH-13C41EGYPTIAN HIEROGLYPH-13C" +
"42EGYPTIAN HIEROGLYPH-13C43EGYPTIAN HIEROGLYPH-13C44EGYPTIAN HIEROGLYPH-" +
"13C45EGYPTIAN HIEROGLYPH-13C46EGYPTIAN HIEROGLYPH-13C47EGYPTIAN HIEROGLY" +
"PH-13C48EGYPTIAN HIEROGLYPH-13C49EGYPTIAN HIEROGLYPH-13C4AEGYPTIAN HIERO" +
"GLYPH-13C4BEGYPTIAN HIEROGLYPH-13C4CEGYPTIAN HIEROGLYPH-13C4DEGYPTIAN HI" +
"EROGLYPH-13C4EEGYPTIAN HIEROGLYPH-13C4FEGYPTIAN HIEROGLYPH-13C50EGYPTIAN" +
" HIEROGLYPH-13C51EGYPTIAN HIEROGLYPH-13C52EGYPTIAN HIEROGLYPH-13C53EGYPT" +
"IAN HIEROGLYPH-13C54EGYPTIAN HIEROGLYPH-13C55EGYPTIAN HIEROGLYPH-13C56EG" +
"YPTIAN HIEROGLYPH-13C57EGYPTIAN HIEROGLYPH-13C58EGYPTIAN HIEROGLYPH-13C5" +
"9EGYPTIAN HIEROGLYPH-13C5AEGYPTIAN HIEROGLYPH-13C5BEGYPTIAN HIEROGLYPH-1" +
"3C5CEGYPTIAN HIEROGLYPH-13C5DEGYPTIAN HIEROGLYPH-13C5EEGYPTIAN HIEROGLYP" +
"H-13C5FEGYPTIAN HIEROGLYPH-13C60EGYPTIAN HIEROGLYPH-13C61EGYPTIAN HIEROG" +
"LYPH-13C62EGYPTIAN HIEROGLYPH-13C63EGYPTIAN HIEROGLYPH-13C64EGYPTIAN HIE" +
"ROGLYPH-13C65EGYPTIAN HIEROGLYPH-13C66EGYPTIAN HIEROGLYPH-13C67EGYPTIAN " +
"HIEROGLYPH-13C68EGYPTIAN HIEROGLYPH-13C69EGYPTIAN HIEROGLYPH-13C6AEGYPTI" +
"AN HIEROGLYPH-13C6BEGYPTIAN HIEROGLYPH-13C6CEGYPTIAN HIEROGLYPH-13C6DEGY" +
"PTIAN HIEROGLYPH-13C6EEGYPTIAN HIEROGLYPH-13C6FEGYPTIAN HIEROGLYPH-13C70" +
"EGYPTIAN HIEROGLYPH-13C71EGYPTIAN HIEROGLYPH-13C72EGYPTIAN HIEROGLYPH-13" +
"C73EGYPTIAN HIEROGLYPH-13C74EGYPTIAN HIEROGLYPH-13C75EGYPTIAN HIEROGLYPH" +
"-13C76EGYPTIAN HIEROGLYPH-13C77EGYPTIAN HIEROGLYPH-13C78EGYPTIAN HIEROGL" +
"YPH-13C79EGYPTIAN HIEROGLYPH-13C7AEGYPTIAN HIEROGLYPH-13C7BEGYPTIAN HIER" +
"OGLYPH-13C7CEGYPTIAN HIEROGLYPH-13C7DEGYPTIAN HIEROGLYPH-13C7EEGYPTIAN H" +
"IEROGLYPH-13C7FEGYPTIAN HIEROGLYPH-13C80EGYPTIAN HIEROGLYPH-13C81EGYPTIA" +
"N HIEROGLYPH-13C82EGYPTIAN HIEROGLYPH-13C83EGYPTIAN HIEROGLYPH-13C84EGYP" +
"TIAN HIEROGLYPH-13C85EGYPTIAN HIEROGLYPH-13C86EGYPTIAN HIEROGLYPH-13C87E" +
"GYPTIAN HIEROGLYPH-13C88EGYPTIAN HIEROGLYPH-13C89EGYPTIAN HIEROGLYPH-13C" +
"8AEGYPTIAN HIEROGLYPH-13C8BEGYPTIAN HIEROGLYPH-13C8CEGYPTIAN HIEROGLYPH-" +
"13C8DEGYPTIAN HIEROGLYPH-13C8EEGYPTIAN HIEROGLYPH-13C8FEGYPTIAN HIEROGLY" +
"PH-13C90EGYPTIAN HIEROGLYPH-13C91EGYPTIAN HIEROGLYPH-13C92EGYPTIAN HIERO" +
"GLYPH-13C93EGYPTIAN HIEROGLYPH-13C94EGYPTIAN HIEROGLYPH-13C95EGYPTIAN HI" +
"EROGLYPH-13C96EGYPTIAN HIEROGLYPH-13C97EGYPTIAN HIEROGLYPH-13C98EGYPTIAN" +
" HIEROGLYPH-13C99EGYPTIAN HIEROGLYPH-13C9AEGYPTIAN HIEROGLYPH-13C9BEGYPT" +
"IAN HIEROGLYPH-13C9CEGYPTIAN HIEROGLYPH-13C9DEGYPTIAN HIEROGLYPH-13C9EEG" +
"YPTIAN HIEROGLYPH-13C9FEGYPTIAN HIEROGLYPH-13CA0EGYPTIAN HIEROGLYPH-13CA" +
"1EGYPTIAN HIEROGLYPH-13CA2EGYPTIAN HIEROGLYPH-13CA3EGYPTIAN HIEROGLYPH-1" +
"3CA4EGYPTIAN HIEROGLYPH-13CA5EGYPTIAN HIEROGLYPH-13CA6EGYPTIAN HIEROGLYP" +
"H-13CA7EGYPTIAN HIEROGLYPH-13CA8EGYPTIAN HIEROGLYPH-13CA9EGYPTIAN HIEROG" +
"LYPH-13CAAEGYPTIAN HIEROGLYPH-13CABEGYPTIAN HIEROGLYPH-13CACEGYPTIAN HIE" +
"ROGLYPH-13CADEGYPTIAN HIEROGLYPH-13CAEEGYPTIAN HIEROGLYPH-13CAFEGYPTIAN " +
"HIEROGLYPH-13CB0EGYPTIAN HIEROGLYPH-13CB1EGYPTIAN HIEROGLYPH-13CB2EGYPTI" +
"AN HIEROGLYPH-13CB3EGYPTIAN HIEROGLYPH-13CB4EGYPTIAN HIEROGLYPH-13CB5EGY" +
"PTIAN HIEROGLYPH-13CB6EGYPTIAN HIEROGLYPH-13CB7EGYPTIAN HIEROGLYPH-13CB8" +
"EGYPTIAN HIEROGLYPH-13CB9EGYPTIAN HIEROGLYPH-13CBAEGYPTIAN HIEROGLYPH-13" +
"CBBEGYPTIAN HIEROGLYPH-13CBCEGYPTIAN HIEROGLYPH-13CBDEGYPTIAN HIEROGLYPH" +
"-13CBEEGYPTIAN HIEROGLYPH-13CBFEGYPTIAN HIEROGLYPH-13CC0EGYPTIAN HIEROGL" +
"YPH-13CC1EGYPTIAN HIEROGLYPH-13CC2EGYPTIAN HIEROGLYPH-13CC3EGYPTIAN HIER" +
"OGLYPH-13CC4EGYPTIAN HIEROGLYPH-13CC5EGYPTIAN HIEROGLYPH-13CC6EGYPTIAN H" +
"IEROGLYPH-13CC7EGYPTIAN HIEROGLYPH-13CC8EGYPTIAN HIEROGLYPH-13CC9EGYPTIA" +
"N HIEROGLYPH-13CCAEGYPTIAN HIEROGLYPH-13CCBEGYPTIAN HIEROGLYPH-13CCCEGYP" +
"TIAN HIEROGLYPH-13CCDEGYPTIAN HIEROGLYPH-13CCEEGYPTIAN HIEROGLYPH-13CCFE" +
"GYPTIAN HIEROGLYPH-13CD0EGYPTIAN HIEROGLYPH-13CD1EGYPTIAN HIEROGLYPH-13C" +
"D2EGYPTIAN HIEROGLYPH-13CD3EGYPTIAN HIEROGLYPH-13CD4EGYPTIAN HIEROGLYPH-" +
"13CD5EGYPTIAN HIEROGLYPH-13CD6EGYPTIAN HIEROGLYPH-13CD7EGYPTIAN HIEROGLY" +
"PH-13CD8EGYPTIAN HIEROGLYPH-13CD9EGYPTIAN HIEROGLYPH-13CDAEGYPTIAN HIERO" +
"GLYPH-13CDBEGYPTIAN HIEROGLYPH-13CDCEGYPTIAN HIEROGLYPH-13CDDEGYPTIAN HI" +
"EROGLYPH-13CDEEGYPTIAN HIEROGLYPH-13CDFEGYPTIAN HIEROGLYPH-13CE0EGYPTIAN" +
" HIEROGLYPH-13CE1EGYPTIAN HIEROGLYPH-13CE2EGYPTIAN HIEROGLYPH-13CE3EGYPT" +
"IAN HIEROGLYPH-13CE4EGYPTIAN HIEROGLYPH-13CE5EGYPTIAN HIEROGLYPH-13CE6EG" +
"YPTIAN HIEROGLYPH-13CE7EGYPTIAN HIEROGLYPH-13CE8EGYPTIAN HIEROGLYPH-13CE" +
"9EGYPTIAN HIEROGLYPH-13CEAEGYPTIAN HIEROGLYPH-13CEBEGYPTIAN HIEROGLYPH-1") + ("" +
"3CECEGYPTIAN HIEROGLYPH-13CEDEGYPTIAN HIEROGLYPH-13CEEEGYPTIAN HIEROGLYP" +
"H-13CEFEGYPTIAN HIEROGLYPH-13CF0EGYPTIAN HIEROGLYPH-13CF1EGYPTIAN HIEROG" +
"LYPH-13CF2EGYPTIAN HIEROGLYPH-13CF3EGYPTIAN HIEROGLYPH-13CF4EGYPTIAN HIE" +
"ROGLYPH-13CF5EGYPTIAN HIEROGLYPH-13CF6EGYPTIAN HIEROGLYPH-13CF7EGYPTIAN " +
"HIEROGLYPH-13CF8EGYPTIAN HIEROGLYPH-13CF9EGYPTIAN HIEROGLYPH-13CFAEGYPTI" +
"AN HIEROGLYPH-13CFBEGYPTIAN HIEROGLYPH-13CFCEGYPTIAN HIEROGLYPH-13CFDEGY" +
"PTIAN HIEROGLYPH-13CFEEGYPTIAN HIEROGLYPH-13CFFEGYPTIAN HIEROGLYPH-13D00" +
"EGYPTIAN HIEROGLYPH-13D01EGYPTIAN HIEROGLYPH-13D02EGYPTIAN HIEROGLYPH-13" +
"D03EGYPTIAN HIEROGLYPH-13D04EGYPTIAN HIEROGLYPH-13D05EGYPTIAN HIEROGLYPH" +
"-13D06EGYPTIAN HIEROGLYPH-13D07EGYPTIAN HIEROGLYPH-13D08EGYPTIAN HIEROGL" +
"YPH-13D09EGYPTIAN HIEROGLYPH-13D0AEGYPTIAN HIEROGLYPH-13D0BEGYPTIAN HIER" +
"OGLYPH-13D0CEGYPTIAN HIEROGLYPH-13D0DEGYPTIAN HIEROGLYPH-13D0EEGYPTIAN H" +
"IEROGLYPH-13D0FEGYPTIAN HIEROGLYPH-13D10EGYPTIAN HIEROGLYPH-13D11EGYPTIA" +
"N HIEROGLYPH-13D12EGYPTIAN HIEROGLYPH-13D13EGYPTIAN HIEROGLYPH-13D14EGYP" +
"TIAN HIEROGLYPH-13D15EGYPTIAN HIEROGLYPH-13D16EGYPTIAN HIEROGLYPH-13D17E" +
"GYPTIAN HIEROGLYPH-13D18EGYPTIAN HIEROGLYPH-13D19EGYPTIAN HIEROGLYPH-13D" +
"1AEGYPTIAN HIEROGLYPH-13D1BEGYPTIAN HIEROGLYPH-13D1CEGYPTIAN HIEROGLYPH-" +
"13D1DEGYPTIAN HIEROGLYPH-13D1EEGYPTIAN HIEROGLYPH-13D1FEGYPTIAN HIEROGLY" +
"PH-13D20EGYPTIAN HIEROGLYPH-13D21EGYPTIAN HIEROGLYPH-13D22EGYPTIAN HIERO" +
"GLYPH-13D23EGYPTIAN HIEROGLYPH-13D24EGYPTIAN HIEROGLYPH-13D25EGYPTIAN HI" +
"EROGLYPH-13D26EGYPTIAN HIEROGLYPH-13D27EGYPTIAN HIEROGLYPH-13D28EGYPTIAN" +
" HIEROGLYPH-13D29EGYPTIAN HIEROGLYPH-13D2AEGYPTIAN HIEROGLYPH-13D2BEGYPT" +
"IAN HIEROGLYPH-13D2CEGYPTIAN HIEROGLYPH-13D2DEGYPTIAN HIEROGLYPH-13D2EEG" +
"YPTIAN HIEROGLYPH-13D2FEGYPTIAN HIEROGLYPH-13D30EGYPTIAN HIEROGLYPH-13D3" +
"1EGYPTIAN HIEROGLYPH-13D32EGYPTIAN HIEROGLYPH-13D33EGYPTIAN HIEROGLYPH-1" +
"3D34EGYPTIAN HIEROGLYPH-13D35EGYPTIAN HIEROGLYPH-13D36EGYPTIAN HIEROGLYP" +
"H-13D37EGYPTIAN HIEROGLYPH-13D38EGYPTIAN HIEROGLYPH-13D39EGYPTIAN HIEROG" +
"LYPH-13D3AEGYPTIAN HIEROGLYPH-13D3BEGYPTIAN HIEROGLYPH-13D3CEGYPTIAN HIE" +
"ROGLYPH-13D3DEGYPTIAN HIEROGLYPH-13D3EEGYPTIAN HIEROGLYPH-13D3FEGYPTIAN " +
"HIEROGLYPH-13D40EGYPTIAN HIEROGLYPH-13D41EGYPTIAN HIEROGLYPH-13D42EGYPTI" +
"AN HIEROGLYPH-13D43EGYPTIAN HIEROGLYPH-13D44EGYPTIAN HIEROGLYPH-13D45EGY" +
"PTIAN HIEROGLYPH-13D46EGYPTIAN HIEROGLYPH-13D47EGYPTIAN HIEROGLYPH-13D48" +
"EGYPTIAN HIEROGLYPH-13D49EGYPTIAN HIEROGLYPH-13D4AEGYPTIAN HIEROGLYPH-13" +
"D4BEGYPTIAN HIEROGLYPH-13D4CEGYPTIAN HIEROGLYPH-13D4DEGYPTIAN HIEROGLYPH" +
"-13D4EEGYPTIAN HIEROGLYPH-13D4FEGYPTIAN HIEROGLYPH-13D50EGYPTIAN HIEROGL" +
"YPH-13D51EGYPTIAN HIEROGLYPH-13D52EGYPTIAN HIEROGLYPH-13D53EGYPTIAN HIER" +
"OGLYPH-13D54EGYPTIAN HIEROGLYPH-13D55EGYPTIAN HIEROGLYPH-13D56EGYPTIAN H" +
"IEROGLYPH-13D57EGYPTIAN HIEROGLYPH-13D58EGYPTIAN HIEROGLYPH-13D59EGYPTIA" +
"N HIEROGLYPH-13D5AEGYPTIAN HIEROGLYPH-13D5BEGYPTIAN HIEROGLYPH-13D5CEGYP" +
"TIAN HIEROGLYPH-13D5DEGYPTIAN HIEROGLYPH-13D5EEGYPTIAN HIEROGLYPH-13D5FE" +
"GYPTIAN HIEROGLYPH-13D60EGYPTIAN HIEROGLYPH-13D61EGYPTIAN HIEROGLYPH-13D" +
"62EGYPTIAN HIEROGLYPH-13D63EGYPTIAN HIEROGLYPH-13D64EGYPTIAN HIEROGLYPH-" +
"13D65EGYPTIAN HIEROGLYPH-13D66EGYPTIAN HIEROGLYPH-13D67EGYPTIAN HIEROGLY" +
"PH-13D68EGYPTIAN HIEROGLYPH-13D69EGYPTIAN HIEROGLYPH-13D6AEGYPTIAN HIERO" +
"GLYPH-13D6BEGYPTIAN HIEROGLYPH-13D6CEGYPTIAN HIEROGLYPH-13D6DEGYPTIAN HI" +
"EROGLYPH-13D6EEGYPTIAN HIEROGLYPH-13D6FEGYPTIAN HIEROGLYPH-13D70EGYPTIAN" +
" HIEROGLYPH-13D71EGYPTIAN HIEROGLYPH-13D72EGYPTIAN HIEROGLYPH-13D73EGYPT" +
"IAN HIEROGLYPH-13D74EGYPTIAN HIEROGLYPH-13D75EGYPTIAN HIEROGLYPH-13D76EG" +
"YPTIAN HIEROGLYPH-13D77EGYPTIAN HIEROGLYPH-13D78EGYPTIAN HIEROGLYPH-13D7" +
"9EGYPTIAN HIEROGLYPH-13D7AEGYPTIAN HIEROGLYPH-13D7BEGYPTIAN HIEROGLYPH-1" +
"3D7CEGYPTIAN HIEROGLYPH-13D7DEGYPTIAN HIEROGLYPH-13D7EEGYPTIAN HIEROGLYP" +
"H-13D7FEGYPTIAN HIEROGLYPH-13D80EGYPTIAN HIEROGLYPH-13D81EGYPTIAN HIEROG" +
"LYPH-13D82EGYPTIAN HIEROGLYPH-13D83EGYPTIAN HIEROGLYPH-13D84EGYPTIAN HIE" +
"ROGLYPH-13D85EGYPTIAN HIEROGLYPH-13D86EGYPTIAN HIEROGLYPH-13D87EGYPTIAN " +
"HIEROGLYPH-13D88EGYPTIAN HIEROGLYPH-13D89EGYPTIAN HIEROGLYPH-13D8AEGYPTI" +
"AN HIEROGLYPH-13D8BEGYPTIAN HIEROGLYPH-13D8CEGYPTIAN HIEROGLYPH-13D8DEGY" +
"PTIAN HIEROGLYPH-13D8EEGYPTIAN HIEROGLYPH-13D8FEGYPTIAN HIEROGLYPH-13D90" +
"EGYPTIAN HIEROGLYPH-13D91EGYPTIAN HIEROGLYPH-13D92EGYPTIAN HIEROGLYPH-13" +
"D93EGYPTIAN HIEROGLYPH-13D94EGYPTIAN HIEROGLYPH-13D95EGYPTIAN HIEROGLYPH" +
"-13D96EGYPTIAN HIEROGLYPH-13D97EGYPTIAN HIEROGLYPH-13D98EGYPTIAN HIEROGL" +
"YPH-13D99EGYPTIAN HIEROGLYPH-13D9AEGYPTIAN HIEROGLYPH-13D9BEGYPTIAN HIER" +
"OGLYPH-13D9CEGYPTIAN HIEROGLYPH-13D9DEGYPTIAN HIEROGLYPH-13D9EEGYPTIAN H" +
"IEROGLYPH-13D9FEGYPTIAN HIEROGLYPH-13DA0EGYPTIAN HIEROGLYPH-13DA1EGYPTIA" +
"N HIEROGLYPH-13DA2EGYPTIAN HIEROGLYPH-13DA3EGYPTIAN HIEROGLYPH-13DA4EGYP") + ("" +
"TIAN HIEROGLYPH-13DA5EGYPTIAN HIEROGLYPH-13DA6EGYPTIAN HIEROGLYPH-13DA7E" +
"GYPTIAN HIEROGLYPH-13DA8EGYPTIAN HIEROGLYPH-13DA9EGYPTIAN HIEROGLYPH-13D" +
"AAEGYPTIAN HIEROGLYPH-13DABEGYPTIAN HIEROGLYPH-13DACEGYPTIAN HIEROGLYPH-" +
"13DADEGYPTIAN HIEROGLYPH-13DAEEGYPTIAN HIEROGLYPH-13DAFEGYPTIAN HIEROGLY" +
"PH-13DB0EGYPTIAN HIEROGLYPH-13DB1EGYPTIAN HIEROGLYPH-13DB2EGYPTIAN HIERO" +
"GLYPH-13DB3EGYPTIAN HIEROGLYPH-13DB4EGYPTIAN HIEROGLYPH-13DB5EGYPTIAN HI" +
"EROGLYPH-13DB6EGYPTIAN HIEROGLYPH-13DB7EGYPTIAN HIEROGLYPH-13DB8EGYPTIAN" +
" HIEROGLYPH-13DB9EGYPTIAN HIEROGLYPH-13DBAEGYPTIAN HIEROGLYPH-13DBBEGYPT" +
"IAN HIEROGLYPH-13DBCEGYPTIAN HIEROGLYPH-13DBDEGYPTIAN HIEROGLYPH-13DBEEG" +
"YPTIAN HIEROGLYPH-13DBFEGYPTIAN HIEROGLYPH-13DC0EGYPTIAN HIEROGLYPH-13DC" +
"1EGYPTIAN HIEROGLYPH-13DC2EGYPTIAN HIEROGLYPH-13DC3EGYPTIAN HIEROGLYPH-1" +
"3DC4EGYPTIAN HIEROGLYPH-13DC5EGYPTIAN HIEROGLYPH-13DC6EGYPTIAN HIEROGLYP" +
"H-13DC7EGYPTIAN HIEROGLYPH-13DC8EGYPTIAN HIEROGLYPH-13DC9EGYPTIAN HIEROG" +
"LYPH-13DCAEGYPTIAN HIEROGLYPH-13DCBEGYPTIAN HIEROGLYPH-13DCCEGYPTIAN HIE" +
"ROGLYPH-13DCDEGYPTIAN HIEROGLYPH-13DCEEGYPTIAN HIEROGLYPH-13DCFEGYPTIAN " +
"HIEROGLYPH-13DD0EGYPTIAN HIEROGLYPH-13DD1EGYPTIAN HIEROGLYPH-13DD2EGYPTI" +
"AN HIEROGLYPH-13DD3EGYPTIAN HIEROGLYPH-13DD4EGYPTIAN HIEROGLYPH-13DD5EGY" +
"PTIAN HIEROGLYPH-13DD6EGYPTIAN HIEROGLYPH-13DD7EGYPTIAN HIEROGLYPH-13DD8" +
"EGYPTIAN HIEROGLYPH-13DD9EGYPTIAN HIEROGLYPH-13DDAEGYPTIAN HIEROGLYPH-13" +
"DDBEGYPTIAN HIEROGLYPH-13DDCEGYPTIAN HIEROGLYPH-13DDDEGYPTIAN HIEROGLYPH" +
"-13DDEEGYPTIAN HIEROGLYPH-13DDFEGYPTIAN HIEROGLYPH-13DE0EGYPTIAN HIEROGL" +
"YPH-13DE1EGYPTIAN HIEROGLYPH-13DE2EGYPTIAN HIEROGLYPH-13DE3EGYPTIAN HIER" +
"OGLYPH-13DE4EGYPTIAN HIEROGLYPH-13DE5EGYPTIAN HIEROGLYPH-13DE6EGYPTIAN H" +
"IEROGLYPH-13DE7EGYPTIAN HIEROGLYPH-13DE8EGYPTIAN HIEROGLYPH-13DE9EGYPTIA" +
"N HIEROGLYPH-13DEAEGYPTIAN HIEROGLYPH-13DEBEGYPTIAN HIEROGLYPH-13DECEGYP" +
"TIAN HIEROGLYPH-13DEDEGYPTIAN HIEROGLYPH-13DEEEGYPTIAN HIEROGLYPH-13DEFE" +
"GYPTIAN HIEROGLYPH-13DF0EGYPTIAN HIEROGLYPH-13DF1EGYPTIAN HIEROGLYPH-13D" +
"F2EGYPTIAN HIEROGLYPH-13DF3EGYPTIAN HIEROGLYPH-13DF4EGYPTIAN HIEROGLYPH-" +
"13DF5EGYPTIAN HIEROGLYPH-13DF6EGYPTIAN HIEROGLYPH-13DF7EGYPTIAN HIEROGLY" +
"PH-13DF8EGYPTIAN HIEROGLYPH-13DF9EGYPTIAN HIEROGLYPH-13DFAEGYPTIAN HIERO" +
"GLYPH-13DFBEGYPTIAN HIEROGLYPH-13DFCEGYPTIAN HIEROGLYPH-13DFDEGYPTIAN HI" +
"EROGLYPH-13DFEEGYPTIAN HIEROGLYPH-13DFFEGYPTIAN HIEROGLYPH-13E00EGYPTIAN" +
" HIEROGLYPH-13E01EGYPTIAN HIEROGLYPH-13E02EGYPTIAN HIEROGLYPH-13E03EGYPT" +
"IAN HIEROGLYPH-13E04EGYPTIAN HIEROGLYPH-13E05EGYPTIAN HIEROGLYPH-13E06EG" +
"YPTIAN HIEROGLYPH-13E07EGYPTIAN HIEROGLYPH-13E08EGYPTIAN HIEROGLYPH-13E0" +
"9EGYPTIAN HIEROGLYPH-13E0AEGYPTIAN HIEROGLYPH-13E0BEGYPTIAN HIEROGLYPH-1" +
"3E0CEGYPTIAN HIEROGLYPH-13E0DEGYPTIAN HIEROGLYPH-13E0EEGYPTIAN HIEROGLYP" +
"H-13E0FEGYPTIAN HIEROGLYPH-13E10EGYPTIAN HIEROGLYPH-13E11EGYPTIAN HIEROG" +
"LYPH-13E12EGYPTIAN HIEROGLYPH-13E13EGYPTIAN HIEROGLYPH-13E14EGYPTIAN HIE" +
"ROGLYPH-13E15EGYPTIAN HIEROGLYPH-13E16EGYPTIAN HIEROGLYPH-13E17EGYPTIAN " +
"HIEROGLYPH-13E18EGYPTIAN HIEROGLYPH-13E19EGYPTIAN HIEROGLYPH-13E1AEGYPTI" +
"AN HIEROGLYPH-13E1BEGYPTIAN HIEROGLYPH-13E1CEGYPTIAN HIEROGLYPH-13E1DEGY" +
"PTIAN HIEROGLYPH-13E1EEGYPTIAN HIEROGLYPH-13E1FEGYPTIAN HIEROGLYPH-13E20" +
"EGYPTIAN HIEROGLYPH-13E21EGYPTIAN HIEROGLYPH-13E22EGYPTIAN HIEROGLYPH-13" +
"E23EGYPTIAN HIEROGLYPH-13E24EGYPTIAN HIEROGLYPH-13E25EGYPTIAN HIEROGLYPH" +
"-13E26EGYPTIAN HIEROGLYPH-13E27EGYPTIAN HIEROGLYPH-13E28EGYPTIAN HIEROGL" +
"YPH-13E29EGYPTIAN HIEROGLYPH-13E2AEGYPTIAN HIEROGLYPH-13E2BEGYPTIAN HIER" +
"OGLYPH-13E2CEGYPTIAN HIEROGLYPH-13E2DEGYPTIAN HIEROGLYPH-13E2EEGYPTIAN H" +
"IEROGLYPH-13E2FEGYPTIAN HIEROGLYPH-13E30EGYPTIAN HIEROGLYPH-13E31EGYPTIA" +
"N HIEROGLYPH-13E32EGYPTIAN HIEROGLYPH-13E33EGYPTIAN HIEROGLYPH-13E34EGYP" +
"TIAN HIEROGLYPH-13E35EGYPTIAN HIEROGLYPH-13E36EGYPTIAN HIEROGLYPH-13E37E" +
"GYPTIAN HIEROGLYPH-13E38EGYPTIAN HIEROGLYPH-13E39EGYPTIAN HIEROGLYPH-13E" +
"3AEGYPTIAN HIEROGLYPH-13E3BEGYPTIAN HIEROGLYPH-13E3CEGYPTIAN HIEROGLYPH-" +
"13E3DEGYPTIAN HIEROGLYPH-13E3EEGYPTIAN HIEROGLYPH-13E3FEGYPTIAN HIEROGLY" +
"PH-13E40EGYPTIAN HIEROGLYPH-13E41EGYPTIAN HIEROGLYPH-13E42EGYPTIAN HIERO" +
"GLYPH-13E43EGYPTIAN HIEROGLYPH-13E44EGYPTIAN HIEROGLYPH-13E45EGYPTIAN HI" +
"EROGLYPH-13E46EGYPTIAN HIEROGLYPH-13E47EGYPTIAN HIEROGLYPH-13E48EGYPTIAN" +
" HIEROGLYPH-13E49EGYPTIAN HIEROGLYPH-13E4AEGYPTIAN HIEROGLYPH-13E4BEGYPT" +
"IAN HIEROGLYPH-13E4CEGYPTIAN HIEROGLYPH-13E4DEGYPTIAN HIEROGLYPH-13E4EEG" +
"YPTIAN HIEROGLYPH-13E4FEGYPTIAN HIEROGLYPH-13E50EGYPTIAN HIEROGLYPH-13E5" +
"1EGYPTIAN HIEROGLYPH-13E52EGYPTIAN HIEROGLYPH-13E53EGYPTIAN HIEROGLYPH-1" +
"3E54EGYPTIAN HIEROGLYPH-13E55EGYPTIAN HIEROGLYPH-13E56EGYPTIAN HIEROGLYP" +
"H-13E57EGYPTIAN HIEROGLYPH-13E58EGYPTIAN HIEROGLYPH-13E59EGYPTIAN HIEROG" +
"LYPH-13E5AEGYPTIAN HIEROGLYPH-13E5BEGYPTIAN HIEROGLYPH-13E5CEGYPTIAN HIE") + ("" +
"ROGLYPH-13E5DEGYPTIAN HIEROGLYPH-13E5EEGYPTIAN HIEROGLYPH-13E5FEGYPTIAN " +
"HIEROGLYPH-13E60EGYPTIAN HIEROGLYPH-13E61EGYPTIAN HIEROGLYPH-13E62EGYPTI" +
"AN HIEROGLYPH-13E63EGYPTIAN HIEROGLYPH-13E64EGYPTIAN HIEROGLYPH-13E65EGY" +
"PTIAN HIEROGLYPH-13E66EGYPTIAN HIEROGLYPH-13E67EGYPTIAN HIEROGLYPH-13E68" +
"EGYPTIAN HIEROGLYPH-13E69EGYPTIAN HIEROGLYPH-13E6AEGYPTIAN HIEROGLYPH-13" +
"E6BEGYPTIAN HIEROGLYPH-13E6CEGYPTIAN HIEROGLYPH-13E6DEGYPTIAN HIEROGLYPH" +
"-13E6EEGYPTIAN HIEROGLYPH-13E6FEGYPTIAN HIEROGLYPH-13E70EGYPTIAN HIEROGL" +
"YPH-13E71EGYPTIAN HIEROGLYPH-13E72EGYPTIAN HIEROGLYPH-13E73EGYPTIAN HIER" +
"OGLYPH-13E74EGYPTIAN HIEROGLYPH-13E75EGYPTIAN HIEROGLYPH-13E76EGYPTIAN H" +
"IEROGLYPH-13E77EGYPTIAN HIEROGLYPH-13E78EGYPTIAN HIEROGLYPH-13E79EGYPTIA" +
"N HIEROGLYPH-13E7AEGYPTIAN HIEROGLYPH-13E7BEGYPTIAN HIEROGLYPH-13E7CEGYP" +
"TIAN HIEROGLYPH-13E7DEGYPTIAN HIEROGLYPH-13E7EEGYPTIAN HIEROGLYPH-13E7FE" +
"GYPTIAN HIEROGLYPH-13E80EGYPTIAN HIEROGLYPH-13E81EGYPTIAN HIEROGLYPH-13E" +
"82EGYPTIAN HIEROGLYPH-13E83EGYPTIAN HIEROGLYPH-13E84EGYPTIAN HIEROGLYPH-" +
"13E85EGYPTIAN HIEROGLYPH-13E86EGYPTIAN HIEROGLYPH-13E87EGYPTIAN HIEROGLY" +
"PH-13E88EGYPTIAN HIEROGLYPH-13E89EGYPTIAN HIEROGLYPH-13E8AEGYPTIAN HIERO" +
"GLYPH-13E8BEGYPTIAN HIEROGLYPH-13E8CEGYPTIAN HIEROGLYPH-13E8DEGYPTIAN HI" +
"EROGLYPH-13E8EEGYPTIAN HIEROGLYPH-13E8FEGYPTIAN HIEROGLYPH-13E90EGYPTIAN" +
" HIEROGLYPH-13E91EGYPTIAN HIEROGLYPH-13E92EGYPTIAN HIEROGLYPH-13E93EGYPT" +
"IAN HIEROGLYPH-13E94EGYPTIAN HIEROGLYPH-13E95EGYPTIAN HIEROGLYPH-13E96EG" +
"YPTIAN HIEROGLYPH-13E97EGYPTIAN HIEROGLYPH-13E98EGYPTIAN HIEROGLYPH-13E9" +
"9EGYPTIAN HIEROGLYPH-13E9AEGYPTIAN HIEROGLYPH-13E9BEGYPTIAN HIEROGLYPH-1" +
"3E9CEGYPTIAN HIEROGLYPH-13E9DEGYPTIAN HIEROGLYPH-13E9EEGYPTIAN HIEROGLYP" +
"H-13E9FEGYPTIAN HIEROGLYPH-13EA0EGYPTIAN HIEROGLYPH-13EA1EGYPTIAN HIEROG" +
"LYPH-13EA2EGYPTIAN HIEROGLYPH-13EA3EGYPTIAN HIEROGLYPH-13EA4EGYPTIAN HIE" +
"ROGLYPH-13EA5EGYPTIAN HIEROGLYPH-13EA6EGYPTIAN HIEROGLYPH-13EA7EGYPTIAN " +
"HIEROGLYPH-13EA8EGYPTIAN HIEROGLYPH-13EA9EGYPTIAN HIEROGLYPH-13EAAEGYPTI" +
"AN HIEROGLYPH-13EABEGYPTIAN HIEROGLYPH-13EACEGYPTIAN HIEROGLYPH-13EADEGY" +
"PTIAN HIEROGLYPH-13EAEEGYPTIAN HIEROGLYPH-13EAFEGYPTIAN HIEROGLYPH-13EB0" +
"EGYPTIAN HIEROGLYPH-13EB1EGYPTIAN HIEROGLYPH-13EB2EGYPTIAN HIEROGLYPH-13" +
"EB3EGYPTIAN HIEROGLYPH-13EB4EGYPTIAN HIEROGLYPH-13EB5EGYPTIAN HIEROGLYPH" +
"-13EB6EGYPTIAN HIEROGLYPH-13EB7EGYPTIAN HIEROGLYPH-13EB8EGYPTIAN HIEROGL" +
"YPH-13EB9EGYPTIAN HIEROGLYPH-13EBAEGYPTIAN HIEROGLYPH-13EBBEGYPTIAN HIER" +
"OGLYPH-13EBCEGYPTIAN HIEROGLYPH-13EBDEGYPTIAN HIEROGLYPH-13EBEEGYPTIAN H" +
"IEROGLYPH-13EBFEGYPTIAN HIEROGLYPH-13EC0EGYPTIAN HIEROGLYPH-13EC1EGYPTIA" +
"N HIEROGLYPH-13EC2EGYPTIAN HIEROGLYPH-13EC3EGYPTIAN HIEROGLYPH-13EC4EGYP" +
"TIAN HIEROGLYPH-13EC5EGYPTIAN HIEROGLYPH-13EC6EGYPTIAN HIEROGLYPH-13EC7E" +
"GYPTIAN HIEROGLYPH-13EC8EGYPTIAN HIEROGLYPH-13EC9EGYPTIAN HIEROGLYPH-13E" +
"CAEGYPTIAN HIEROGLYPH-13ECBEGYPTIAN HIEROGLYPH-13ECCEGYPTIAN HIEROGLYPH-" +
"13ECDEGYPTIAN HIEROGLYPH-13ECEEGYPTIAN HIEROGLYPH-13ECFEGYPTIAN HIEROGLY" +
"PH-13ED0EGYPTIAN HIEROGLYPH-13ED1EGYPTIAN HIEROGLYPH-13ED2EGYPTIAN HIERO" +
"GLYPH-13ED3EGYPTIAN HIEROGLYPH-13ED4EGYPTIAN HIEROGLYPH-13ED5EGYPTIAN HI" +
"EROGLYPH-13ED6EGYPTIAN HIEROGLYPH-13ED7EGYPTIAN HIEROGLYPH-13ED8EGYPTIAN" +
" HIEROGLYPH-13ED9EGYPTIAN HIEROGLYPH-13EDAEGYPTIAN HIEROGLYPH-13EDBEGYPT" +
"IAN HIEROGLYPH-13EDCEGYPTIAN HIEROGLYPH-13EDDEGYPTIAN HIEROGLYPH-13EDEEG" +
"YPTIAN HIEROGLYPH-13EDFEGYPTIAN HIEROGLYPH-13EE0EGYPTIAN HIEROGLYPH-13EE" +
"1EGYPTIAN HIEROGLYPH-13EE2EGYPTIAN HIEROGLYPH-13EE3EGYPTIAN HIEROGLYPH-1" +
"3EE4EGYPTIAN HIEROGLYPH-13EE5EGYPTIAN HIEROGLYPH-13EE6EGYPTIAN HIEROGLYP" +
"H-13EE7EGYPTIAN HIEROGLYPH-13EE8EGYPTIAN HIEROGLYPH-13EE9EGYPTIAN HIEROG" +
"LYPH-13EEAEGYPTIAN HIEROGLYPH-13EEBEGYPTIAN HIEROGLYPH-13EECEGYPTIAN HIE" +
"ROGLYPH-13EEDEGYPTIAN HIEROGLYPH-13EEEEGYPTIAN HIEROGLYPH-13EEFEGYPTIAN " +
"HIEROGLYPH-13EF0EGYPTIAN HIEROGLYPH-13EF1EGYPTIAN HIEROGLYPH-13EF2EGYPTI" +
"AN HIEROGLYPH-13EF3EGYPTIAN HIEROGLYPH-13EF4EGYPTIAN HIEROGLYPH-13EF5EGY" +
"PTIAN HIEROGLYPH-13EF6EGYPTIAN HIEROGLYPH-13EF7EGYPTIAN HIEROGLYPH-13EF8" +
"EGYPTIAN HIEROGLYPH-13EF9EGYPTIAN HIEROGLYPH-13EFAEGYPTIAN HIEROGLYPH-13" +
"EFBEGYPTIAN HIEROGLYPH-13EFCEGYPTIAN HIEROGLYPH-13EFDEGYPTIAN HIEROGLYPH" +
"-13EFEEGYPTIAN HIEROGLYPH-13EFFEGYPTIAN HIEROGLYPH-13F00EGYPTIAN HIEROGL" +
"YPH-13F01EGYPTIAN HIEROGLYPH-13F02EGYPTIAN HIEROGLYPH-13F03EGYPTIAN HIER" +
"OGLYPH-13F04EGYPTIAN HIEROGLYPH-13F05EGYPTIAN HIEROGLYPH-13F06EGYPTIAN H" +
"IEROGLYPH-13F07EGYPTIAN HIEROGLYPH-13F08EGYPTIAN HIEROGLYPH-13F09EGYPTIA" +
"N HIEROGLYPH-13F0AEGYPTIAN HIEROGLYPH-13F0BEGYPTIAN HIEROGLYPH-13F0CEGYP" +
"TIAN HIEROGLYPH-13F0DEGYPTIAN HIEROGLYPH-13F0EEGYPTIAN HIEROGLYPH-13F0FE" +
"GYPTIAN HIEROGLYPH-13F10EGYPTIAN HIEROGLYPH-13F11EGYPTIAN HIEROGLYPH-13F" +
"12EGYPTIAN HIEROGLYPH-13F13EGYPTIAN HIEROGLYPH-13F14EGYPTIAN HIEROGLYPH-") + ("" +
"13F15EGYPTIAN HIEROGLYPH-13F16EGYPTIAN HIEROGLYPH-13F17EGYPTIAN HIEROGLY" +
"PH-13F18EGYPTIAN HIEROGLYPH-13F19EGYPTIAN HIEROGLYPH-13F1AEGYPTIAN HIERO" +
"GLYPH-13F1BEGYPTIAN HIEROGLYPH-13F1CEGYPTIAN HIEROGLYPH-13F1DEGYPTIAN HI" +
"EROGLYPH-13F1EEGYPTIAN HIEROGLYPH-13F1FEGYPTIAN HIEROGLYPH-13F20EGYPTIAN" +
" HIEROGLYPH-13F21EGYPTIAN HIEROGLYPH-13F22EGYPTIAN HIEROGLYPH-13F23EGYPT" +
"IAN HIEROGLYPH-13F24EGYPTIAN HIEROGLYPH-13F25EGYPTIAN HIEROGLYPH-13F26EG" +
"YPTIAN HIEROGLYPH-13F27EGYPTIAN HIEROGLYPH-13F28EGYPTIAN HIEROGLYPH-13F2" +
"9EGYPTIAN HIEROGLYPH-13F2AEGYPTIAN HIEROGLYPH-13F2BEGYPTIAN HIEROGLYPH-1" +
"3F2CEGYPTIAN HIEROGLYPH-13F2DEGYPTIAN HIEROGLYPH-13F2EEGYPTIAN HIEROGLYP" +
"H-13F2FEGYPTIAN HIEROGLYPH-13F30EGYPTIAN HIEROGLYPH-13F31EGYPTIAN HIEROG" +
"LYPH-13F32EGYPTIAN HIEROGLYPH-13F33EGYPTIAN HIEROGLYPH-13F34EGYPTIAN HIE" +
"ROGLYPH-13F35EGYPTIAN HIEROGLYPH-13F36EGYPTIAN HIEROGLYPH-13F37EGYPTIAN " +
"HIEROGLYPH-13F38EGYPTIAN HIEROGLYPH-13F39EGYPTIAN HIEROGLYPH-13F3AEGYPTI" +
"AN HIEROGLYPH-13F3BEGYPTIAN HIEROGLYPH-13F3CEGYPTIAN HIEROGLYPH-13F3DEGY" +
"PTIAN HIEROGLYPH-13F3EEGYPTIAN HIEROGLYPH-13F3FEGYPTIAN HIEROGLYPH-13F40" +
"EGYPTIAN HIEROGLYPH-13F41EGYPTIAN HIEROGLYPH-13F42EGYPTIAN HIEROGLYPH-13" +
"F43EGYPTIAN HIEROGLYPH-13F44EGYPTIAN HIEROGLYPH-13F45EGYPTIAN HIEROGLYPH" +
"-13F46EGYPTIAN HIEROGLYPH-13F47EGYPTIAN HIEROGLYPH-13F48EGYPTIAN HIEROGL" +
"YPH-13F49EGYPTIAN HIEROGLYPH-13F4AEGYPTIAN HIEROGLYPH-13F4BEGYPTIAN HIER" +
"OGLYPH-13F4CEGYPTIAN HIEROGLYPH-13F4DEGYPTIAN HIEROGLYPH-13F4EEGYPTIAN H" +
"IEROGLYPH-13F4FEGYPTIAN HIEROGLYPH-13F50EGYPTIAN HIEROGLYPH-13F51EGYPTIA" +
"N HIEROGLYPH-13F52EGYPTIAN HIEROGLYPH-13F53EGYPTIAN HIEROGLYPH-13F54EGYP" +
"TIAN HIEROGLYPH-13F55EGYPTIAN HIEROGLYPH-13F56EGYPTIAN HIEROGLYPH-13F57E" +
"GYPTIAN HIEROGLYPH-13F58EGYPTIAN HIEROGLYPH-13F59EGYPTIAN HIEROGLYPH-13F" +
"5AEGYPTIAN HIEROGLYPH-13F5BEGYPTIAN HIEROGLYPH-13F5CEGYPTIAN HIEROGLYPH-" +
"13F5DEGYPTIAN HIEROGLYPH-13F5EEGYPTIAN HIEROGLYPH-13F5FEGYPTIAN HIEROGLY" +
"PH-13F60EGYPTIAN HIEROGLYPH-13F61EGYPTIAN HIEROGLYPH-13F62EGYPTIAN HIERO" +
"GLYPH-13F63EGYPTIAN HIEROGLYPH-13F64EGYPTIAN HIEROGLYPH-13F65EGYPTIAN HI" +
"EROGLYPH-13F66EGYPTIAN HIEROGLYPH-13F67EGYPTIAN HIEROGLYPH-13F68EGYPTIAN" +
" HIEROGLYPH-13F69EGYPTIAN HIEROGLYPH-13F6AEGYPTIAN HIEROGLYPH-13F6BEGYPT" +
"IAN HIEROGLYPH-13F6CEGYPTIAN HIEROGLYPH-13F6DEGYPTIAN HIEROGLYPH-13F6EEG" +
"YPTIAN HIEROGLYPH-13F6FEGYPTIAN HIEROGLYPH-13F70EGYPTIAN HIEROGLYPH-13F7" +
"1EGYPTIAN HIEROGLYPH-13F72EGYPTIAN HIEROGLYPH-13F73EGYPTIAN HIEROGLYPH-1" +
"3F74EGYPTIAN HIEROGLYPH-13F75EGYPTIAN HIEROGLYPH-13F76EGYPTIAN HIEROGLYP" +
"H-13F77EGYPTIAN HIEROGLYPH-13F78EGYPTIAN HIEROGLYPH-13F79EGYPTIAN HIEROG" +
"LYPH-13F7AEGYPTIAN HIEROGLYPH-13F7BEGYPTIAN HIEROGLYPH-13F7CEGYPTIAN HIE" +
"ROGLYPH-13F7DEGYPTIAN HIEROGLYPH-13F7EEGYPTIAN HIEROGLYPH-13F7FEGYPTIAN " +
"HIEROGLYPH-13F80EGYPTIAN HIEROGLYPH-13F81EGYPTIAN HIEROGLYPH-13F82EGYPTI" +
"AN HIEROGLYPH-13F83EGYPTIAN HIEROGLYPH-13F84EGYPTIAN HIEROGLYPH-13F85EGY" +
"PTIAN HIEROGLYPH-13F86EGYPTIAN HIEROGLYPH-13F87EGYPTIAN HIEROGLYPH-13F88" +
"EGYPTIAN HIEROGLYPH-13F89EGYPTIAN HIEROGLYPH-13F8AEGYPTIAN HIEROGLYPH-13" +
"F8BEGYPTIAN HIEROGLYPH-13F8CEGYPTIAN HIEROGLYPH-13F8DEGYPTIAN HIEROGLYPH" +
"-13F8EEGYPTIAN HIEROGLYPH-13F8FEGYPTIAN HIEROGLYPH-13F90EGYPTIAN HIEROGL" +
"YPH-13F91EGYPTIAN HIEROGLYPH-13F92EGYPTIAN HIEROGLYPH-13F93EGYPTIAN HIER" +
"OGLYPH-13F94EGYPTIAN HIEROGLYPH-13F95EGYPTIAN HIEROGLYPH-13F96EGYPTIAN H" +
"IEROGLYPH-13F97EGYPTIAN HIEROGLYPH-13F98EGYPTIAN HIEROGLYPH-13F99EGYPTIA" +
"N HIEROGLYPH-13F9AEGYPTIAN HIEROGLYPH-13F9BEGYPTIAN HIEROGLYPH-13F9CEGYP" +
"TIAN HIEROGLYPH-13F9DEGYPTIAN HIEROGLYPH-13F9EEGYPTIAN HIEROGLYPH-13F9FE" +
"GYPTIAN HIEROGLYPH-13FA0EGYPTIAN HIEROGLYPH-13FA1EGYPTIAN HIEROGLYPH-13F" +
"A2EGYPTIAN HIEROGLYPH-13FA3EGYPTIAN HIEROGLYPH-13FA4EGYPTIAN HIEROGLYPH-" +
"13FA5EGYPTIAN HIEROGLYPH-13FA6EGYPTIAN HIEROGLYPH-13FA7EGYPTIAN HIEROGLY" +
"PH-13FA8EGYPTIAN HIEROGLYPH-13FA9EGYPTIAN HIEROGLYPH-13FAAEGYPTIAN HIERO" +
"GLYPH-13FABEGYPTIAN HIEROGLYPH-13FACEGYPTIAN HIEROGLYPH-13FADEGYPTIAN HI" +
"EROGLYPH-13FAEEGYPTIAN HIEROGLYPH-13FAFEGYPTIAN HIEROGLYPH-13FB0EGYPTIAN" +
" HIEROGLYPH-13FB1EGYPTIAN HIEROGLYPH-13FB2EGYPTIAN HIEROGLYPH-13FB3EGYPT" +
"IAN HIEROGLYPH-13FB4EGYPTIAN HIEROGLYPH-13FB5EGYPTIAN HIEROGLYPH-13FB6EG" +
"YPTIAN HIEROGLYPH-13FB7EGYPTIAN HIEROGLYPH-13FB8EGYPTIAN HIEROGLYPH-13FB" +
"9EGYPTIAN HIEROGLYPH-13FBAEGYPTIAN HIEROGLYPH-13FBBEGYPTIAN HIEROGLYPH-1" +
"3FBCEGYPTIAN HIEROGLYPH-13FBDEGYPTIAN HIEROGLYPH-13FBEEGYPTIAN HIEROGLYP" +
"H-13FBFEGYPTIAN HIEROGLYPH-13FC0EGYPTIAN HIEROGLYPH-13FC1EGYPTIAN HIEROG" +
"LYPH-13FC2EGYPTIAN HIEROGLYPH-13FC3EGYPTIAN HIEROGLYPH-13FC4EGYPTIAN HIE" +
"ROGLYPH-13FC5EGYPTIAN HIEROGLYPH-13FC6EGYPTIAN HIEROGLYPH-13FC7EGYPTIAN " +
"HIEROGLYPH-13FC8EGYPTIAN HIEROGLYPH-13FC9EGYPTIAN HIEROGLYPH-13FCAEGYPTI" +
"AN HIEROGLYPH-13FCBEGYPTIAN HIEROGLYPH-13FCCEGYPTIAN HIEROGLYPH-13FCDEGY") + ("" +
"PTIAN HIEROGLYPH-13FCEEGYPTIAN HIEROGLYPH-13FCFEGYPTIAN HIEROGLYPH-13FD0" +
"EGYPTIAN HIEROGLYPH-13FD1EGYPTIAN HIEROGLYPH-13FD2EGYPTIAN HIEROGLYPH-13" +
"FD3EGYPTIAN HIEROGLYPH-13FD4EGYPTIAN HIEROGLYPH-13FD5EGYPTIAN HIEROGLYPH" +
"-13FD6EGYPTIAN HIEROGLYPH-13FD7EGYPTIAN HIEROGLYPH-13FD8EGYPTIAN HIEROGL" +
"YPH-13FD9EGYPTIAN HIEROGLYPH-13FDAEGYPTIAN HIEROGLYPH-13FDBEGYPTIAN HIER" +
"OGLYPH-13FDCEGYPTIAN HIEROGLYPH-13FDDEGYPTIAN HIEROGLYPH-13FDEEGYPTIAN H" +
"IEROGLYPH-13FDFEGYPTIAN HIEROGLYPH-13FE0EGYPTIAN HIEROGLYPH-13FE1EGYPTIA" +
"N HIEROGLYPH-13FE2EGYPTIAN HIEROGLYPH-13FE3EGYPTIAN HIEROGLYPH-13FE4EGYP" +
"TIAN HIEROGLYPH-13FE5EGYPTIAN HIEROGLYPH-13FE6EGYPTIAN HIEROGLYPH-13FE7E" +
"GYPTIAN HIEROGLYPH-13FE8EGYPTIAN HIEROGLYPH-13FE9EGYPTIAN HIEROGLYPH-13F" +
"EAEGYPTIAN HIEROGLYPH-13FEBEGYPTIAN HIEROGLYPH-13FECEGYPTIAN HIEROGLYPH-" +
"13FEDEGYPTIAN HIEROGLYPH-13FEEEGYPTIAN HIEROGLYPH-13FEFEGYPTIAN HIEROGLY" +
"PH-13FF0EGYPTIAN HIEROGLYPH-13FF1EGYPTIAN HIEROGLYPH-13FF2EGYPTIAN HIERO" +
"GLYPH-13FF3EGYPTIAN HIEROGLYPH-13FF4EGYPTIAN HIEROGLYPH-13FF5EGYPTIAN HI" +
"EROGLYPH-13FF6EGYPTIAN HIEROGLYPH-13FF7EGYPTIAN HIEROGLYPH-13FF8EGYPTIAN" +
" HIEROGLYPH-13FF9EGYPTIAN HIEROGLYPH-13FFAEGYPTIAN HIEROGLYPH-13FFBEGYPT" +
"IAN HIEROGLYPH-13FFCEGYPTIAN HIEROGLYPH-13FFDEGYPTIAN HIEROGLYPH-13FFEEG" +
"YPTIAN HIEROGLYPH-13FFFEGYPTIAN HIEROGLYPH-14000EGYPTIAN HIEROGLYPH-1400" +
"1EGYPTIAN HIEROGLYPH-14002EGYPTIAN HIEROGLYPH-14003EGYPTIAN HIEROGLYPH-1" +
"4004EGYPTIAN HIEROGLYPH-14005EGYPTIAN HIEROGLYPH-14006EGYPTIAN HIEROGLYP" +
"H-14007EGYPTIAN HIEROGLYPH-14008EGYPTIAN HIEROGLYPH-14009EGYPTIAN HIEROG" +
"LYPH-1400AEGYPTIAN HIEROGLYPH-1400BEGYPTIAN HIEROGLYPH-1400CEGYPTIAN HIE" +
"ROGLYPH-1400DEGYPTIAN HIEROGLYPH-1400EEGYPTIAN HIEROGLYPH-1400FEGYPTIAN " +
"HIEROGLYPH-14010EGYPTIAN HIEROGLYPH-14011EGYPTIAN HIEROGLYPH-14012EGYPTI" +
"AN HIEROGLYPH-14013EGYPTIAN HIEROGLYPH-14014EGYPTIAN HIEROGLYPH-14015EGY" +
"PTIAN HIEROGLYPH-14016EGYPTIAN HIEROGLYPH-14017EGYPTIAN HIEROGLYPH-14018" +
"EGYPTIAN HIEROGLYPH-14019EGYPTIAN HIEROGLYPH-1401AEGYPTIAN HIEROGLYPH-14" +
"01BEGYPTIAN HIEROGLYPH-1401CEGYPTIAN HIEROGLYPH-1401DEGYPTIAN HIEROGLYPH" +
"-1401EEGYPTIAN HIEROGLYPH-1401FEGYPTIAN HIEROGLYPH-14020EGYPTIAN HIEROGL" +
"YPH-14021EGYPTIAN HIEROGLYPH-14022EGYPTIAN HIEROGLYPH-14023EGYPTIAN HIER" +
"OGLYPH-14024EGYPTIAN HIEROGLYPH-14025EGYPTIAN HIEROGLYPH-14026EGYPTIAN H" +
"IEROGLYPH-14027EGYPTIAN HIEROGLYPH-14028EGYPTIAN HIEROGLYPH-14029EGYPTIA" +
"N HIEROGLYPH-1402AEGYPTIAN HIEROGLYPH-1402BEGYPTIAN HIEROGLYPH-1402CEGYP" +
"TIAN HIEROGLYPH-1402DEGYPTIAN HIEROGLYPH-1402EEGYPTIAN HIEROGLYPH-1402FE" +
"GYPTIAN HIEROGLYPH-14030EGYPTIAN HIEROGLYPH-14031EGYPTIAN HIEROGLYPH-140" +
"32EGYPTIAN HIEROGLYPH-14033EGYPTIAN HIEROGLYPH-14034EGYPTIAN HIEROGLYPH-" +
"14035EGYPTIAN HIEROGLYPH-14036EGYPTIAN HIEROGLYPH-14037EGYPTIAN HIEROGLY" +
"PH-14038EGYPTIAN HIEROGLYPH-14039EGYPTIAN HIEROGLYPH-1403AEGYPTIAN HIERO" +
"GLYPH-1403BEGYPTIAN HIEROGLYPH-1403CEGYPTIAN HIEROGLYPH-1403DEGYPTIAN HI" +
"EROGLYPH-1403EEGYPTIAN HIEROGLYPH-1403FEGYPTIAN HIEROGLYPH-14040EGYPTIAN" +
" HIEROGLYPH-14041EGYPTIAN HIEROGLYPH-14042EGYPTIAN HIEROGLYPH-14043EGYPT" +
"IAN HIEROGLYPH-14044EGYPTIAN HIEROGLYPH-14045EGYPTIAN HIEROGLYPH-14046EG" +
"YPTIAN HIEROGLYPH-14047EGYPTIAN HIEROGLYPH-14048EGYPTIAN HIEROGLYPH-1404" +
"9EGYPTIAN HIEROGLYPH-1404AEGYPTIAN HIEROGLYPH-1404BEGYPTIAN HIEROGLYPH-1" +
"404CEGYPTIAN HIEROGLYPH-1404DEGYPTIAN HIEROGLYPH-1404EEGYPTIAN HIEROGLYP" +
"H-1404FEGYPTIAN HIEROGLYPH-14050EGYPTIAN HIEROGLYPH-14051EGYPTIAN HIEROG" +
"LYPH-14052EGYPTIAN HIEROGLYPH-14053EGYPTIAN HIEROGLYPH-14054EGYPTIAN HIE" +
"ROGLYPH-14055EGYPTIAN HIEROGLYPH-14056EGYPTIAN HIEROGLYPH-14057EGYPTIAN " +
"HIEROGLYPH-14058EGYPTIAN HIEROGLYPH-14059EGYPTIAN HIEROGLYPH-1405AEGYPTI" +
"AN HIEROGLYPH-1405BEGYPTIAN HIEROGLYPH-1405CEGYPTIAN HIEROGLYPH-1405DEGY" +
"PTIAN HIEROGLYPH-1405EEGYPTIAN HIEROGLYPH-1405FEGYPTIAN HIEROGLYPH-14060" +
"EGYPTIAN HIEROGLYPH-14061EGYPTIAN HIEROGLYPH-14062EGYPTIAN HIEROGLYPH-14" +
"063EGYPTIAN HIEROGLYPH-14064EGYPTIAN HIEROGLYPH-14065EGYPTIAN HIEROGLYPH" +
"-14066EGYPTIAN HIEROGLYPH-14067EGYPTIAN HIEROGLYPH-14068EGYPTIAN HIEROGL" +
"YPH-14069EGYPTIAN HIEROGLYPH-1406AEGYPTIAN HIEROGLYPH-1406BEGYPTIAN HIER" +
"OGLYPH-1406CEGYPTIAN HIEROGLYPH-1406DEGYPTIAN HIEROGLYPH-1406EEGYPTIAN H" +
"IEROGLYPH-1406FEGYPTIAN HIEROGLYPH-14070EGYPTIAN HIEROGLYPH-14071EGYPTIA" +
"N HIEROGLYPH-14072EGYPTIAN HIEROGLYPH-14073EGYPTIAN HIEROGLYPH-14074EGYP" +
"TIAN HIEROGLYPH-14075EGYPTIAN HIEROGLYPH-14076EGYPTIAN HIEROGLYPH-14077E" +
"GYPTIAN HIEROGLYPH-14078EGYPTIAN HIEROGLYPH-14079EGYPTIAN HIEROGLYPH-140" +
"7AEGYPTIAN HIEROGLYPH-1407BEGYPTIAN HIEROGLYPH-1407CEGYPTIAN HIEROGLYPH-" +
"1407DEGYPTIAN HIEROGLYPH-1407EEGYPTIAN HIEROGLYPH-1407FEGYPTIAN HIEROGLY" +
"PH-14080EGYPTIAN HIEROGLYPH-14081EGYPTIAN HIEROGLYPH-14082EGYPTIAN HIERO" +
"GLYPH-14083EGYPTIAN HIEROGLYPH-14084EGYPTIAN HIEROGLYPH-14085EGYPTIAN HI") + ("" +
"EROGLYPH-14086EGYPTIAN HIEROGLYPH-14087EGYPTIAN HIEROGLYPH-14088EGYPTIAN" +
" HIEROGLYPH-14089EGYPTIAN HIEROGLYPH-1408AEGYPTIAN HIEROGLYPH-1408BEGYPT" +
"IAN HIEROGLYPH-1408CEGYPTIAN HIEROGLYPH-1408DEGYPTIAN HIEROGLYPH-1408EEG" +
"YPTIAN HIEROGLYPH-1408FEGYPTIAN HIEROGLYPH-14090EGYPTIAN HIEROGLYPH-1409" +
"1EGYPTIAN HIEROGLYPH-14092EGYPTIAN HIEROGLYPH-14093EGYPTIAN HIEROGLYPH-1" +
"4094EGYPTIAN HIEROGLYPH-14095EGYPTIAN HIEROGLYPH-14096EGYPTIAN HIEROGLYP" +
"H-14097EGYPTIAN HIEROGLYPH-14098EGYPTIAN HIEROGLYPH-14099EGYPTIAN HIEROG" +
"LYPH-1409AEGYPTIAN HIEROGLYPH-1409BEGYPTIAN HIEROGLYPH-1409CEGYPTIAN HIE" +
"ROGLYPH-1409DEGYPTIAN HIEROGLYPH-1409EEGYPTIAN HIEROGLYPH-1409FEGYPTIAN " +
"HIEROGLYPH-140A0EGYPTIAN HIEROGLYPH-140A1EGYPTIAN HIEROGLYPH-140A2EGYPTI" +
"AN HIEROGLYPH-140A3EGYPTIAN HIEROGLYPH-140A4EGYPTIAN HIEROGLYPH-140A5EGY" +
"PTIAN HIEROGLYPH-140A6EGYPTIAN HIEROGLYPH-140A7EGYPTIAN HIEROGLYPH-140A8" +
"EGYPTIAN HIEROGLYPH-140A9EGYPTIAN HIEROGLYPH-140AAEGYPTIAN HIEROGLYPH-14" +
"0ABEGYPTIAN HIEROGLYPH-140ACEGYPTIAN HIEROGLYPH-140ADEGYPTIAN HIEROGLYPH" +
"-140AEEGYPTIAN HIEROGLYPH-140AFEGYPTIAN HIEROGLYPH-140B0EGYPTIAN HIEROGL" +
"YPH-140B1EGYPTIAN HIEROGLYPH-140B2EGYPTIAN HIEROGLYPH-140B3EGYPTIAN HIER" +
"OGLYPH-140B4EGYPTIAN HIEROGLYPH-140B5EGYPTIAN HIEROGLYPH-140B6EGYPTIAN H" +
"IEROGLYPH-140B7EGYPTIAN HIEROGLYPH-140B8EGYPTIAN HIEROGLYPH-140B9EGYPTIA" +
"N HIEROGLYPH-140BAEGYPTIAN HIEROGLYPH-140BBEGYPTIAN HIEROGLYPH-140BCEGYP" +
"TIAN HIEROGLYPH-140BDEGYPTIAN HIEROGLYPH-140BEEGYPTIAN HIEROGLYPH-140BFE" +
"GYPTIAN HIEROGLYPH-140C0EGYPTIAN HIEROGLYPH-140C1EGYPTIAN HIEROGLYPH-140" +
"C2EGYPTIAN HIEROGLYPH-140C3EGYPTIAN HIEROGLYPH-140C4EGYPTIAN HIEROGLYPH-" +
"140C5EGYPTIAN HIEROGLYPH-140C6EGYPTIAN HIEROGLYPH-140C7EGYPTIAN HIEROGLY" +
"PH-140C8EGYPTIAN HIEROGLYPH-140C9EGYPTIAN HIEROGLYPH-140CAEGYPTIAN HIERO" +
"GLYPH-140CBEGYPTIAN HIEROGLYPH-140CCEGYPTIAN HIEROGLYPH-140CDEGYPTIAN HI" +
"EROGLYPH-140CEEGYPTIAN HIEROGLYPH-140CFEGYPTIAN HIEROGLYPH-140D0EGYPTIAN" +
" HIEROGLYPH-140D1EGYPTIAN HIEROGLYPH-140D2EGYPTIAN HIEROGLYPH-140D3EGYPT" +
"IAN HIEROGLYPH-140D4EGYPTIAN HIEROGLYPH-140D5EGYPTIAN HIEROGLYPH-140D6EG" +
"YPTIAN HIEROGLYPH-140D7EGYPTIAN HIEROGLYPH-140D8EGYPTIAN HIEROGLYPH-140D" +
"9EGYPTIAN HIEROGLYPH-140DAEGYPTIAN HIEROGLYPH-140DBEGYPTIAN HIEROGLYPH-1" +
"40DCEGYPTIAN HIEROGLYPH-140DDEGYPTIAN HIEROGLYPH-140DEEGYPTIAN HIEROGLYP" +
"H-140DFEGYPTIAN HIEROGLYPH-140E0EGYPTIAN HIEROGLYPH-140E1EGYPTIAN HIEROG" +
"LYPH-140E2EGYPTIAN HIEROGLYPH-140E3EGYPTIAN HIEROGLYPH-140E4EGYPTIAN HIE" +
"ROGLYPH-140E5EGYPTIAN HIEROGLYPH-140E6EGYPTIAN HIEROGLYPH-140E7EGYPTIAN " +
"HIEROGLYPH-140E8EGYPTIAN HIEROGLYPH-140E9EGYPTIAN HIEROGLYPH-140EAEGYPTI" +
"AN HIEROGLYPH-140EBEGYPTIAN HIEROGLYPH-140ECEGYPTIAN HIEROGLYPH-140EDEGY" +
"PTIAN HIEROGLYPH-140EEEGYPTIAN HIEROGLYPH-140EFEGYPTIAN HIEROGLYPH-140F0" +
"EGYPTIAN HIEROGLYPH-140F1EGYPTIAN HIEROGLYPH-140F2EGYPTIAN HIEROGLYPH-14" +
"0F3EGYPTIAN HIEROGLYPH-140F4EGYPTIAN HIEROGLYPH-140F5EGYPTIAN HIEROGLYPH" +
"-140F6EGYPTIAN HIEROGLYPH-140F7EGYPTIAN HIEROGLYPH-140F8EGYPTIAN HIEROGL" +
"YPH-140F9EGYPTIAN HIEROGLYPH-140FAEGYPTIAN HIEROGLYPH-140FBEGYPTIAN HIER" +
"OGLYPH-140FCEGYPTIAN HIEROGLYPH-140FDEGYPTIAN HIEROGLYPH-140FEEGYPTIAN H" +
"IEROGLYPH-140FFEGYPTIAN HIEROGLYPH-14100EGYPTIAN HIEROGLYPH-14101EGYPTIA" +
"N HIEROGLYPH-14102EGYPTIAN HIEROGLYPH-14103EGYPTIAN HIEROGLYPH-14104EGYP" +
"TIAN HIEROGLYPH-14105EGYPTIAN HIEROGLYPH-14106EGYPTIAN HIEROGLYPH-14107E" +
"GYPTIAN HIEROGLYPH-14108EGYPTIAN HIEROGLYPH-14109EGYPTIAN HIEROGLYPH-141" +
"0AEGYPTIAN HIEROGLYPH-1410BEGYPTIAN HIEROGLYPH-1410CEGYPTIAN HIEROGLYPH-" +
"1410DEGYPTIAN HIEROGLYPH-1410EEGYPTIAN HIEROGLYPH-1410FEGYPTIAN HIEROGLY" +
"PH-14110EGYPTIAN HIEROGLYPH-14111EGYPTIAN HIEROGLYPH-14112EGYPTIAN HIERO" +
"GLYPH-14113EGYPTIAN HIEROGLYPH-14114EGYPTIAN HIEROGLYPH-14115EGYPTIAN HI" +
"EROGLYPH-14116EGYPTIAN HIEROGLYPH-14117EGYPTIAN HIEROGLYPH-14118EGYPTIAN" +
" HIEROGLYPH-14119EGYPTIAN HIEROGLYPH-1411AEGYPTIAN HIEROGLYPH-1411BEGYPT" +
"IAN HIEROGLYPH-1411CEGYPTIAN HIEROGLYPH-1411DEGYPTIAN HIEROGLYPH-1411EEG" +
"YPTIAN HIEROGLYPH-1411FEGYPTIAN HIEROGLYPH-14120EGYPTIAN HIEROGLYPH-1412" +
"1EGYPTIAN HIEROGLYPH-14122EGYPTIAN HIEROGLYPH-14123EGYPTIAN HIEROGLYPH-1" +
"4124EGYPTIAN HIEROGLYPH-14125EGYPTIAN HIEROGLYPH-14126EGYPTIAN HIEROGLYP" +
"H-14127EGYPTIAN HIEROGLYPH-14128EGYPTIAN HIEROGLYPH-14129EGYPTIAN HIEROG" +
"LYPH-1412AEGYPTIAN HIEROGLYPH-1412BEGYPTIAN HIEROGLYPH-1412CEGYPTIAN HIE" +
"ROGLYPH-1412DEGYPTIAN HIEROGLYPH-1412EEGYPTIAN HIEROGLYPH-1412FEGYPTIAN " +
"HIEROGLYPH-14130EGYPTIAN HIEROGLYPH-14131EGYPTIAN HIEROGLYPH-14132EGYPTI" +
"AN HIEROGLYPH-14133EGYPTIAN HIEROGLYPH-14134EGYPTIAN HIEROGLYPH-14135EGY" +
"PTIAN HIEROGLYPH-14136EGYPTIAN HIEROGLYPH-14137EGYPTIAN HIEROGLYPH-14138" +
"EGYPTIAN HIEROGLYPH-14139EGYPTIAN HIEROGLYPH-1413AEGYPTIAN HIEROGLYPH-14" +
"13BEGYPTIAN HIEROGLYPH-1413CEGYPTIAN HIEROGLYPH-1413DEGYPTIAN HIEROGLYPH") + ("" +
"-1413EEGYPTIAN HIEROGLYPH-1413FEGYPTIAN HIEROGLYPH-14140EGYPTIAN HIEROGL" +
"YPH-14141EGYPTIAN HIEROGLYPH-14142EGYPTIAN HIEROGLYPH-14143EGYPTIAN HIER" +
"OGLYPH-14144EGYPTIAN HIEROGLYPH-14145EGYPTIAN HIEROGLYPH-14146EGYPTIAN H" +
"IEROGLYPH-14147EGYPTIAN HIEROGLYPH-14148EGYPTIAN HIEROGLYPH-14149EGYPTIA" +
"N HIEROGLYPH-1414AEGYPTIAN HIEROGLYPH-1414BEGYPTIAN HIEROGLYPH-1414CEGYP" +
"TIAN HIEROGLYPH-1414DEGYPTIAN HIEROGLYPH-1414EEGYPTIAN HIEROGLYPH-1414FE" +
"GYPTIAN HIEROGLYPH-14150EGYPTIAN HIEROGLYPH-14151EGYPTIAN HIEROGLYPH-141" +
"52EGYPTIAN HIEROGLYPH-14153EGYPTIAN HIEROGLYPH-14154EGYPTIAN HIEROGLYPH-" +
"14155EGYPTIAN HIEROGLYPH-14156EGYPTIAN HIEROGLYPH-14157EGYPTIAN HIEROGLY" +
"PH-14158EGYPTIAN HIEROGLYPH-14159EGYPTIAN HIEROGLYPH-1415AEGYPTIAN HIERO" +
"GLYPH-1415BEGYPTIAN HIEROGLYPH-1415CEGYPTIAN HIEROGLYPH-1415DEGYPTIAN HI" +
"EROGLYPH-1415EEGYPTIAN HIEROGLYPH-1415FEGYPTIAN HIEROGLYPH-14160EGYPTIAN" +
" HIEROGLYPH-14161EGYPTIAN HIEROGLYPH-14162EGYPTIAN HIEROGLYPH-14163EGYPT" +
"IAN HIEROGLYPH-14164EGYPTIAN HIEROGLYPH-14165EGYPTIAN HIEROGLYPH-14166EG" +
"YPTIAN HIEROGLYPH-14167EGYPTIAN HIEROGLYPH-14168EGYPTIAN HIEROGLYPH-1416" +
"9EGYPTIAN HIEROGLYPH-1416AEGYPTIAN HIEROGLYPH-1416BEGYPTIAN HIEROGLYPH-1" +
"416CEGYPTIAN HIEROGLYPH-1416DEGYPTIAN HIEROGLYPH-1416EEGYPTIAN HIEROGLYP" +
"H-1416FEGYPTIAN HIEROGLYPH-14170EGYPTIAN HIEROGLYPH-14171EGYPTIAN HIEROG" +
"LYPH-14172EGYPTIAN HIEROGLYPH-14173EGYPTIAN HIEROGLYPH-14174EGYPTIAN HIE" +
"ROGLYPH-14175EGYPTIAN HIEROGLYPH-14176EGYPTIAN HIEROGLYPH-14177EGYPTIAN " +
"HIEROGLYPH-14178EGYPTIAN HIEROGLYPH-14179EGYPTIAN HIEROGLYPH-1417AEGYPTI" +
"AN HIEROGLYPH-1417BEGYPTIAN HIEROGLYPH-1417CEGYPTIAN HIEROGLYPH-1417DEGY" +
"PTIAN HIEROGLYPH-1417EEGYPTIAN HIEROGLYPH-1417FEGYPTIAN HIEROGLYPH-14180" +
"EGYPTIAN HIEROGLYPH-14181EGYPTIAN HIEROGLYPH-14182EGYPTIAN HIEROGLYPH-14" +
"183EGYPTIAN HIEROGLYPH-14184EGYPTIAN HIEROGLYPH-14185EGYPTIAN HIEROGLYPH" +
"-14186EGYPTIAN HIEROGLYPH-14187EGYPTIAN HIEROGLYPH-14188EGYPTIAN HIEROGL" +
"YPH-14189EGYPTIAN HIEROGLYPH-1418AEGYPTIAN HIEROGLYPH-1418BEGYPTIAN HIER" +
"OGLYPH-1418CEGYPTIAN HIEROGLYPH-1418DEGYPTIAN HIEROGLYPH-1418EEGYPTIAN H" +
"IEROGLYPH-1418FEGYPTIAN HIEROGLYPH-14190EGYPTIAN HIEROGLYPH-14191EGYPTIA" +
"N HIEROGLYPH-14192EGYPTIAN HIEROGLYPH-14193EGYPTIAN HIEROGLYPH-14194EGYP" +
"TIAN HIEROGLYPH-14195EGYPTIAN HIEROGLYPH-14196EGYPTIAN HIEROGLYPH-14197E" +
"GYPTIAN HIEROGLYPH-14198EGYPTIAN HIEROGLYPH-14199EGYPTIAN HIEROGLYPH-141" +
"9AEGYPTIAN HIEROGLYPH-1419BEGYPTIAN HIEROGLYPH-1419CEGYPTIAN HIEROGLYPH-" +
"1419DEGYPTIAN HIEROGLYPH-1419EEGYPTIAN HIEROGLYPH-1419FEGYPTIAN HIEROGLY" +
"PH-141A0EGYPTIAN HIEROGLYPH-141A1EGYPTIAN HIEROGLYPH-141A2EGYPTIAN HIERO" +
"GLYPH-141A3EGYPTIAN HIEROGLYPH-141A4EGYPTIAN HIEROGLYPH-141A5EGYPTIAN HI" +
"EROGLYPH-141A6EGYPTIAN HIEROGLYPH-141A7EGYPTIAN HIEROGLYPH-141A8EGYPTIAN" +
" HIEROGLYPH-141A9EGYPTIAN HIEROGLYPH-141AAEGYPTIAN HIEROGLYPH-141ABEGYPT" +
"IAN HIEROGLYPH-141ACEGYPTIAN HIEROGLYPH-141ADEGYPTIAN HIEROGLYPH-141AEEG" +
"YPTIAN HIEROGLYPH-141AFEGYPTIAN HIEROGLYPH-141B0EGYPTIAN HIEROGLYPH-141B" +
"1EGYPTIAN HIEROGLYPH-141B2EGYPTIAN HIEROGLYPH-141B3EGYPTIAN HIEROGLYPH-1" +
"41B4EGYPTIAN HIEROGLYPH-141B5EGYPTIAN HIEROGLYPH-141B6EGYPTIAN HIEROGLYP" +
"H-141B7EGYPTIAN HIEROGLYPH-141B8EGYPTIAN HIEROGLYPH-141B9EGYPTIAN HIEROG" +
"LYPH-141BAEGYPTIAN HIEROGLYPH-141BBEGYPTIAN HIEROGLYPH-141BCEGYPTIAN HIE" +
"ROGLYPH-141BDEGYPTIAN HIEROGLYPH-141BEEGYPTIAN HIEROGLYPH-141BFEGYPTIAN " +
"HIEROGLYPH-141C0EGYPTIAN HIEROGLYPH-141C1EGYPTIAN HIEROGLYPH-141C2EGYPTI" +
"AN HIEROGLYPH-141C3EGYPTIAN HIEROGLYPH-141C4EGYPTIAN HIEROGLYPH-141C5EGY" +
"PTIAN HIEROGLYPH-141C6EGYPTIAN HIEROGLYPH-141C7EGYPTIAN HIEROGLYPH-141C8" +
"EGYPTIAN HIEROGLYPH-141C9EGYPTIAN HIEROGLYPH-141CAEGYPTIAN HIEROGLYPH-14" +
"1CBEGYPTIAN HIEROGLYPH-141CCEGYPTIAN HIEROGLYPH-141CDEGYPTIAN HIEROGLYPH" +
"-141CEEGYPTIAN HIEROGLYPH-141CFEGYPTIAN HIEROGLYPH-141D0EGYPTIAN HIEROGL" +
"YPH-141D1EGYPTIAN HIEROGLYPH-141D2EGYPTIAN HIEROGLYPH-141D3EGYPTIAN HIER" +
"OGLYPH-141D4EGYPTIAN HIEROGLYPH-141D5EGYPTIAN HIEROGLYPH-141D6EGYPTIAN H" +
"IEROGLYPH-141D7EGYPTIAN HIEROGLYPH-141D8EGYPTIAN HIEROGLYPH-141D9EGYPTIA" +
"N HIEROGLYPH-141DAEGYPTIAN HIEROGLYPH-141DBEGYPTIAN HIEROGLYPH-141DCEGYP" +
"TIAN HIEROGLYPH-141DDEGYPTIAN HIEROGLYPH-141DEEGYPTIAN HIEROGLYPH-141DFE" +
"GYPTIAN HIEROGLYPH-141E0EGYPTIAN HIEROGLYPH-141E1EGYPTIAN HIEROGLYPH-141" +
"E2EGYPTIAN HIEROGLYPH-141E3EGYPTIAN HIEROGLYPH-141E4EGYPTIAN HIEROGLYPH-" +
"141E5EGYPTIAN HIEROGLYPH-141E6EGYPTIAN HIEROGLYPH-141E7EGYPTIAN HIEROGLY" +
"PH-141E8EGYPTIAN HIEROGLYPH-141E9EGYPTIAN HIEROGLYPH-141EAEGYPTIAN HIERO" +
"GLYPH-141EBEGYPTIAN HIEROGLYPH-141ECEGYPTIAN HIEROGLYPH-141EDEGYPTIAN HI" +
"EROGLYPH-141EEEGYPTIAN HIEROGLYPH-141EFEGYPTIAN HIEROGLYPH-141F0EGYPTIAN" +
" HIEROGLYPH-141F1EGYPTIAN HIEROGLYPH-141F2EGYPTIAN HIEROGLYPH-141F3EGYPT" +
"IAN HIEROGLYPH-141F4EGYPTIAN HIEROGLYPH-141F5EGYPTIAN HIEROGLYPH-141F6EG") + ("" +
"YPTIAN HIEROGLYPH-141F7EGYPTIAN HIEROGLYPH-141F8EGYPTIAN HIEROGLYPH-141F" +
"9EGYPTIAN HIEROGLYPH-141FAEGYPTIAN HIEROGLYPH-141FBEGYPTIAN HIEROGLYPH-1" +
"41FCEGYPTIAN HIEROGLYPH-141FDEGYPTIAN HIEROGLYPH-141FEEGYPTIAN HIEROGLYP" +
"H-141FFEGYPTIAN HIEROGLYPH-14200EGYPTIAN HIEROGLYPH-14201EGYPTIAN HIEROG" +
"LYPH-14202EGYPTIAN HIEROGLYPH-14203EGYPTIAN HIEROGLYPH-14204EGYPTIAN HIE" +
"ROGLYPH-14205EGYPTIAN HIEROGLYPH-14206EGYPTIAN HIEROGLYPH-14207EGYPTIAN " +
"HIEROGLYPH-14208EGYPTIAN HIEROGLYPH-14209EGYPTIAN HIEROGLYPH-1420AEGYPTI" +
"AN HIEROGLYPH-1420BEGYPTIAN HIEROGLYPH-1420CEGYPTIAN HIEROGLYPH-1420DEGY" +
"PTIAN HIEROGLYPH-1420EEGYPTIAN HIEROGLYPH-1420FEGYPTIAN HIEROGLYPH-14210" +
"EGYPTIAN HIEROGLYPH-14211EGYPTIAN HIEROGLYPH-14212EGYPTIAN HIEROGLYPH-14" +
"213EGYPTIAN HIEROGLYPH-14214EGYPTIAN HIEROGLYPH-14215EGYPTIAN HIEROGLYPH" +
"-14216EGYPTIAN HIEROGLYPH-14217EGYPTIAN HIEROGLYPH-14218EGYPTIAN HIEROGL" +
"YPH-14219EGYPTIAN HIEROGLYPH-1421AEGYPTIAN HIEROGLYPH-1421BEGYPTIAN HIER" +
"OGLYPH-1421CEGYPTIAN HIEROGLYPH-1421DEGYPTIAN HIEROGLYPH-1421EEGYPTIAN H" +
"IEROGLYPH-1421FEGYPTIAN HIEROGLYPH-14220EGYPTIAN HIEROGLYPH-14221EGYPTIA" +
"N HIEROGLYPH-14222EGYPTIAN HIEROGLYPH-14223EGYPTIAN HIEROGLYPH-14224EGYP" +
"TIAN HIEROGLYPH-14225EGYPTIAN HIEROGLYPH-14226EGYPTIAN HIEROGLYPH-14227E" +
"GYPTIAN HIEROGLYPH-14228EGYPTIAN HIEROGLYPH-14229EGYPTIAN HIEROGLYPH-142" +
"2AEGYPTIAN HIEROGLYPH-1422BEGYPTIAN HIEROGLYPH-1422CEGYPTIAN HIEROGLYPH-" +
"1422DEGYPTIAN HIEROGLYPH-1422EEGYPTIAN HIEROGLYPH-1422FEGYPTIAN HIEROGLY" +
"PH-14230EGYPTIAN HIEROGLYPH-14231EGYPTIAN HIEROGLYPH-14232EGYPTIAN HIERO" +
"GLYPH-14233EGYPTIAN HIEROGLYPH-14234EGYPTIAN HIEROGLYPH-14235EGYPTIAN HI" +
"EROGLYPH-14236EGYPTIAN HIEROGLYPH-14237EGYPTIAN HIEROGLYPH-14238EGYPTIAN" +
" HIEROGLYPH-14239EGYPTIAN HIEROGLYPH-1423AEGYPTIAN HIEROGLYPH-1423BEGYPT" +
"IAN HIEROGLYPH-1423CEGYPTIAN HIEROGLYPH-1423DEGYPTIAN HIEROGLYPH-1423EEG" +
"YPTIAN HIEROGLYPH-1423FEGYPTIAN HIEROGLYPH-14240EGYPTIAN HIEROGLYPH-1424" +
"1EGYPTIAN HIEROGLYPH-14242EGYPTIAN HIEROGLYPH-14243EGYPTIAN HIEROGLYPH-1" +
"4244EGYPTIAN HIEROGLYPH-14245EGYPTIAN HIEROGLYPH-14246EGYPTIAN HIEROGLYP" +
"H-14247EGYPTIAN HIEROGLYPH-14248EGYPTIAN HIEROGLYPH-14249EGYPTIAN HIEROG" +
"LYPH-1424AEGYPTIAN HIEROGLYPH-1424BEGYPTIAN HIEROGLYPH-1424CEGYPTIAN HIE" +
"ROGLYPH-1424DEGYPTIAN HIEROGLYPH-1424EEGYPTIAN HIEROGLYPH-1424FEGYPTIAN " +
"HIEROGLYPH-14250EGYPTIAN HIEROGLYPH-14251EGYPTIAN HIEROGLYPH-14252EGYPTI" +
"AN HIEROGLYPH-14253EGYPTIAN HIEROGLYPH-14254EGYPTIAN HIEROGLYPH-14255EGY" +
"PTIAN HIEROGLYPH-14256EGYPTIAN HIEROGLYPH-14257EGYPTIAN HIEROGLYPH-14258" +
"EGYPTIAN HIEROGLYPH-14259EGYPTIAN HIEROGLYPH-1425AEGYPTIAN HIEROGLYPH-14" +
"25BEGYPTIAN HIEROGLYPH-1425CEGYPTIAN HIEROGLYPH-1425DEGYPTIAN HIEROGLYPH" +
"-1425EEGYPTIAN HIEROGLYPH-1425FEGYPTIAN HIEROGLYPH-14260EGYPTIAN HIEROGL" +
"YPH-14261EGYPTIAN HIEROGLYPH-14262EGYPTIAN HIEROGLYPH-14263EGYPTIAN HIER" +
"OGLYPH-14264EGYPTIAN HIEROGLYPH-14265EGYPTIAN HIEROGLYPH-14266EGYPTIAN H" +
"IEROGLYPH-14267EGYPTIAN HIEROGLYPH-14268EGYPTIAN HIEROGLYPH-14269EGYPTIA" +
"N HIEROGLYPH-1426AEGYPTIAN HIEROGLYPH-1426BEGYPTIAN HIEROGLYPH-1426CEGYP" +
"TIAN HIEROGLYPH-1426DEGYPTIAN HIEROGLYPH-1426EEGYPTIAN HIEROGLYPH-1426FE" +
"GYPTIAN HIEROGLYPH-14270EGYPTIAN HIEROGLYPH-14271EGYPTIAN HIEROGLYPH-142" +
"72EGYPTIAN HIEROGLYPH-14273EGYPTIAN HIEROGLYPH-14274EGYPTIAN HIEROGLYPH-" +
"14275EGYPTIAN HIEROGLYPH-14276EGYPTIAN HIEROGLYPH-14277EGYPTIAN HIEROGLY" +
"PH-14278EGYPTIAN HIEROGLYPH-14279EGYPTIAN HIEROGLYPH-1427AEGYPTIAN HIERO" +
"GLYPH-1427BEGYPTIAN HIEROGLYPH-1427CEGYPTIAN HIEROGLYPH-1427DEGYPTIAN HI" +
"EROGLYPH-1427EEGYPTIAN HIEROGLYPH-1427FEGYPTIAN HIEROGLYPH-14280EGYPTIAN" +
" HIEROGLYPH-14281EGYPTIAN HIEROGLYPH-14282EGYPTIAN HIEROGLYPH-14283EGYPT" +
"IAN HIEROGLYPH-14284EGYPTIAN HIEROGLYPH-14285EGYPTIAN HIEROGLYPH-14286EG" +
"YPTIAN HIEROGLYPH-14287EGYPTIAN HIEROGLYPH-14288EGYPTIAN HIEROGLYPH-1428" +
"9EGYPTIAN HIEROGLYPH-1428AEGYPTIAN HIEROGLYPH-1428BEGYPTIAN HIEROGLYPH-1" +
"428CEGYPTIAN HIEROGLYPH-1428DEGYPTIAN HIEROGLYPH-1428EEGYPTIAN HIEROGLYP" +
"H-1428FEGYPTIAN HIEROGLYPH-14290EGYPTIAN HIEROGLYPH-14291EGYPTIAN HIEROG" +
"LYPH-14292EGYPTIAN HIEROGLYPH-14293EGYPTIAN HIEROGLYPH-14294EGYPTIAN HIE" +
"ROGLYPH-14295EGYPTIAN HIEROGLYPH-14296EGYPTIAN HIEROGLYPH-14297EGYPTIAN " +
"HIEROGLYPH-14298EGYPTIAN HIEROGLYPH-14299EGYPTIAN HIEROGLYPH-1429AEGYPTI" +
"AN HIEROGLYPH-1429BEGYPTIAN HIEROGLYPH-1429CEGYPTIAN HIEROGLYPH-1429DEGY" +
"PTIAN HIEROGLYPH-1429EEGYPTIAN HIEROGLYPH-1429FEGYPTIAN HIEROGLYPH-142A0" +
"EGYPTIAN HIEROGLYPH-142A1EGYPTIAN HIEROGLYPH-142A2EGYPTIAN HIEROGLYPH-14" +
"2A3EGYPTIAN HIEROGLYPH-142A4EGYPTIAN HIEROGLYPH-142A5EGYPTIAN HIEROGLYPH" +
"-142A6EGYPTIAN HIEROGLYPH-142A7EGYPTIAN HIEROGLYPH-142A8EGYPTIAN HIEROGL" +
"YPH-142A9EGYPTIAN HIEROGLYPH-142AAEGYPTIAN HIEROGLYPH-142ABEGYPTIAN HIER" +
"OGLYPH-142ACEGYPTIAN HIEROGLYPH-142ADEGYPTIAN HIEROGLYPH-142AEEGYPTIAN H") + ("" +
"IEROGLYPH-142AFEGYPTIAN HIEROGLYPH-142B0EGYPTIAN HIEROGLYPH-142B1EGYPTIA" +
"N HIEROGLYPH-142B2EGYPTIAN HIEROGLYPH-142B3EGYPTIAN HIEROGLYPH-142B4EGYP" +
"TIAN HIEROGLYPH-142B5EGYPTIAN HIEROGLYPH-142B6EGYPTIAN HIEROGLYPH-142B7E" +
"GYPTIAN HIEROGLYPH-142B8EGYPTIAN HIEROGLYPH-142B9EGYPTIAN HIEROGLYPH-142" +
"BAEGYPTIAN HIEROGLYPH-142BBEGYPTIAN HIEROGLYPH-142BCEGYPTIAN HIEROGLYPH-" +
"142BDEGYPTIAN HIEROGLYPH-142BEEGYPTIAN HIEROGLYPH-142BFEGYPTIAN HIEROGLY" +
"PH-142C0EGYPTIAN HIEROGLYPH-142C1EGYPTIAN HIEROGLYPH-142C2EGYPTIAN HIERO" +
"GLYPH-142C3EGYPTIAN HIEROGLYPH-142C4EGYPTIAN HIEROGLYPH-142C5EGYPTIAN HI" +
"EROGLYPH-142C6EGYPTIAN HIEROGLYPH-142C7EGYPTIAN HIEROGLYPH-142C8EGYPTIAN" +
" HIEROGLYPH-142C9EGYPTIAN HIEROGLYPH-142CAEGYPTIAN HIEROGLYPH-142CBEGYPT" +
"IAN HIEROGLYPH-142CCEGYPTIAN HIEROGLYPH-142CDEGYPTIAN HIEROGLYPH-142CEEG" +
"YPTIAN HIEROGLYPH-142CFEGYPTIAN HIEROGLYPH-142D0EGYPTIAN HIEROGLYPH-142D" +
"1EGYPTIAN HIEROGLYPH-142D2EGYPTIAN HIEROGLYPH-142D3EGYPTIAN HIEROGLYPH-1" +
"42D4EGYPTIAN HIEROGLYPH-142D5EGYPTIAN HIEROGLYPH-142D6EGYPTIAN HIEROGLYP" +
"H-142D7EGYPTIAN HIEROGLYPH-142D8EGYPTIAN HIEROGLYPH-142D9EGYPTIAN HIEROG" +
"LYPH-142DAEGYPTIAN HIEROGLYPH-142DBEGYPTIAN HIEROGLYPH-142DCEGYPTIAN HIE" +
"ROGLYPH-142DDEGYPTIAN HIEROGLYPH-142DEEGYPTIAN HIEROGLYPH-142DFEGYPTIAN " +
"HIEROGLYPH-142E0EGYPTIAN HIEROGLYPH-142E1EGYPTIAN HIEROGLYPH-142E2EGYPTI" +
"AN HIEROGLYPH-142E3EGYPTIAN HIEROGLYPH-142E4EGYPTIAN HIEROGLYPH-142E5EGY" +
"PTIAN HIEROGLYPH-142E6EGYPTIAN HIEROGLYPH-142E7EGYPTIAN HIEROGLYPH-142E8" +
"EGYPTIAN HIEROGLYPH-142E9EGYPTIAN HIEROGLYPH-142EAEGYPTIAN HIEROGLYPH-14" +
"2EBEGYPTIAN HIEROGLYPH-142ECEGYPTIAN HIEROGLYPH-142EDEGYPTIAN HIEROGLYPH" +
"-142EEEGYPTIAN HIEROGLYPH-142EFEGYPTIAN HIEROGLYPH-142F0EGYPTIAN HIEROGL" +
"YPH-142F1EGYPTIAN HIEROGLYPH-142F2EGYPTIAN HIEROGLYPH-142F3EGYPTIAN HIER" +
"OGLYPH-142F4EGYPTIAN HIEROGLYPH-142F5EGYPTIAN HIEROGLYPH-142F6EGYPTIAN H" +
"IEROGLYPH-142F7EGYPTIAN HIEROGLYPH-142F8EGYPTIAN HIEROGLYPH-142F9EGYPTIA" +
"N HIEROGLYPH-142FAEGYPTIAN HIEROGLYPH-142FBEGYPTIAN HIEROGLYPH-142FCEGYP" +
"TIAN HIEROGLYPH-142FDEGYPTIAN HIEROGLYPH-142FEEGYPTIAN HIEROGLYPH-142FFE" +
"GYPTIAN HIEROGLYPH-14300EGYPTIAN HIEROGLYPH-14301EGYPTIAN HIEROGLYPH-143" +
"02EGYPTIAN HIEROGLYPH-14303EGYPTIAN HIEROGLYPH-14304EGYPTIAN HIEROGLYPH-" +
"14305EGYPTIAN HIEROGLYPH-14306EGYPTIAN HIEROGLYPH-14307EGYPTIAN HIEROGLY" +
"PH-14308EGYPTIAN HIEROGLYPH-14309EGYPTIAN HIEROGLYPH-1430AEGYPTIAN HIERO" +
"GLYPH-1430BEGYPTIAN HIEROGLYPH-1430CEGYPTIAN HIEROGLYPH-1430DEGYPTIAN HI" +
"EROGLYPH-1430EEGYPTIAN HIEROGLYPH-1430FEGYPTIAN HIEROGLYPH-14310EGYPTIAN" +
" HIEROGLYPH-14311EGYPTIAN HIEROGLYPH-14312EGYPTIAN HIEROGLYPH-14313EGYPT" +
"IAN HIEROGLYPH-14314EGYPTIAN HIEROGLYPH-14315EGYPTIAN HIEROGLYPH-14316EG" +
"YPTIAN HIEROGLYPH-14317EGYPTIAN HIEROGLYPH-14318EGYPTIAN HIEROGLYPH-1431" +
"9EGYPTIAN HIEROGLYPH-1431AEGYPTIAN HIEROGLYPH-1431BEGYPTIAN HIEROGLYPH-1" +
"431CEGYPTIAN HIEROGLYPH-1431DEGYPTIAN HIEROGLYPH-1431EEGYPTIAN HIEROGLYP" +
"H-1431FEGYPTIAN HIEROGLYPH-14320EGYPTIAN HIEROGLYPH-14321EGYPTIAN HIEROG" +
"LYPH-14322EGYPTIAN HIEROGLYPH-14323EGYPTIAN HIEROGLYPH-14324EGYPTIAN HIE" +
"ROGLYPH-14325EGYPTIAN HIEROGLYPH-14326EGYPTIAN HIEROGLYPH-14327EGYPTIAN " +
"HIEROGLYPH-14328EGYPTIAN HIEROGLYPH-14329EGYPTIAN HIEROGLYPH-1432AEGYPTI" +
"AN HIEROGLYPH-1432BEGYPTIAN HIEROGLYPH-1432CEGYPTIAN HIEROGLYPH-1432DEGY" +
"PTIAN HIEROGLYPH-1432EEGYPTIAN HIEROGLYPH-1432FEGYPTIAN HIEROGLYPH-14330" +
"EGYPTIAN HIEROGLYPH-14331EGYPTIAN HIEROGLYPH-14332EGYPTIAN HIEROGLYPH-14" +
"333EGYPTIAN HIEROGLYPH-14334EGYPTIAN HIEROGLYPH-14335EGYPTIAN HIEROGLYPH" +
"-14336EGYPTIAN HIEROGLYPH-14337EGYPTIAN HIEROGLYPH-14338EGYPTIAN HIEROGL" +
"YPH-14339EGYPTIAN HIEROGLYPH-1433AEGYPTIAN HIEROGLYPH-1433BEGYPTIAN HIER" +
"OGLYPH-1433CEGYPTIAN HIEROGLYPH-1433DEGYPTIAN HIEROGLYPH-1433EEGYPTIAN H" +
"IEROGLYPH-1433FEGYPTIAN HIEROGLYPH-14340EGYPTIAN HIEROGLYPH-14341EGYPTIA" +
"N HIEROGLYPH-14342EGYPTIAN HIEROGLYPH-14343EGYPTIAN HIEROGLYPH-14344EGYP" +
"TIAN HIEROGLYPH-14345EGYPTIAN HIEROGLYPH-14346EGYPTIAN HIEROGLYPH-14347E" +
"GYPTIAN HIEROGLYPH-14348EGYPTIAN HIEROGLYPH-14349EGYPTIAN HIEROGLYPH-143" +
"4AEGYPTIAN HIEROGLYPH-1434BEGYPTIAN HIEROGLYPH-1434CEGYPTIAN HIEROGLYPH-" +
"1434DEGYPTIAN HIEROGLYPH-1434EEGYPTIAN HIEROGLYPH-1434FEGYPTIAN HIEROGLY" +
"PH-14350EGYPTIAN HIEROGLYPH-14351EGYPTIAN HIEROGLYPH-14352EGYPTIAN HIERO" +
"GLYPH-14353EGYPTIAN HIEROGLYPH-14354EGYPTIAN HIEROGLYPH-14355EGYPTIAN HI" +
"EROGLYPH-14356EGYPTIAN HIEROGLYPH-14357EGYPTIAN HIEROGLYPH-14358EGYPTIAN" +
" HIEROGLYPH-14359EGYPTIAN HIEROGLYPH-1435AEGYPTIAN HIEROGLYPH-1435BEGYPT" +
"IAN HIEROGLYPH-1435CEGYPTIAN HIEROGLYPH-1435DEGYPTIAN HIEROGLYPH-1435EEG" +
"YPTIAN HIEROGLYPH-1435FEGYPTIAN HIEROGLYPH-14360EGYPTIAN HIEROGLYPH-1436" +
"1EGYPTIAN HIEROGLYPH-14362EGYPTIAN HIEROGLYPH-14363EGYPTIAN HIEROGLYPH-1" +
"4364EGYPTIAN HIEROGLYPH-14365EGYPTIAN HIEROGLYPH-14366EGYPTIAN HIEROGLYP") + ("" +
"H-14367EGYPTIAN HIEROGLYPH-14368EGYPTIAN HIEROGLYPH-14369EGYPTIAN HIEROG" +
"LYPH-1436AEGYPTIAN HIEROGLYPH-1436BEGYPTIAN HIEROGLYPH-1436CEGYPTIAN HIE" +
"ROGLYPH-1436DEGYPTIAN HIEROGLYPH-1436EEGYPTIAN HIEROGLYPH-1436FEGYPTIAN " +
"HIEROGLYPH-14370EGYPTIAN HIEROGLYPH-14371EGYPTIAN HIEROGLYPH-14372EGYPTI" +
"AN HIEROGLYPH-14373EGYPTIAN HIEROGLYPH-14374EGYPTIAN HIEROGLYPH-14375EGY" +
"PTIAN HIEROGLYPH-14376EGYPTIAN HIEROGLYPH-14377EGYPTIAN HIEROGLYPH-14378" +
"EGYPTIAN HIEROGLYPH-14379EGYPTIAN HIEROGLYPH-1437AEGYPTIAN HIEROGLYPH-14" +
"37BEGYPTIAN HIEROGLYPH-1437CEGYPTIAN HIEROGLYPH-1437DEGYPTIAN HIEROGLYPH" +
"-1437EEGYPTIAN HIEROGLYPH-1437FEGYPTIAN HIEROGLYPH-14380EGYPTIAN HIEROGL" +
"YPH-14381EGYPTIAN HIEROGLYPH-14382EGYPTIAN HIEROGLYPH-14383EGYPTIAN HIER" +
"OGLYPH-14384EGYPTIAN HIEROGLYPH-14385EGYPTIAN HIEROGLYPH-14386EGYPTIAN H" +
"IEROGLYPH-14387EGYPTIAN HIEROGLYPH-14388EGYPTIAN HIEROGLYPH-14389EGYPTIA" +
"N HIEROGLYPH-1438AEGYPTIAN HIEROGLYPH-1438BEGYPTIAN HIEROGLYPH-1438CEGYP" +
"TIAN HIEROGLYPH-1438DEGYPTIAN HIEROGLYPH-1438EEGYPTIAN HIEROGLYPH-1438FE" +
"GYPTIAN HIEROGLYPH-14390EGYPTIAN HIEROGLYPH-14391EGYPTIAN HIEROGLYPH-143" +
"92EGYPTIAN HIEROGLYPH-14393EGYPTIAN HIEROGLYPH-14394EGYPTIAN HIEROGLYPH-" +
"14395EGYPTIAN HIEROGLYPH-14396EGYPTIAN HIEROGLYPH-14397EGYPTIAN HIEROGLY" +
"PH-14398EGYPTIAN HIEROGLYPH-14399EGYPTIAN HIEROGLYPH-1439AEGYPTIAN HIERO" +
"GLYPH-1439BEGYPTIAN HIEROGLYPH-1439CEGYPTIAN HIEROGLYPH-1439DEGYPTIAN HI" +
"EROGLYPH-1439EEGYPTIAN HIEROGLYPH-1439FEGYPTIAN HIEROGLYPH-143A0EGYPTIAN" +
" HIEROGLYPH-143A1EGYPTIAN HIEROGLYPH-143A2EGYPTIAN HIEROGLYPH-143A3EGYPT" +
"IAN HIEROGLYPH-143A4EGYPTIAN HIEROGLYPH-143A5EGYPTIAN HIEROGLYPH-143A6EG" +
"YPTIAN HIEROGLYPH-143A7EGYPTIAN HIEROGLYPH-143A8EGYPTIAN HIEROGLYPH-143A" +
"9EGYPTIAN HIEROGLYPH-143AAEGYPTIAN HIEROGLYPH-143ABEGYPTIAN HIEROGLYPH-1" +
"43ACEGYPTIAN HIEROGLYPH-143ADEGYPTIAN HIEROGLYPH-143AEEGYPTIAN HIEROGLYP" +
"H-143AFEGYPTIAN HIEROGLYPH-143B0EGYPTIAN HIEROGLYPH-143B1EGYPTIAN HIEROG" +
"LYPH-143B2EGYPTIAN HIEROGLYPH-143B3EGYPTIAN HIEROGLYPH-143B4EGYPTIAN HIE" +
"ROGLYPH-143B5EGYPTIAN HIEROGLYPH-143B6EGYPTIAN HIEROGLYPH-143B7EGYPTIAN " +
"HIEROGLYPH-143B8EGYPTIAN HIEROGLYPH-143B9EGYPTIAN HIEROGLYPH-143BAEGYPTI" +
"AN HIEROGLYPH-143BBEGYPTIAN HIEROGLYPH-143BCEGYPTIAN HIEROGLYPH-143BDEGY" +
"PTIAN HIEROGLYPH-143BEEGYPTIAN HIEROGLYPH-143BFEGYPTIAN HIEROGLYPH-143C0" +
"EGYPTIAN HIEROGLYPH-143C1EGYPTIAN HIEROGLYPH-143C2EGYPTIAN HIEROGLYPH-14" +
"3C3EGYPTIAN HIEROGLYPH-143C4EGYPTIAN HIEROGLYPH-143C5EGYPTIAN HIEROGLYPH" +
"-143C6EGYPTIAN HIEROGLYPH-143C7EGYPTIAN HIEROGLYPH-143C8EGYPTIAN HIEROGL" +
"YPH-143C9EGYPTIAN HIEROGLYPH-143CAEGYPTIAN HIEROGLYPH-143CBEGYPTIAN HIER" +
"OGLYPH-143CCEGYPTIAN HIEROGLYPH-143CDEGYPTIAN HIEROGLYPH-143CEEGYPTIAN H" +
"IEROGLYPH-143CFEGYPTIAN HIEROGLYPH-143D0EGYPTIAN HIEROGLYPH-143D1EGYPTIA" +
"N HIEROGLYPH-143D2EGYPTIAN HIEROGLYPH-143D3EGYPTIAN HIEROGLYPH-143D4EGYP" +
"TIAN HIEROGLYPH-143D5EGYPTIAN HIEROGLYPH-143D6EGYPTIAN HIEROGLYPH-143D7E" +
"GYPTIAN HIEROGLYPH-143D8EGYPTIAN HIEROGLYPH-143D9EGYPTIAN HIEROGLYPH-143" +
"DAEGYPTIAN HIEROGLYPH-143DBEGYPTIAN HIEROGLYPH-143DCEGYPTIAN HIEROGLYPH-" +
"143DDEGYPTIAN HIEROGLYPH-143DEEGYPTIAN HIEROGLYPH-143DFEGYPTIAN HIEROGLY" +
"PH-143E0EGYPTIAN HIEROGLYPH-143E1EGYPTIAN HIEROGLYPH-143E2EGYPTIAN HIERO" +
"GLYPH-143E3EGYPTIAN HIEROGLYPH-143E4EGYPTIAN HIEROGLYPH-143E5EGYPTIAN HI" +
"EROGLYPH-143E6EGYPTIAN HIEROGLYPH-143E7EGYPTIAN HIEROGLYPH-143E8EGYPTIAN" +
" HIEROGLYPH-143E9EGYPTIAN HIEROGLYPH-143EAEGYPTIAN HIEROGLYPH-143EBEGYPT" +
"IAN HIEROGLYPH-143ECEGYPTIAN HIEROGLYPH-143EDEGYPTIAN HIEROGLYPH-143EEEG" +
"YPTIAN HIEROGLYPH-143EFEGYPTIAN HIEROGLYPH-143F0EGYPTIAN HIEROGLYPH-143F" +
"1EGYPTIAN HIEROGLYPH-143F2EGYPTIAN HIEROGLYPH-143F3EGYPTIAN HIEROGLYPH-1" +
"43F4EGYPTIAN HIEROGLYPH-143F5EGYPTIAN HIEROGLYPH-143F6EGYPTIAN HIEROGLYP" +
"H-143F7EGYPTIAN HIEROGLYPH-143F8EGYPTIAN HIEROGLYPH-143F9EGYPTIAN HIEROG" +
"LYPH-143FAANATOLIAN HIEROGLYPH A001ANATOLIAN HIEROGLYPH A002ANATOLIAN HI" +
"EROGLYPH A003ANATOLIAN HIEROGLYPH A004ANATOLIAN HIEROGLYPH A005ANATOLIAN" +
" HIEROGLYPH A006ANATOLIAN HIEROGLYPH A007ANATOLIAN HIEROGLYPH A008ANATOL" +
"IAN HIEROGLYPH A009ANATOLIAN HIEROGLYPH A010ANATOLIAN HIEROGLYPH A010AAN" +
"ATOLIAN HIEROGLYPH A011ANATOLIAN HIEROGLYPH A012ANATOLIAN HIEROGLYPH A01" +
"3ANATOLIAN HIEROGLYPH A014ANATOLIAN HIEROGLYPH A015ANATOLIAN HIEROGLYPH " +
"A016ANATOLIAN HIEROGLYPH A017ANATOLIAN HIEROGLYPH A018ANATOLIAN HIEROGLY" +
"PH A019ANATOLIAN HIEROGLYPH A020ANATOLIAN HIEROGLYPH A021ANATOLIAN HIERO" +
"GLYPH A022ANATOLIAN HIEROGLYPH A023ANATOLIAN HIEROGLYPH A024ANATOLIAN HI" +
"EROGLYPH A025ANATOLIAN HIEROGLYPH A026ANATOLIAN HIEROGLYPH A026AANATOLIA" +
"N HIEROGLYPH A027ANATOLIAN HIEROGLYPH A028ANATOLIAN HIEROGLYPH A029ANATO" +
"LIAN HIEROGLYPH A030ANATOLIAN HIEROGLYPH A031ANATOLIAN HIEROGLYPH A032AN" +
"ATOLIAN HIEROGLYPH A033ANATOLIAN HIEROGLYPH A034ANATOLIAN HIEROGLYPH A03") + ("" +
"5ANATOLIAN HIEROGLYPH A036ANATOLIAN HIEROGLYPH A037ANATOLIAN HIEROGLYPH " +
"A038ANATOLIAN HIEROGLYPH A039ANATOLIAN HIEROGLYPH A039AANATOLIAN HIEROGL" +
"YPH A040ANATOLIAN HIEROGLYPH A041ANATOLIAN HIEROGLYPH A041AANATOLIAN HIE" +
"ROGLYPH A042ANATOLIAN HIEROGLYPH A043ANATOLIAN HIEROGLYPH A044ANATOLIAN " +
"HIEROGLYPH A045ANATOLIAN HIEROGLYPH A045AANATOLIAN HIEROGLYPH A046ANATOL" +
"IAN HIEROGLYPH A046AANATOLIAN HIEROGLYPH A046BANATOLIAN HIEROGLYPH A047A" +
"NATOLIAN HIEROGLYPH A048ANATOLIAN HIEROGLYPH A049ANATOLIAN HIEROGLYPH A0" +
"50ANATOLIAN HIEROGLYPH A051ANATOLIAN HIEROGLYPH A052ANATOLIAN HIEROGLYPH" +
" A053ANATOLIAN HIEROGLYPH A054ANATOLIAN HIEROGLYPH A055ANATOLIAN HIEROGL" +
"YPH A056ANATOLIAN HIEROGLYPH A057ANATOLIAN HIEROGLYPH A058ANATOLIAN HIER" +
"OGLYPH A059ANATOLIAN HIEROGLYPH A060ANATOLIAN HIEROGLYPH A061ANATOLIAN H" +
"IEROGLYPH A062ANATOLIAN HIEROGLYPH A063ANATOLIAN HIEROGLYPH A064ANATOLIA" +
"N HIEROGLYPH A065ANATOLIAN HIEROGLYPH A066ANATOLIAN HIEROGLYPH A066AANAT" +
"OLIAN HIEROGLYPH A066BANATOLIAN HIEROGLYPH A066CANATOLIAN HIEROGLYPH A06" +
"7ANATOLIAN HIEROGLYPH A068ANATOLIAN HIEROGLYPH A069ANATOLIAN HIEROGLYPH " +
"A070ANATOLIAN HIEROGLYPH A071ANATOLIAN HIEROGLYPH A072ANATOLIAN HIEROGLY" +
"PH A073ANATOLIAN HIEROGLYPH A074ANATOLIAN HIEROGLYPH A075ANATOLIAN HIERO" +
"GLYPH A076ANATOLIAN HIEROGLYPH A077ANATOLIAN HIEROGLYPH A078ANATOLIAN HI" +
"EROGLYPH A079ANATOLIAN HIEROGLYPH A080ANATOLIAN HIEROGLYPH A081ANATOLIAN" +
" HIEROGLYPH A082ANATOLIAN HIEROGLYPH A083ANATOLIAN HIEROGLYPH A084ANATOL" +
"IAN HIEROGLYPH A085ANATOLIAN HIEROGLYPH A086ANATOLIAN HIEROGLYPH A087ANA" +
"TOLIAN HIEROGLYPH A088ANATOLIAN HIEROGLYPH A089ANATOLIAN HIEROGLYPH A090" +
"ANATOLIAN HIEROGLYPH A091ANATOLIAN HIEROGLYPH A092ANATOLIAN HIEROGLYPH A" +
"093ANATOLIAN HIEROGLYPH A094ANATOLIAN HIEROGLYPH A095ANATOLIAN HIEROGLYP" +
"H A096ANATOLIAN HIEROGLYPH A097ANATOLIAN HIEROGLYPH A097AANATOLIAN HIERO" +
"GLYPH A098ANATOLIAN HIEROGLYPH A098AANATOLIAN HIEROGLYPH A099ANATOLIAN H" +
"IEROGLYPH A100ANATOLIAN HIEROGLYPH A100AANATOLIAN HIEROGLYPH A101ANATOLI" +
"AN HIEROGLYPH A101AANATOLIAN HIEROGLYPH A102ANATOLIAN HIEROGLYPH A102AAN" +
"ATOLIAN HIEROGLYPH A103ANATOLIAN HIEROGLYPH A104ANATOLIAN HIEROGLYPH A10" +
"4AANATOLIAN HIEROGLYPH A104BANATOLIAN HIEROGLYPH A104CANATOLIAN HIEROGLY" +
"PH A105ANATOLIAN HIEROGLYPH A105AANATOLIAN HIEROGLYPH A105BANATOLIAN HIE" +
"ROGLYPH A106ANATOLIAN HIEROGLYPH A107ANATOLIAN HIEROGLYPH A107AANATOLIAN" +
" HIEROGLYPH A107BANATOLIAN HIEROGLYPH A107CANATOLIAN HIEROGLYPH A108ANAT" +
"OLIAN HIEROGLYPH A109ANATOLIAN HIEROGLYPH A110ANATOLIAN HIEROGLYPH A110A" +
"ANATOLIAN HIEROGLYPH A110BANATOLIAN HIEROGLYPH A111ANATOLIAN HIEROGLYPH " +
"A112ANATOLIAN HIEROGLYPH A113ANATOLIAN HIEROGLYPH A114ANATOLIAN HIEROGLY" +
"PH A115ANATOLIAN HIEROGLYPH A115AANATOLIAN HIEROGLYPH A116ANATOLIAN HIER" +
"OGLYPH A117ANATOLIAN HIEROGLYPH A118ANATOLIAN HIEROGLYPH A119ANATOLIAN H" +
"IEROGLYPH A120ANATOLIAN HIEROGLYPH A121ANATOLIAN HIEROGLYPH A122ANATOLIA" +
"N HIEROGLYPH A123ANATOLIAN HIEROGLYPH A124ANATOLIAN HIEROGLYPH A125ANATO" +
"LIAN HIEROGLYPH A125AANATOLIAN HIEROGLYPH A126ANATOLIAN HIEROGLYPH A127A" +
"NATOLIAN HIEROGLYPH A128ANATOLIAN HIEROGLYPH A129ANATOLIAN HIEROGLYPH A1" +
"30ANATOLIAN HIEROGLYPH A131ANATOLIAN HIEROGLYPH A132ANATOLIAN HIEROGLYPH" +
" A133ANATOLIAN HIEROGLYPH A134ANATOLIAN HIEROGLYPH A135ANATOLIAN HIEROGL" +
"YPH A135AANATOLIAN HIEROGLYPH A136ANATOLIAN HIEROGLYPH A137ANATOLIAN HIE" +
"ROGLYPH A138ANATOLIAN HIEROGLYPH A139ANATOLIAN HIEROGLYPH A140ANATOLIAN " +
"HIEROGLYPH A141ANATOLIAN HIEROGLYPH A142ANATOLIAN HIEROGLYPH A143ANATOLI" +
"AN HIEROGLYPH A144ANATOLIAN HIEROGLYPH A145ANATOLIAN HIEROGLYPH A146ANAT" +
"OLIAN HIEROGLYPH A147ANATOLIAN HIEROGLYPH A148ANATOLIAN HIEROGLYPH A149A" +
"NATOLIAN HIEROGLYPH A150ANATOLIAN HIEROGLYPH A151ANATOLIAN HIEROGLYPH A1" +
"52ANATOLIAN HIEROGLYPH A153ANATOLIAN HIEROGLYPH A154ANATOLIAN HIEROGLYPH" +
" A155ANATOLIAN HIEROGLYPH A156ANATOLIAN HIEROGLYPH A157ANATOLIAN HIEROGL" +
"YPH A158ANATOLIAN HIEROGLYPH A159ANATOLIAN HIEROGLYPH A160ANATOLIAN HIER" +
"OGLYPH A161ANATOLIAN HIEROGLYPH A162ANATOLIAN HIEROGLYPH A163ANATOLIAN H" +
"IEROGLYPH A164ANATOLIAN HIEROGLYPH A165ANATOLIAN HIEROGLYPH A166ANATOLIA" +
"N HIEROGLYPH A167ANATOLIAN HIEROGLYPH A168ANATOLIAN HIEROGLYPH A169ANATO" +
"LIAN HIEROGLYPH A170ANATOLIAN HIEROGLYPH A171ANATOLIAN HIEROGLYPH A172AN" +
"ATOLIAN HIEROGLYPH A173ANATOLIAN HIEROGLYPH A174ANATOLIAN HIEROGLYPH A17" +
"5ANATOLIAN HIEROGLYPH A176ANATOLIAN HIEROGLYPH A177ANATOLIAN HIEROGLYPH " +
"A178ANATOLIAN HIEROGLYPH A179ANATOLIAN HIEROGLYPH A180ANATOLIAN HIEROGLY" +
"PH A181ANATOLIAN HIEROGLYPH A182ANATOLIAN HIEROGLYPH A183ANATOLIAN HIERO" +
"GLYPH A184ANATOLIAN HIEROGLYPH A185ANATOLIAN HIEROGLYPH A186ANATOLIAN HI" +
"EROGLYPH A187ANATOLIAN HIEROGLYPH A188ANATOLIAN HIEROGLYPH A189ANATOLIAN" +
" HIEROGLYPH A190ANATOLIAN HIEROGLYPH A191ANATOLIAN HIEROGLYPH A192ANATOL") + ("" +
"IAN HIEROGLYPH A193ANATOLIAN HIEROGLYPH A194ANATOLIAN HIEROGLYPH A195ANA" +
"TOLIAN HIEROGLYPH A196ANATOLIAN HIEROGLYPH A197ANATOLIAN HIEROGLYPH A198" +
"ANATOLIAN HIEROGLYPH A199ANATOLIAN HIEROGLYPH A200ANATOLIAN HIEROGLYPH A" +
"201ANATOLIAN HIEROGLYPH A202ANATOLIAN HIEROGLYPH A202AANATOLIAN HIEROGLY" +
"PH A202BANATOLIAN HIEROGLYPH A203ANATOLIAN HIEROGLYPH A204ANATOLIAN HIER" +
"OGLYPH A205ANATOLIAN HIEROGLYPH A206ANATOLIAN HIEROGLYPH A207ANATOLIAN H" +
"IEROGLYPH A207AANATOLIAN HIEROGLYPH A208ANATOLIAN HIEROGLYPH A209ANATOLI" +
"AN HIEROGLYPH A209AANATOLIAN HIEROGLYPH A210ANATOLIAN HIEROGLYPH A211ANA" +
"TOLIAN HIEROGLYPH A212ANATOLIAN HIEROGLYPH A213ANATOLIAN HIEROGLYPH A214" +
"ANATOLIAN HIEROGLYPH A215ANATOLIAN HIEROGLYPH A215AANATOLIAN HIEROGLYPH " +
"A216ANATOLIAN HIEROGLYPH A216AANATOLIAN HIEROGLYPH A217ANATOLIAN HIEROGL" +
"YPH A218ANATOLIAN HIEROGLYPH A219ANATOLIAN HIEROGLYPH A220ANATOLIAN HIER" +
"OGLYPH A221ANATOLIAN HIEROGLYPH A222ANATOLIAN HIEROGLYPH A223ANATOLIAN H" +
"IEROGLYPH A224ANATOLIAN HIEROGLYPH A225ANATOLIAN HIEROGLYPH A226ANATOLIA" +
"N HIEROGLYPH A227ANATOLIAN HIEROGLYPH A227AANATOLIAN HIEROGLYPH A228ANAT" +
"OLIAN HIEROGLYPH A229ANATOLIAN HIEROGLYPH A230ANATOLIAN HIEROGLYPH A231A" +
"NATOLIAN HIEROGLYPH A232ANATOLIAN HIEROGLYPH A233ANATOLIAN HIEROGLYPH A2" +
"34ANATOLIAN HIEROGLYPH A235ANATOLIAN HIEROGLYPH A236ANATOLIAN HIEROGLYPH" +
" A237ANATOLIAN HIEROGLYPH A238ANATOLIAN HIEROGLYPH A239ANATOLIAN HIEROGL" +
"YPH A240ANATOLIAN HIEROGLYPH A241ANATOLIAN HIEROGLYPH A242ANATOLIAN HIER" +
"OGLYPH A243ANATOLIAN HIEROGLYPH A244ANATOLIAN HIEROGLYPH A245ANATOLIAN H" +
"IEROGLYPH A246ANATOLIAN HIEROGLYPH A247ANATOLIAN HIEROGLYPH A248ANATOLIA" +
"N HIEROGLYPH A249ANATOLIAN HIEROGLYPH A250ANATOLIAN HIEROGLYPH A251ANATO" +
"LIAN HIEROGLYPH A252ANATOLIAN HIEROGLYPH A253ANATOLIAN HIEROGLYPH A254AN" +
"ATOLIAN HIEROGLYPH A255ANATOLIAN HIEROGLYPH A256ANATOLIAN HIEROGLYPH A25" +
"7ANATOLIAN HIEROGLYPH A258ANATOLIAN HIEROGLYPH A259ANATOLIAN HIEROGLYPH " +
"A260ANATOLIAN HIEROGLYPH A261ANATOLIAN HIEROGLYPH A262ANATOLIAN HIEROGLY" +
"PH A263ANATOLIAN HIEROGLYPH A264ANATOLIAN HIEROGLYPH A265ANATOLIAN HIERO" +
"GLYPH A266ANATOLIAN HIEROGLYPH A267ANATOLIAN HIEROGLYPH A267AANATOLIAN H" +
"IEROGLYPH A268ANATOLIAN HIEROGLYPH A269ANATOLIAN HIEROGLYPH A270ANATOLIA" +
"N HIEROGLYPH A271ANATOLIAN HIEROGLYPH A272ANATOLIAN HIEROGLYPH A273ANATO" +
"LIAN HIEROGLYPH A274ANATOLIAN HIEROGLYPH A275ANATOLIAN HIEROGLYPH A276AN" +
"ATOLIAN HIEROGLYPH A277ANATOLIAN HIEROGLYPH A278ANATOLIAN HIEROGLYPH A27" +
"9ANATOLIAN HIEROGLYPH A280ANATOLIAN HIEROGLYPH A281ANATOLIAN HIEROGLYPH " +
"A282ANATOLIAN HIEROGLYPH A283ANATOLIAN HIEROGLYPH A284ANATOLIAN HIEROGLY" +
"PH A285ANATOLIAN HIEROGLYPH A286ANATOLIAN HIEROGLYPH A287ANATOLIAN HIERO" +
"GLYPH A288ANATOLIAN HIEROGLYPH A289ANATOLIAN HIEROGLYPH A289AANATOLIAN H" +
"IEROGLYPH A290ANATOLIAN HIEROGLYPH A291ANATOLIAN HIEROGLYPH A292ANATOLIA" +
"N HIEROGLYPH A293ANATOLIAN HIEROGLYPH A294ANATOLIAN HIEROGLYPH A294AANAT" +
"OLIAN HIEROGLYPH A295ANATOLIAN HIEROGLYPH A296ANATOLIAN HIEROGLYPH A297A" +
"NATOLIAN HIEROGLYPH A298ANATOLIAN HIEROGLYPH A299ANATOLIAN HIEROGLYPH A2" +
"99AANATOLIAN HIEROGLYPH A300ANATOLIAN HIEROGLYPH A301ANATOLIAN HIEROGLYP" +
"H A302ANATOLIAN HIEROGLYPH A303ANATOLIAN HIEROGLYPH A304ANATOLIAN HIEROG" +
"LYPH A305ANATOLIAN HIEROGLYPH A306ANATOLIAN HIEROGLYPH A307ANATOLIAN HIE" +
"ROGLYPH A308ANATOLIAN HIEROGLYPH A309ANATOLIAN HIEROGLYPH A309AANATOLIAN" +
" HIEROGLYPH A310ANATOLIAN HIEROGLYPH A311ANATOLIAN HIEROGLYPH A312ANATOL" +
"IAN HIEROGLYPH A313ANATOLIAN HIEROGLYPH A314ANATOLIAN HIEROGLYPH A315ANA" +
"TOLIAN HIEROGLYPH A316ANATOLIAN HIEROGLYPH A317ANATOLIAN HIEROGLYPH A318" +
"ANATOLIAN HIEROGLYPH A319ANATOLIAN HIEROGLYPH A320ANATOLIAN HIEROGLYPH A" +
"321ANATOLIAN HIEROGLYPH A322ANATOLIAN HIEROGLYPH A323ANATOLIAN HIEROGLYP" +
"H A324ANATOLIAN HIEROGLYPH A325ANATOLIAN HIEROGLYPH A326ANATOLIAN HIEROG" +
"LYPH A327ANATOLIAN HIEROGLYPH A328ANATOLIAN HIEROGLYPH A329ANATOLIAN HIE" +
"ROGLYPH A329AANATOLIAN HIEROGLYPH A330ANATOLIAN HIEROGLYPH A331ANATOLIAN" +
" HIEROGLYPH A332AANATOLIAN HIEROGLYPH A332BANATOLIAN HIEROGLYPH A332CANA" +
"TOLIAN HIEROGLYPH A333ANATOLIAN HIEROGLYPH A334ANATOLIAN HIEROGLYPH A335" +
"ANATOLIAN HIEROGLYPH A336ANATOLIAN HIEROGLYPH A336AANATOLIAN HIEROGLYPH " +
"A336BANATOLIAN HIEROGLYPH A336CANATOLIAN HIEROGLYPH A337ANATOLIAN HIEROG" +
"LYPH A338ANATOLIAN HIEROGLYPH A339ANATOLIAN HIEROGLYPH A340ANATOLIAN HIE" +
"ROGLYPH A341ANATOLIAN HIEROGLYPH A342ANATOLIAN HIEROGLYPH A343ANATOLIAN " +
"HIEROGLYPH A344ANATOLIAN HIEROGLYPH A345ANATOLIAN HIEROGLYPH A346ANATOLI" +
"AN HIEROGLYPH A347ANATOLIAN HIEROGLYPH A348ANATOLIAN HIEROGLYPH A349ANAT" +
"OLIAN HIEROGLYPH A350ANATOLIAN HIEROGLYPH A351ANATOLIAN HIEROGLYPH A352A" +
"NATOLIAN HIEROGLYPH A353ANATOLIAN HIEROGLYPH A354ANATOLIAN HIEROGLYPH A3" +
"55ANATOLIAN HIEROGLYPH A356ANATOLIAN HIEROGLYPH A357ANATOLIAN HIEROGLYPH") + ("" +
" A358ANATOLIAN HIEROGLYPH A359ANATOLIAN HIEROGLYPH A359AANATOLIAN HIEROG" +
"LYPH A360ANATOLIAN HIEROGLYPH A361ANATOLIAN HIEROGLYPH A362ANATOLIAN HIE" +
"ROGLYPH A363ANATOLIAN HIEROGLYPH A364ANATOLIAN HIEROGLYPH A364AANATOLIAN" +
" HIEROGLYPH A365ANATOLIAN HIEROGLYPH A366ANATOLIAN HIEROGLYPH A367ANATOL" +
"IAN HIEROGLYPH A368ANATOLIAN HIEROGLYPH A368AANATOLIAN HIEROGLYPH A369AN" +
"ATOLIAN HIEROGLYPH A370ANATOLIAN HIEROGLYPH A371ANATOLIAN HIEROGLYPH A37" +
"1AANATOLIAN HIEROGLYPH A372ANATOLIAN HIEROGLYPH A373ANATOLIAN HIEROGLYPH" +
" A374ANATOLIAN HIEROGLYPH A375ANATOLIAN HIEROGLYPH A376ANATOLIAN HIEROGL" +
"YPH A377ANATOLIAN HIEROGLYPH A378ANATOLIAN HIEROGLYPH A379ANATOLIAN HIER" +
"OGLYPH A380ANATOLIAN HIEROGLYPH A381ANATOLIAN HIEROGLYPH A381AANATOLIAN " +
"HIEROGLYPH A382ANATOLIAN HIEROGLYPH A383 RA OR RIANATOLIAN HIEROGLYPH A3" +
"83AANATOLIAN HIEROGLYPH A384ANATOLIAN HIEROGLYPH A385ANATOLIAN HIEROGLYP" +
"H A386ANATOLIAN HIEROGLYPH A386AANATOLIAN HIEROGLYPH A387ANATOLIAN HIERO" +
"GLYPH A388ANATOLIAN HIEROGLYPH A389ANATOLIAN HIEROGLYPH A390ANATOLIAN HI" +
"EROGLYPH A391ANATOLIAN HIEROGLYPH A392ANATOLIAN HIEROGLYPH A393 EIGHTANA" +
"TOLIAN HIEROGLYPH A394ANATOLIAN HIEROGLYPH A395ANATOLIAN HIEROGLYPH A396" +
"ANATOLIAN HIEROGLYPH A397ANATOLIAN HIEROGLYPH A398ANATOLIAN HIEROGLYPH A" +
"399ANATOLIAN HIEROGLYPH A400ANATOLIAN HIEROGLYPH A401ANATOLIAN HIEROGLYP" +
"H A402ANATOLIAN HIEROGLYPH A403ANATOLIAN HIEROGLYPH A404ANATOLIAN HIEROG" +
"LYPH A405ANATOLIAN HIEROGLYPH A406ANATOLIAN HIEROGLYPH A407ANATOLIAN HIE" +
"ROGLYPH A408ANATOLIAN HIEROGLYPH A409ANATOLIAN HIEROGLYPH A410 BEGIN LOG" +
"OGRAM MARKANATOLIAN HIEROGLYPH A410A END LOGOGRAM MARKANATOLIAN HIEROGLY" +
"PH A411ANATOLIAN HIEROGLYPH A412ANATOLIAN HIEROGLYPH A413ANATOLIAN HIERO" +
"GLYPH A414ANATOLIAN HIEROGLYPH A415ANATOLIAN HIEROGLYPH A416ANATOLIAN HI" +
"EROGLYPH A417ANATOLIAN HIEROGLYPH A418ANATOLIAN HIEROGLYPH A419ANATOLIAN" +
" HIEROGLYPH A420ANATOLIAN HIEROGLYPH A421ANATOLIAN HIEROGLYPH A422ANATOL" +
"IAN HIEROGLYPH A423ANATOLIAN HIEROGLYPH A424ANATOLIAN HIEROGLYPH A425ANA" +
"TOLIAN HIEROGLYPH A426ANATOLIAN HIEROGLYPH A427ANATOLIAN HIEROGLYPH A428" +
"ANATOLIAN HIEROGLYPH A429ANATOLIAN HIEROGLYPH A430ANATOLIAN HIEROGLYPH A" +
"431ANATOLIAN HIEROGLYPH A432ANATOLIAN HIEROGLYPH A433ANATOLIAN HIEROGLYP" +
"H A434ANATOLIAN HIEROGLYPH A435ANATOLIAN HIEROGLYPH A436ANATOLIAN HIEROG" +
"LYPH A437ANATOLIAN HIEROGLYPH A438ANATOLIAN HIEROGLYPH A439ANATOLIAN HIE" +
"ROGLYPH A440ANATOLIAN HIEROGLYPH A441ANATOLIAN HIEROGLYPH A442ANATOLIAN " +
"HIEROGLYPH A443ANATOLIAN HIEROGLYPH A444ANATOLIAN HIEROGLYPH A445ANATOLI" +
"AN HIEROGLYPH A446ANATOLIAN HIEROGLYPH A447ANATOLIAN HIEROGLYPH A448ANAT" +
"OLIAN HIEROGLYPH A449ANATOLIAN HIEROGLYPH A450ANATOLIAN HIEROGLYPH A450A" +
"ANATOLIAN HIEROGLYPH A451ANATOLIAN HIEROGLYPH A452ANATOLIAN HIEROGLYPH A" +
"453ANATOLIAN HIEROGLYPH A454ANATOLIAN HIEROGLYPH A455ANATOLIAN HIEROGLYP" +
"H A456ANATOLIAN HIEROGLYPH A457ANATOLIAN HIEROGLYPH A457AANATOLIAN HIERO" +
"GLYPH A458ANATOLIAN HIEROGLYPH A459ANATOLIAN HIEROGLYPH A460ANATOLIAN HI" +
"EROGLYPH A461ANATOLIAN HIEROGLYPH A462ANATOLIAN HIEROGLYPH A463ANATOLIAN" +
" HIEROGLYPH A464ANATOLIAN HIEROGLYPH A465ANATOLIAN HIEROGLYPH A466ANATOL" +
"IAN HIEROGLYPH A467ANATOLIAN HIEROGLYPH A468ANATOLIAN HIEROGLYPH A469ANA" +
"TOLIAN HIEROGLYPH A470ANATOLIAN HIEROGLYPH A471ANATOLIAN HIEROGLYPH A472" +
"ANATOLIAN HIEROGLYPH A473ANATOLIAN HIEROGLYPH A474ANATOLIAN HIEROGLYPH A" +
"475ANATOLIAN HIEROGLYPH A476ANATOLIAN HIEROGLYPH A477ANATOLIAN HIEROGLYP" +
"H A478ANATOLIAN HIEROGLYPH A479ANATOLIAN HIEROGLYPH A480ANATOLIAN HIEROG" +
"LYPH A481ANATOLIAN HIEROGLYPH A482ANATOLIAN HIEROGLYPH A483ANATOLIAN HIE" +
"ROGLYPH A484ANATOLIAN HIEROGLYPH A485ANATOLIAN HIEROGLYPH A486ANATOLIAN " +
"HIEROGLYPH A487ANATOLIAN HIEROGLYPH A488ANATOLIAN HIEROGLYPH A489ANATOLI" +
"AN HIEROGLYPH A490ANATOLIAN HIEROGLYPH A491ANATOLIAN HIEROGLYPH A492ANAT" +
"OLIAN HIEROGLYPH A493ANATOLIAN HIEROGLYPH A494ANATOLIAN HIEROGLYPH A495A" +
"NATOLIAN HIEROGLYPH A496ANATOLIAN HIEROGLYPH A497ANATOLIAN HIEROGLYPH A5" +
"01ANATOLIAN HIEROGLYPH A502ANATOLIAN HIEROGLYPH A503ANATOLIAN HIEROGLYPH" +
" A504ANATOLIAN HIEROGLYPH A505ANATOLIAN HIEROGLYPH A506ANATOLIAN HIEROGL" +
"YPH A507ANATOLIAN HIEROGLYPH A508ANATOLIAN HIEROGLYPH A509ANATOLIAN HIER" +
"OGLYPH A510ANATOLIAN HIEROGLYPH A511ANATOLIAN HIEROGLYPH A512ANATOLIAN H" +
"IEROGLYPH A513ANATOLIAN HIEROGLYPH A514ANATOLIAN HIEROGLYPH A515ANATOLIA" +
"N HIEROGLYPH A516ANATOLIAN HIEROGLYPH A517ANATOLIAN HIEROGLYPH A518ANATO" +
"LIAN HIEROGLYPH A519ANATOLIAN HIEROGLYPH A520ANATOLIAN HIEROGLYPH A521AN" +
"ATOLIAN HIEROGLYPH A522ANATOLIAN HIEROGLYPH A523ANATOLIAN HIEROGLYPH A52" +
"4ANATOLIAN HIEROGLYPH A525ANATOLIAN HIEROGLYPH A526ANATOLIAN HIEROGLYPH " +
"A527ANATOLIAN HIEROGLYPH A528ANATOLIAN HIEROGLYPH A529ANATOLIAN HIEROGLY" +
"PH A530GURUNG KHEMA LETTER AGURUNG KHEMA LETTER KAGURUNG KHEMA LETTER KH") + ("" +
"AGURUNG KHEMA LETTER GAGURUNG KHEMA LETTER GHAGURUNG KHEMA LETTER NGAGUR" +
"UNG KHEMA LETTER CAGURUNG KHEMA LETTER CHAGURUNG KHEMA LETTER JAGURUNG K" +
"HEMA LETTER JHAGURUNG KHEMA LETTER HAGURUNG KHEMA LETTER TTAGURUNG KHEMA" +
" LETTER TTHAGURUNG KHEMA LETTER DDAGURUNG KHEMA LETTER DDHAGURUNG KHEMA " +
"LETTER VAGURUNG KHEMA LETTER TAGURUNG KHEMA LETTER THAGURUNG KHEMA LETTE" +
"R DAGURUNG KHEMA LETTER DHAGURUNG KHEMA LETTER NAGURUNG KHEMA LETTER PAG" +
"URUNG KHEMA LETTER PHAGURUNG KHEMA LETTER BAGURUNG KHEMA LETTER BHAGURUN" +
"G KHEMA LETTER MAGURUNG KHEMA LETTER YAGURUNG KHEMA LETTER RAGURUNG KHEM" +
"A LETTER LAGURUNG KHEMA LETTER SAGURUNG KHEMA VOWEL SIGN AAGURUNG KHEMA " +
"VOWEL SIGN IGURUNG KHEMA VOWEL SIGN IIGURUNG KHEMA VOWEL SIGN UGURUNG KH" +
"EMA VOWEL SIGN UUGURUNG KHEMA VOWEL SIGN EGURUNG KHEMA VOWEL SIGN EEGURU" +
"NG KHEMA VOWEL SIGN AIGURUNG KHEMA VOWEL SIGN OGURUNG KHEMA VOWEL SIGN O" +
"OGURUNG KHEMA VOWEL SIGN AUGURUNG KHEMA VOWEL LENGTH MARKGURUNG KHEMA CO" +
"NSONANT SIGN MEDIAL YAGURUNG KHEMA CONSONANT SIGN MEDIAL VAGURUNG KHEMA " +
"CONSONANT SIGN MEDIAL HAGURUNG KHEMA SIGN ANUSVARAGURUNG KHEMA CONSONANT" +
" SIGN MEDIAL RAGURUNG KHEMA SIGN THOLHOMAGURUNG KHEMA DIGIT ZEROGURUNG K" +
"HEMA DIGIT ONEGURUNG KHEMA DIGIT TWOGURUNG KHEMA DIGIT THREEGURUNG KHEMA" +
" DIGIT FOURGURUNG KHEMA DIGIT FIVEGURUNG KHEMA DIGIT SIXGURUNG KHEMA DIG" +
"IT SEVENGURUNG KHEMA DIGIT EIGHTGURUNG KHEMA DIGIT NINEBAMUM LETTER PHAS" +
"E-A NGKUE MFONBAMUM LETTER PHASE-A GBIEE FONBAMUM LETTER PHASE-A PON MFO" +
"N PIPAEMGBIEEBAMUM LETTER PHASE-A PON MFON PIPAEMBABAMUM LETTER PHASE-A " +
"NAA MFONBAMUM LETTER PHASE-A SHUENSHUETBAMUM LETTER PHASE-A TITA MFONBAM" +
"UM LETTER PHASE-A NZA MFONBAMUM LETTER PHASE-A SHINDA PA NJIBAMUM LETTER" +
" PHASE-A PON PA NJI PIPAEMGBIEEBAMUM LETTER PHASE-A PON PA NJI PIPAEMBAB" +
"AMUM LETTER PHASE-A MAEMBGBIEEBAMUM LETTER PHASE-A TU MAEMBABAMUM LETTER" +
" PHASE-A NGANGUBAMUM LETTER PHASE-A MAEMVEUXBAMUM LETTER PHASE-A MANSUAE" +
"BAMUM LETTER PHASE-A MVEUAENGAMBAMUM LETTER PHASE-A SEUNYAMBAMUM LETTER " +
"PHASE-A NTOQPENBAMUM LETTER PHASE-A KEUKEUTNDABAMUM LETTER PHASE-A NKIND" +
"IBAMUM LETTER PHASE-A SUUBAMUM LETTER PHASE-A NGKUENZEUMBAMUM LETTER PHA" +
"SE-A LAPAQBAMUM LETTER PHASE-A LET KUTBAMUM LETTER PHASE-A NTAP MFAABAMU" +
"M LETTER PHASE-A MAEKEUPBAMUM LETTER PHASE-A PASHAEBAMUM LETTER PHASE-A " +
"GHEUAERAEBAMUM LETTER PHASE-A PAMSHAEBAMUM LETTER PHASE-A MON NGGEUAETBA" +
"MUM LETTER PHASE-A NZUN MEUTBAMUM LETTER PHASE-A U YUQ NAEBAMUM LETTER P" +
"HASE-A GHEUAEGHEUAEBAMUM LETTER PHASE-A NTAP NTAABAMUM LETTER PHASE-A SI" +
"SABAMUM LETTER PHASE-A MGBASABAMUM LETTER PHASE-A MEUNJOMNDEUQBAMUM LETT" +
"ER PHASE-A MOOMPUQBAMUM LETTER PHASE-A KAFABAMUM LETTER PHASE-A PA LEERA" +
"EWABAMUM LETTER PHASE-A NDA LEERAEWABAMUM LETTER PHASE-A PETBAMUM LETTER" +
" PHASE-A MAEMKPENBAMUM LETTER PHASE-A NIKABAMUM LETTER PHASE-A PUPBAMUM " +
"LETTER PHASE-A TUAEPBAMUM LETTER PHASE-A LUAEPBAMUM LETTER PHASE-A SONJA" +
"MBAMUM LETTER PHASE-A TEUTEUWENBAMUM LETTER PHASE-A MAENYIBAMUM LETTER P" +
"HASE-A KETBAMUM LETTER PHASE-A NDAANGGEUAETBAMUM LETTER PHASE-A KUOQBAMU" +
"M LETTER PHASE-A MOOMEUTBAMUM LETTER PHASE-A SHUMBAMUM LETTER PHASE-A LO" +
"MMAEBAMUM LETTER PHASE-A FIRIBAMUM LETTER PHASE-A ROMBAMUM LETTER PHASE-" +
"A KPOQBAMUM LETTER PHASE-A SOQBAMUM LETTER PHASE-A MAP PIEETBAMUM LETTER" +
" 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 N" +
"GGENBAMUM LETTER PHASE-A MAESIBAMUM LETTER PHASE-A NJAMBAMUM LETTER PHAS" +
"E-A MBANYIBAMUM LETTER PHASE-A NYETBAMUM LETTER PHASE-A TEUAENBAMUM LETT" +
"ER PHASE-A SOTBAMUM LETTER PHASE-A PAAMBAMUM LETTER PHASE-A NSHIEEBAMUM " +
"LETTER PHASE-A MAEMBAMUM LETTER PHASE-A NYIBAMUM LETTER PHASE-A KAQBAMUM" +
" LETTER PHASE-A NSHABAMUM LETTER PHASE-A VEEBAMUM LETTER PHASE-A LUBAMUM" +
" LETTER PHASE-A NENBAMUM LETTER PHASE-A NAQBAMUM LETTER PHASE-A MBAQBAMU" +
"M LETTER PHASE-B NSHUETBAMUM LETTER PHASE-B TU MAEMGBIEEBAMUM LETTER PHA" +
"SE-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 P" +
"HASE-B PEESHIBAMUM LETTER PHASE-B YAFU LEERAEWABAMUM LETTER PHASE-B LAM " +
"NSHUT NYAMBAMUM LETTER PHASE-B NTIEE SHEUOQBAMUM LETTER PHASE-B NDU NJAA" +
"BAMUM LETTER PHASE-B GHEUGHEUAEMBAMUM LETTER PHASE-B PITBAMUM LETTER PHA" +
"SE-B TU NSIEEBAMUM LETTER PHASE-B SHET NJAQBAMUM LETTER PHASE-B SHEUAEQT" +
"UBAMUM 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 LET") + ("" +
"TER PHASE-B PARUMBAMUM LETTER PHASE-B VEUMBAMUM LETTER PHASE-B NGKINDI M" +
"VOPBAMUM LETTER PHASE-B NGGEU MBUBAMUM LETTER PHASE-B WUAETBAMUM LETTER " +
"PHASE-B SAKEUAEBAMUM LETTER PHASE-B TAAMBAMUM LETTER PHASE-B MEUQBAMUM L" +
"ETTER 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 PUNGAAM" +
"BAMUM LETTER PHASE-B MEUT NGGEETBAMUM LETTER PHASE-B FEUXBAMUM LETTER PH" +
"ASE-B MBUOQBAMUM LETTER PHASE-B FEEBAMUM LETTER PHASE-B KEUAEMBAMUM LETT" +
"ER PHASE-B MA NJEUAENABAMUM LETTER PHASE-B MA NJUQABAMUM LETTER PHASE-B " +
"LETBAMUM LETTER PHASE-B NGGAAMBAMUM LETTER PHASE-B NSENBAMUM LETTER PHAS" +
"E-B MABAMUM LETTER PHASE-B KIQBAMUM LETTER PHASE-B NGOMBAMUM LETTER PHAS" +
"E-C NGKUE MAEMBABAMUM LETTER PHASE-C NZABAMUM LETTER PHASE-C YUMBAMUM LE" +
"TTER PHASE-C WANGKUOQBAMUM LETTER PHASE-C NGGENBAMUM LETTER PHASE-C NDEU" +
"AEREEBAMUM LETTER PHASE-C NGKAQBAMUM LETTER PHASE-C GHARAEBAMUM LETTER P" +
"HASE-C MBEEKEETBAMUM LETTER PHASE-C GBAYIBAMUM LETTER PHASE-C NYIR MKPAR" +
"AQ MEUNBAMUM LETTER PHASE-C NTU MBITBAMUM LETTER PHASE-C MBEUMBAMUM LETT" +
"ER PHASE-C PIRIEENBAMUM LETTER PHASE-C NDOMBUBAMUM LETTER PHASE-C MBAA C" +
"ABBAGE-TREEBAMUM LETTER PHASE-C KEUSHEUAEPBAMUM LETTER PHASE-C GHAPBAMUM" +
" 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 LE" +
"TTER PHASE-C KAABAMUM LETTER PHASE-C SEUXBAMUM LETTER PHASE-C NDIDABAMUM" +
" LETTER PHASE-C TAASHAEBAMUM LETTER PHASE-C NJUEQBAMUM LETTER PHASE-C TI" +
"TA YUEBAMUM LETTER PHASE-C SUAETBAMUM LETTER PHASE-C NGGUAEN NYAMBAMUM L" +
"ETTER PHASE-C VEUXBAMUM LETTER PHASE-C NANSANAQBAMUM LETTER PHASE-C MA K" +
"EUAERIBAMUM LETTER PHASE-C NTAABAMUM LETTER PHASE-C NGGUONBAMUM LETTER P" +
"HASE-C LAPBAMUM LETTER PHASE-C MBIRIEENBAMUM LETTER PHASE-C MGBASAQBAMUM" +
" LETTER PHASE-C NTEUNGBABAMUM LETTER PHASE-C TEUTEUXBAMUM LETTER PHASE-C" +
" NGGUMBAMUM LETTER PHASE-C FUEBAMUM LETTER PHASE-C NDEUTBAMUM LETTER PHA" +
"SE-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 TITUAEP" +
"BAMUM LETTER PHASE-C NSUOT NGOMBAMUM LETTER PHASE-C NJEEEEBAMUM LETTER P" +
"HASE-C KETBAMUM LETTER PHASE-C NGGUBAMUM LETTER PHASE-C MAESIBAMUM LETTE" +
"R PHASE-C MBUAEMBAMUM LETTER PHASE-C LUBAMUM LETTER PHASE-C KUTBAMUM LET" +
"TER PHASE-C NJAMBAMUM LETTER PHASE-C NGOMBAMUM LETTER PHASE-C WUPBAMUM L" +
"ETTER PHASE-C NGGUEETBAMUM LETTER PHASE-C NSOMBAMUM LETTER PHASE-C NTENB" +
"AMUM LETTER PHASE-C KUOP NKAARAEBAMUM LETTER PHASE-C NSUNBAMUM LETTER PH" +
"ASE-C NDAMBAMUM LETTER PHASE-C MA NSIEEBAMUM LETTER PHASE-C YAABAMUM LET" +
"TER PHASE-C NDAPBAMUM LETTER PHASE-C SHUEQBAMUM LETTER PHASE-C SETFONBAM" +
"UM LETTER PHASE-C MBIBAMUM LETTER PHASE-C MAEMBABAMUM LETTER PHASE-C MBA" +
"NYIBAMUM LETTER PHASE-C KEUSEUXBAMUM LETTER PHASE-C MBEUXBAMUM LETTER PH" +
"ASE-C KEUMBAMUM LETTER PHASE-C MBAA PICKETBAMUM LETTER PHASE-C YUWOQBAMU" +
"M LETTER PHASE-C NJEUXBAMUM LETTER PHASE-C MIEEBAMUM LETTER PHASE-C MUAE" +
"BAMUM LETTER PHASE-C SHIQBAMUM LETTER PHASE-C KEN LAWBAMUM LETTER PHASE-" +
"C KEN FATIGUEBAMUM LETTER PHASE-C NGAQBAMUM LETTER PHASE-C NAQBAMUM LETT" +
"ER PHASE-C LIQBAMUM LETTER PHASE-C PINBAMUM LETTER PHASE-C PENBAMUM LETT" +
"ER PHASE-C TETBAMUM LETTER PHASE-D MBUOBAMUM LETTER PHASE-D WAPBAMUM LET" +
"TER PHASE-D NJIBAMUM LETTER PHASE-D MFONBAMUM LETTER PHASE-D NJIEEBAMUM " +
"LETTER PHASE-D LIEEBAMUM LETTER PHASE-D NJEUTBAMUM LETTER PHASE-D NSHEEB" +
"AMUM LETTER PHASE-D NGGAAMAEBAMUM LETTER PHASE-D NYAMBAMUM LETTER PHASE-" +
"D WUAENBAMUM LETTER PHASE-D NGKUNBAMUM LETTER PHASE-D SHEEBAMUM LETTER P" +
"HASE-D NGKAPBAMUM LETTER PHASE-D KEUAETMEUNBAMUM LETTER PHASE-D TEUTBAMU" +
"M LETTER PHASE-D SHEUAEBAMUM LETTER PHASE-D NJAPBAMUM LETTER PHASE-D SUE" +
"BAMUM LETTER PHASE-D KETBAMUM LETTER PHASE-D YAEMMAEBAMUM LETTER PHASE-D" +
" KUOMBAMUM LETTER PHASE-D SAPBAMUM LETTER PHASE-D MFEUTBAMUM LETTER PHAS" +
"E-D NDEUXBAMUM LETTER PHASE-D MALEERIBAMUM LETTER PHASE-D MEUTBAMUM LETT" +
"ER PHASE-D SEUAEQBAMUM LETTER PHASE-D YENBAMUM LETTER PHASE-D NJEUAEMBAM" +
"UM LETTER PHASE-D KEUOT MBUAEBAMUM LETTER PHASE-D NGKEURIBAMUM LETTER PH" +
"ASE-D TUBAMUM LETTER PHASE-D GHAABAMUM LETTER PHASE-D NGKYEEBAMUM LETTER" +
" PHASE-D FEUFEUAETBAMUM LETTER PHASE-D NDEEBAMUM LETTER PHASE-D MGBOFUMB" +
"AMUM LETTER PHASE-D LEUAEPBAMUM LETTER PHASE-D NDONBAMUM LETTER PHASE-D " +
"MONIBAMUM LETTER PHASE-D MGBEUNBAMUM LETTER PHASE-D PUUTBAMUM LETTER PHA" +
"SE-D MGBIEEBAMUM LETTER PHASE-D MFOBAMUM LETTER PHASE-D LUMBAMUM LETTER ") + ("" +
"PHASE-D NSIEEPBAMUM LETTER PHASE-D MBAABAMUM LETTER PHASE-D KWAETBAMUM L" +
"ETTER PHASE-D NYETBAMUM LETTER PHASE-D TEUAENBAMUM LETTER PHASE-D SOTBAM" +
"UM LETTER PHASE-D YUWOQBAMUM LETTER PHASE-D KEUMBAMUM LETTER PHASE-D RAE" +
"MBAMUM LETTER PHASE-D TEEEEBAMUM LETTER PHASE-D NGKEUAEQBAMUM LETTER PHA" +
"SE-D MFEUAEBAMUM LETTER PHASE-D NSIEETBAMUM LETTER PHASE-D KEUPBAMUM LET" +
"TER PHASE-D PIPBAMUM LETTER PHASE-D PEUTAEBAMUM LETTER PHASE-D NYUEBAMUM" +
" LETTER PHASE-D LETBAMUM LETTER PHASE-D NGGAAMBAMUM LETTER PHASE-D MFIEE" +
"BAMUM LETTER PHASE-D NGGWAENBAMUM LETTER PHASE-D YUOMBAMUM LETTER PHASE-" +
"D PAPBAMUM LETTER PHASE-D YUOPBAMUM LETTER PHASE-D NDAMBAMUM LETTER PHAS" +
"E-D NTEUMBAMUM LETTER PHASE-D SUAEBAMUM LETTER PHASE-D KUNBAMUM LETTER P" +
"HASE-D NGGEUXBAMUM LETTER PHASE-D NGKIEEBAMUM LETTER PHASE-D TUOTBAMUM L" +
"ETTER PHASE-D MEUNBAMUM LETTER PHASE-D KUQBAMUM LETTER PHASE-D NSUMBAMUM" +
" LETTER PHASE-D TEUNBAMUM LETTER PHASE-D MAENJETBAMUM LETTER PHASE-D NGG" +
"APBAMUM LETTER PHASE-D LEUMBAMUM LETTER PHASE-D NGGUOMBAMUM LETTER PHASE" +
"-D NSHUTBAMUM LETTER PHASE-D NJUEQBAMUM LETTER PHASE-D GHEUAEBAMUM LETTE" +
"R PHASE-D KUBAMUM LETTER PHASE-D REN OLDBAMUM LETTER PHASE-D TAEBAMUM LE" +
"TTER PHASE-D TOQBAMUM LETTER PHASE-D NYIBAMUM LETTER PHASE-D RIIBAMUM LE" +
"TTER 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 NUBAMU" +
"M LETTER PHASE-D SHUBAMUM LETTER PHASE-D NTEEBAMUM LETTER PHASE-D PEEBAM" +
"UM LETTER PHASE-D NIBAMUM LETTER PHASE-D SHOQBAMUM LETTER PHASE-D PUQBAM" +
"UM LETTER PHASE-D MVOPBAMUM LETTER PHASE-D LOQBAMUM LETTER PHASE-D REN M" +
"UCHBAMUM LETTER PHASE-D TIBAMUM LETTER PHASE-D NTUUBAMUM LETTER PHASE-D " +
"MBAA SEVENBAMUM LETTER PHASE-D SAQBAMUM LETTER PHASE-D FAABAMUM LETTER P" +
"HASE-E NDAPBAMUM LETTER PHASE-E TOONBAMUM LETTER PHASE-E MBEUMBAMUM LETT" +
"ER PHASE-E LAPBAMUM LETTER PHASE-E VOMBAMUM LETTER PHASE-E LOONBAMUM LET" +
"TER PHASE-E PAABAMUM LETTER PHASE-E SOMBAMUM LETTER PHASE-E RAQBAMUM LET" +
"TER PHASE-E NSHUOPBAMUM LETTER PHASE-E NDUNBAMUM LETTER PHASE-E PUAEBAMU" +
"M LETTER PHASE-E TAMBAMUM LETTER PHASE-E NGKABAMUM LETTER PHASE-E KPEUXB" +
"AMUM LETTER PHASE-E WUOBAMUM LETTER PHASE-E SEEBAMUM LETTER PHASE-E NGGE" +
"UAETBAMUM LETTER PHASE-E PAAMBAMUM LETTER PHASE-E TOOBAMUM LETTER PHASE-" +
"E KUOPBAMUM LETTER PHASE-E LOMBAMUM LETTER PHASE-E NSHIEEBAMUM LETTER PH" +
"ASE-E NGOPBAMUM LETTER PHASE-E MAEMBAMUM LETTER PHASE-E NGKEUXBAMUM LETT" +
"ER PHASE-E NGOQBAMUM LETTER PHASE-E NSHUEBAMUM LETTER PHASE-E RIMGBABAMU" +
"M LETTER PHASE-E NJEUXBAMUM LETTER PHASE-E PEEMBAMUM LETTER PHASE-E SAAB" +
"AMUM LETTER PHASE-E NGGURAEBAMUM LETTER PHASE-E MGBABAMUM LETTER PHASE-E" +
" GHEUXBAMUM LETTER PHASE-E NGKEUAEMBAMUM LETTER PHASE-E NJAEMLIBAMUM LET" +
"TER PHASE-E MAPBAMUM LETTER PHASE-E LOOTBAMUM LETTER PHASE-E NGGEEEEBAMU" +
"M LETTER PHASE-E NDIQBAMUM LETTER PHASE-E TAEN NTEUMBAMUM LETTER PHASE-E" +
" SETBAMUM LETTER PHASE-E PUMBAMUM LETTER PHASE-E NDAA SOFTNESSBAMUM LETT" +
"ER PHASE-E NGGUAESHAE NYAMBAMUM LETTER PHASE-E YIEEBAMUM LETTER PHASE-E " +
"GHEUNBAMUM LETTER PHASE-E TUAEBAMUM LETTER PHASE-E YEUAEBAMUM LETTER PHA" +
"SE-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 PUBAMUM" +
" LETTER PHASE-E TAAQBAMUM LETTER PHASE-E GHAAMAEBAMUM LETTER PHASE-E NGE" +
"UREUTBAMUM LETTER PHASE-E SHEUAEQBAMUM LETTER PHASE-E MGBENBAMUM LETTER " +
"PHASE-E MBEEBAMUM LETTER PHASE-E NZAQBAMUM LETTER PHASE-E NKOMBAMUM LETT" +
"ER PHASE-E GBETBAMUM LETTER PHASE-E TUMBAMUM LETTER PHASE-E KUETBAMUM LE" +
"TTER PHASE-E YAPBAMUM LETTER PHASE-E NYI CLEAVERBAMUM LETTER PHASE-E YIT" +
"BAMUM LETTER PHASE-E MFEUQBAMUM LETTER PHASE-E NDIAQBAMUM LETTER PHASE-E" +
" PIEEQBAMUM LETTER PHASE-E YUEQBAMUM LETTER PHASE-E LEUAEMBAMUM LETTER P" +
"HASE-E FUEBAMUM LETTER PHASE-E GBEUXBAMUM LETTER PHASE-E NGKUPBAMUM LETT" +
"ER PHASE-E KETBAMUM LETTER PHASE-E MAEBAMUM LETTER PHASE-E NGKAAMIBAMUM " +
"LETTER PHASE-E GHETBAMUM LETTER PHASE-E FABAMUM LETTER PHASE-E NTUMBAMUM" +
" LETTER PHASE-E PEUTBAMUM LETTER PHASE-E YEUMBAMUM LETTER PHASE-E NGGEUA" +
"EBAMUM LETTER PHASE-E NYI BETWEENBAMUM LETTER PHASE-E NZUQBAMUM LETTER P" +
"HASE-E POONBAMUM LETTER PHASE-E MIEEBAMUM LETTER PHASE-E FUETBAMUM LETTE" +
"R PHASE-E NAEBAMUM LETTER PHASE-E MUAEBAMUM LETTER PHASE-E GHEUAEBAMUM L" +
"ETTER PHASE-E FU IBAMUM LETTER PHASE-E MVIBAMUM LETTER PHASE-E PUAQBAMUM" +
" LETTER PHASE-E NGKUMBAMUM LETTER PHASE-E KUTBAMUM LETTER PHASE-E PIETBA" +
"MUM LETTER PHASE-E NTAPBAMUM LETTER PHASE-E YEUAETBAMUM LETTER PHASE-E N" +
"GGUPBAMUM LETTER PHASE-E PA PEOPLEBAMUM LETTER PHASE-E FU CALLBAMUM LETT") + ("" +
"ER PHASE-E FOMBAMUM LETTER PHASE-E NJEEBAMUM LETTER PHASE-E ABAMUM LETTE" +
"R PHASE-E TOQBAMUM LETTER PHASE-E OBAMUM LETTER PHASE-E IBAMUM LETTER PH" +
"ASE-E LAQBAMUM LETTER PHASE-E PA PLURALBAMUM LETTER PHASE-E TAABAMUM LET" +
"TER PHASE-E TAQBAMUM LETTER PHASE-E NDAA MY HOUSEBAMUM LETTER PHASE-E SH" +
"IQBAMUM LETTER PHASE-E YEUXBAMUM LETTER PHASE-E NGUAEBAMUM LETTER PHASE-" +
"E YUAENBAMUM LETTER PHASE-E YOQ SWIMMINGBAMUM LETTER PHASE-E YOQ COVERBA" +
"MUM LETTER PHASE-E YUQBAMUM LETTER PHASE-E YUNBAMUM LETTER PHASE-E KEUXB" +
"AMUM LETTER PHASE-E PEUXBAMUM LETTER PHASE-E NJEE EPOCHBAMUM LETTER PHAS" +
"E-E PUEBAMUM LETTER PHASE-E WUEBAMUM LETTER PHASE-E FEEBAMUM LETTER PHAS" +
"E-E VEEBAMUM LETTER PHASE-E LUBAMUM LETTER PHASE-E MIBAMUM LETTER PHASE-" +
"E REUXBAMUM LETTER PHASE-E RAEBAMUM LETTER PHASE-E NGUAETBAMUM LETTER PH" +
"ASE-E NGABAMUM LETTER PHASE-E SHOBAMUM LETTER PHASE-E SHOQBAMUM LETTER P" +
"HASE-E FU REMEDYBAMUM LETTER PHASE-E NABAMUM LETTER PHASE-E PIBAMUM LETT" +
"ER PHASE-E LOQBAMUM LETTER PHASE-E KOBAMUM LETTER PHASE-E MENBAMUM LETTE" +
"R PHASE-E MABAMUM LETTER PHASE-E MAQBAMUM LETTER PHASE-E TEUBAMUM LETTER" +
" 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 PHAS" +
"E-F REEBAMUM LETTER PHASE-F TAEBAMUM LETTER PHASE-F NYIBAMUM LETTER PHAS" +
"E-F LABAMUM LETTER PHASE-F RIIBAMUM LETTER PHASE-F RIEEBAMUM LETTER PHAS" +
"E-F MEEEEBAMUM LETTER PHASE-F TAABAMUM LETTER PHASE-F NDAABAMUM LETTER P" +
"HASE-F NJAEMBAMUM LETTER PHASE-F MBAMUM LETTER PHASE-F SUUBAMUM LETTER P" +
"HASE-F SHIIBAMUM LETTER PHASE-F SIBAMUM LETTER PHASE-F SEUXBAMUM LETTER " +
"PHASE-F KYEEBAMUM LETTER PHASE-F KETBAMUM LETTER PHASE-F NUAEBAMUM LETTE" +
"R PHASE-F NUBAMUM LETTER PHASE-F NJUAEBAMUM LETTER PHASE-F YOQBAMUM LETT" +
"ER PHASE-F SHUBAMUM LETTER PHASE-F YABAMUM LETTER PHASE-F NSHABAMUM LETT" +
"ER PHASE-F PEUXBAMUM LETTER PHASE-F NTEEBAMUM LETTER PHASE-F WUEBAMUM LE" +
"TTER PHASE-F PEEBAMUM LETTER PHASE-F RUBAMUM LETTER PHASE-F NIBAMUM LETT" +
"ER PHASE-F REUXBAMUM LETTER PHASE-F KENBAMUM LETTER PHASE-F NGKWAENBAMUM" +
" LETTER PHASE-F NGGABAMUM LETTER PHASE-F SHOBAMUM LETTER PHASE-F PUAEBAM" +
"UM LETTER PHASE-F FOMBAMUM LETTER PHASE-F WABAMUM LETTER PHASE-F LIBAMUM" +
" LETTER PHASE-F LOQBAMUM LETTER PHASE-F KOBAMUM LETTER PHASE-F MBENBAMUM" +
" LETTER PHASE-F RENBAMUM LETTER PHASE-F MABAMUM LETTER PHASE-F MOBAMUM L" +
"ETTER PHASE-F MBAABAMUM LETTER PHASE-F TETBAMUM LETTER PHASE-F KPABAMUM " +
"LETTER PHASE-F SAMBABAMUM LETTER PHASE-F VUEQMRO LETTER TAMRO LETTER NGI" +
"MRO LETTER YOMRO LETTER MIMMRO LETTER BAMRO LETTER DAMRO LETTER AMRO LET" +
"TER PHIMRO LETTER KHAIMRO LETTER HAOMRO LETTER DAIMRO LETTER CHUMRO LETT" +
"ER KEAAEMRO LETTER OLMRO LETTER MAEMMRO LETTER NINMRO LETTER PAMRO LETTE" +
"R OOMRO LETTER OMRO LETTER ROMRO LETTER SHIMRO LETTER THEAMRO LETTER EAM" +
"RO LETTER WAMRO LETTER EMRO LETTER KOMRO LETTER LANMRO LETTER LAMRO LETT" +
"ER HAIMRO LETTER RIMRO LETTER TEKMRO DIGIT ZEROMRO DIGIT ONEMRO DIGIT TW" +
"OMRO DIGIT THREEMRO DIGIT FOURMRO DIGIT FIVEMRO DIGIT SIXMRO DIGIT SEVEN" +
"MRO DIGIT EIGHTMRO DIGIT NINEMRO DANDAMRO DOUBLE DANDATANGSA LETTER OZTA" +
"NGSA LETTER OCTANGSA LETTER OQTANGSA LETTER OXTANGSA LETTER AZTANGSA LET" +
"TER ACTANGSA LETTER AQTANGSA LETTER AXTANGSA LETTER VZTANGSA LETTER VCTA" +
"NGSA LETTER VQTANGSA LETTER VXTANGSA LETTER EZTANGSA LETTER ECTANGSA LET" +
"TER EQTANGSA LETTER EXTANGSA LETTER IZTANGSA LETTER ICTANGSA LETTER IQTA" +
"NGSA LETTER IXTANGSA LETTER UZTANGSA LETTER UCTANGSA LETTER UQTANGSA LET" +
"TER UXTANGSA LETTER AWZTANGSA LETTER AWCTANGSA LETTER AWQTANGSA LETTER A" +
"WXTANGSA LETTER UIZTANGSA LETTER UICTANGSA LETTER UIQTANGSA LETTER UIXTA" +
"NGSA LETTER FINAL NGTANGSA LETTER LONG UEXTANGSA LETTER SHORT UEZTANGSA " +
"LETTER SHORT AWXTANGSA LETTER UECTANGSA LETTER UEZTANGSA LETTER UEQTANGS" +
"A LETTER UEXTANGSA LETTER UIUZTANGSA LETTER UIUCTANGSA LETTER UIUQTANGSA" +
" LETTER UIUXTANGSA LETTER MZTANGSA LETTER MCTANGSA LETTER MQTANGSA LETTE" +
"R MXTANGSA LETTER KATANGSA LETTER KHATANGSA LETTER GATANGSA LETTER NGATA" +
"NGSA LETTER SATANGSA LETTER YATANGSA LETTER WATANGSA LETTER PATANGSA LET" +
"TER NYATANGSA LETTER PHATANGSA LETTER BATANGSA LETTER MATANGSA LETTER NA" +
"TANGSA LETTER HATANGSA LETTER LATANGSA LETTER HTATANGSA LETTER TATANGSA " +
"LETTER DATANGSA LETTER RATANGSA LETTER NHATANGSA LETTER SHATANGSA LETTER" +
" CATANGSA LETTER TSATANGSA LETTER GHATANGSA LETTER HTTATANGSA LETTER THA" +
"TANGSA LETTER XATANGSA LETTER FATANGSA LETTER DHATANGSA LETTER CHATANGSA" +
" LETTER ZATANGSA DIGIT ZEROTANGSA DIGIT ONETANGSA DIGIT TWOTANGSA DIGIT " +
"THREETANGSA DIGIT FOURTANGSA DIGIT FIVETANGSA DIGIT SIXTANGSA DIGIT SEVE" +
"NTANGSA DIGIT EIGHTTANGSA DIGIT NINEBASSA VAH LETTER ENNIBASSA VAH LETTE") + ("" +
"R KABASSA VAH LETTER SEBASSA VAH LETTER FABASSA VAH LETTER MBEBASSA VAH " +
"LETTER YIEBASSA VAH LETTER GAHBASSA VAH LETTER DHIIBASSA VAH LETTER KPAH" +
"BASSA VAH LETTER JOBASSA VAH LETTER HWAHBASSA VAH LETTER WABASSA VAH LET" +
"TER ZOBASSA VAH LETTER GBUBASSA VAH LETTER DOBASSA VAH LETTER CEBASSA VA" +
"H LETTER UWUBASSA VAH LETTER TOBASSA VAH LETTER BABASSA VAH LETTER VUBAS" +
"SA VAH LETTER YEINBASSA VAH LETTER PABASSA VAH LETTER WADDABASSA VAH LET" +
"TER ABASSA VAH LETTER OBASSA VAH LETTER OOBASSA VAH LETTER UBASSA VAH LE" +
"TTER EEBASSA VAH LETTER EBASSA VAH LETTER IBASSA VAH COMBINING HIGH TONE" +
"BASSA VAH COMBINING LOW TONEBASSA VAH COMBINING MID TONEBASSA VAH COMBIN" +
"ING LOW-MID TONEBASSA VAH COMBINING HIGH-LOW TONEBASSA VAH FULL STOPPAHA" +
"WH HMONG VOWEL KEEBPAHAWH HMONG VOWEL KEEVPAHAWH HMONG VOWEL KIBPAHAWH H" +
"MONG VOWEL KIVPAHAWH HMONG VOWEL KAUBPAHAWH HMONG VOWEL KAUVPAHAWH HMONG" +
" VOWEL KUBPAHAWH HMONG VOWEL KUVPAHAWH HMONG VOWEL KEBPAHAWH HMONG VOWEL" +
" KEVPAHAWH HMONG VOWEL KAIBPAHAWH HMONG VOWEL KAIVPAHAWH HMONG VOWEL KOO" +
"BPAHAWH HMONG VOWEL KOOVPAHAWH HMONG VOWEL KAWBPAHAWH HMONG VOWEL KAWVPA" +
"HAWH HMONG VOWEL KUABPAHAWH HMONG VOWEL KUAVPAHAWH HMONG VOWEL KOBPAHAWH" +
" HMONG VOWEL KOVPAHAWH HMONG VOWEL KIABPAHAWH HMONG VOWEL KIAVPAHAWH HMO" +
"NG VOWEL KABPAHAWH HMONG VOWEL KAVPAHAWH HMONG VOWEL KWBPAHAWH HMONG VOW" +
"EL KWVPAHAWH HMONG VOWEL KAABPAHAWH HMONG VOWEL KAAVPAHAWH HMONG CONSONA" +
"NT VAUPAHAWH HMONG CONSONANT NTSAUPAHAWH HMONG CONSONANT LAUPAHAWH HMONG" +
" CONSONANT HAUPAHAWH HMONG CONSONANT NLAUPAHAWH HMONG CONSONANT RAUPAHAW" +
"H HMONG CONSONANT NKAUPAHAWH HMONG CONSONANT QHAUPAHAWH HMONG CONSONANT " +
"YAUPAHAWH HMONG CONSONANT HLAUPAHAWH HMONG CONSONANT MAUPAHAWH HMONG CON" +
"SONANT CHAUPAHAWH HMONG CONSONANT NCHAUPAHAWH HMONG CONSONANT HNAUPAHAWH" +
" HMONG CONSONANT PLHAUPAHAWH HMONG CONSONANT NTHAUPAHAWH HMONG CONSONANT" +
" NAUPAHAWH HMONG CONSONANT AUPAHAWH HMONG CONSONANT XAUPAHAWH HMONG CONS" +
"ONANT CAUPAHAWH HMONG MARK CIM TUBPAHAWH HMONG MARK CIM SOPAHAWH HMONG M" +
"ARK CIM KESPAHAWH HMONG MARK CIM KHAVPAHAWH HMONG MARK CIM SUAMPAHAWH HM" +
"ONG MARK CIM HOMPAHAWH HMONG MARK CIM TAUMPAHAWH HMONG SIGN VOS THOMPAHA" +
"WH HMONG SIGN VOS TSHAB CEEBPAHAWH HMONG SIGN CIM CHEEMPAHAWH HMONG SIGN" +
" VOS THIABPAHAWH HMONG SIGN VOS FEEMPAHAWH HMONG SIGN XYEEM NTXIVPAHAWH " +
"HMONG SIGN XYEEM RHOPAHAWH HMONG SIGN XYEEM TOVPAHAWH HMONG SIGN XYEEM F" +
"AIBPAHAWH HMONG SIGN VOS SEEVPAHAWH HMONG SIGN MEEJ SUABPAHAWH HMONG SIG" +
"N VOS NRUAPAHAWH HMONG SIGN IB YAMPAHAWH HMONG SIGN XAUSPAHAWH HMONG SIG" +
"N CIM TSOV ROGPAHAWH HMONG DIGIT ZEROPAHAWH HMONG DIGIT ONEPAHAWH HMONG " +
"DIGIT TWOPAHAWH HMONG DIGIT THREEPAHAWH HMONG DIGIT FOURPAHAWH HMONG DIG" +
"IT 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 MILLIONSPAH" +
"AWH HMONG NUMBER HUNDRED MILLIONSPAHAWH HMONG NUMBER TEN BILLIONSPAHAWH " +
"HMONG NUMBER TRILLIONSPAHAWH HMONG SIGN VOS LUBPAHAWH HMONG SIGN XYOOPAH" +
"AWH HMONG SIGN HLIPAHAWH HMONG SIGN THIRD-STAGE HLIPAHAWH HMONG SIGN ZWJ" +
" THAJPAHAWH HMONG SIGN HNUBPAHAWH HMONG SIGN NQIGPAHAWH HMONG SIGN XIABP" +
"AHAWH HMONG SIGN NTUJPAHAWH HMONG SIGN AVPAHAWH HMONG SIGN TXHEEJ CEEVPA" +
"HAWH HMONG SIGN MEEJ TSEEBPAHAWH HMONG SIGN TAUPAHAWH HMONG SIGN LOSPAHA" +
"WH HMONG SIGN MUSPAHAWH HMONG SIGN CIM HAIS LUS NTOG NTOGPAHAWH HMONG SI" +
"GN CIM CUAM TSHOOJPAHAWH HMONG SIGN CIM TXWVPAHAWH HMONG SIGN CIM TXWV C" +
"HWVPAHAWH HMONG SIGN CIM PUB DAWBPAHAWH HMONG SIGN CIM NRES TOSPAHAWH HM" +
"ONG CLAN SIGN TSHEEJPAHAWH HMONG CLAN SIGN YEEGPAHAWH HMONG CLAN SIGN LI" +
"SPAHAWH HMONG CLAN SIGN LAUJPAHAWH HMONG CLAN SIGN XYOOJPAHAWH HMONG CLA" +
"N SIGN KOOPAHAWH HMONG CLAN SIGN HAWJPAHAWH HMONG CLAN SIGN MUASPAHAWH H" +
"MONG CLAN SIGN THOJPAHAWH HMONG CLAN SIGN TSABPAHAWH HMONG CLAN SIGN PHA" +
"BPAHAWH HMONG CLAN SIGN KHABPAHAWH HMONG CLAN SIGN HAMPAHAWH HMONG CLAN " +
"SIGN VAJPAHAWH HMONG CLAN SIGN FAJPAHAWH HMONG CLAN SIGN YAJPAHAWH HMONG" +
" CLAN SIGN TSWBPAHAWH HMONG CLAN SIGN KWMPAHAWH HMONG CLAN SIGN VWJKIRAT" +
" RAI SIGN ANUSVARAKIRAT RAI SIGN TONPIKIRAT RAI SIGN VISARGAKIRAT RAI LE" +
"TTER AKIRAT RAI LETTER KAKIRAT RAI LETTER KHAKIRAT RAI LETTER GAKIRAT RA" +
"I LETTER GHAKIRAT RAI LETTER NGAKIRAT RAI LETTER CAKIRAT RAI LETTER CHAK" +
"IRAT RAI LETTER JAKIRAT RAI LETTER JHAKIRAT RAI LETTER NYAKIRAT RAI LETT" +
"ER TTAKIRAT RAI LETTER TTHAKIRAT RAI LETTER DDAKIRAT RAI LETTER DDHAKIRA" +
"T RAI LETTER TAKIRAT RAI LETTER THAKIRAT RAI LETTER DAKIRAT RAI LETTER D" +
"HAKIRAT RAI LETTER NAKIRAT RAI LETTER PAKIRAT RAI LETTER PHAKIRAT RAI LE" +
"TTER BAKIRAT RAI LETTER BHAKIRAT RAI LETTER MAKIRAT RAI LETTER YAKIRAT R" +
"AI LETTER RAKIRAT RAI LETTER LAKIRAT RAI LETTER VAKIRAT RAI LETTER SAKIR") + ("" +
"AT RAI LETTER SHAKIRAT RAI LETTER HAKIRAT RAI VOWEL SIGN AAKIRAT RAI VOW" +
"EL SIGN IKIRAT RAI VOWEL SIGN UKIRAT RAI VOWEL SIGN UEKIRAT RAI VOWEL SI" +
"GN EKIRAT RAI VOWEL SIGN AIKIRAT RAI VOWEL SIGN OKIRAT RAI VOWEL SIGN AU" +
"KIRAT RAI SIGN VIRAMAKIRAT RAI SIGN SAATKIRAT RAI SIGN YUPIKIRAT RAI DAN" +
"DAKIRAT RAI DOUBLE DANDAKIRAT RAI DIGIT ZEROKIRAT RAI DIGIT ONEKIRAT RAI" +
" DIGIT TWOKIRAT RAI DIGIT THREEKIRAT RAI DIGIT FOURKIRAT RAI DIGIT FIVEK" +
"IRAT RAI DIGIT SIXKIRAT RAI DIGIT SEVENKIRAT RAI DIGIT EIGHTKIRAT RAI DI" +
"GIT NINEMEDEFAIDRIN CAPITAL LETTER MMEDEFAIDRIN CAPITAL LETTER SMEDEFAID" +
"RIN CAPITAL LETTER VMEDEFAIDRIN CAPITAL LETTER WMEDEFAIDRIN CAPITAL LETT" +
"ER ATIUMEDEFAIDRIN CAPITAL LETTER ZMEDEFAIDRIN CAPITAL LETTER KPMEDEFAID" +
"RIN CAPITAL LETTER PMEDEFAIDRIN CAPITAL LETTER TMEDEFAIDRIN CAPITAL LETT" +
"ER GMEDEFAIDRIN CAPITAL LETTER FMEDEFAIDRIN CAPITAL LETTER IMEDEFAIDRIN " +
"CAPITAL LETTER KMEDEFAIDRIN CAPITAL LETTER AMEDEFAIDRIN CAPITAL LETTER J" +
"MEDEFAIDRIN CAPITAL LETTER EMEDEFAIDRIN CAPITAL LETTER BMEDEFAIDRIN CAPI" +
"TAL LETTER CMEDEFAIDRIN CAPITAL LETTER UMEDEFAIDRIN CAPITAL LETTER YUMED" +
"EFAIDRIN CAPITAL LETTER LMEDEFAIDRIN CAPITAL LETTER QMEDEFAIDRIN CAPITAL" +
" LETTER HPMEDEFAIDRIN CAPITAL LETTER NYMEDEFAIDRIN CAPITAL LETTER XMEDEF" +
"AIDRIN CAPITAL LETTER DMEDEFAIDRIN CAPITAL LETTER OEMEDEFAIDRIN CAPITAL " +
"LETTER NMEDEFAIDRIN CAPITAL LETTER RMEDEFAIDRIN CAPITAL LETTER OMEDEFAID" +
"RIN CAPITAL LETTER AIMEDEFAIDRIN CAPITAL LETTER YMEDEFAIDRIN SMALL LETTE" +
"R MMEDEFAIDRIN SMALL LETTER SMEDEFAIDRIN SMALL LETTER VMEDEFAIDRIN SMALL" +
" LETTER WMEDEFAIDRIN SMALL LETTER ATIUMEDEFAIDRIN SMALL LETTER ZMEDEFAID" +
"RIN SMALL LETTER KPMEDEFAIDRIN SMALL LETTER PMEDEFAIDRIN SMALL LETTER TM" +
"EDEFAIDRIN SMALL LETTER GMEDEFAIDRIN SMALL LETTER FMEDEFAIDRIN SMALL LET" +
"TER IMEDEFAIDRIN SMALL LETTER KMEDEFAIDRIN SMALL LETTER AMEDEFAIDRIN SMA" +
"LL LETTER JMEDEFAIDRIN SMALL LETTER EMEDEFAIDRIN SMALL LETTER BMEDEFAIDR" +
"IN SMALL LETTER CMEDEFAIDRIN SMALL LETTER UMEDEFAIDRIN SMALL LETTER YUME" +
"DEFAIDRIN SMALL LETTER LMEDEFAIDRIN SMALL LETTER QMEDEFAIDRIN SMALL LETT" +
"ER HPMEDEFAIDRIN SMALL LETTER NYMEDEFAIDRIN SMALL LETTER XMEDEFAIDRIN SM" +
"ALL LETTER DMEDEFAIDRIN SMALL LETTER OEMEDEFAIDRIN SMALL LETTER NMEDEFAI" +
"DRIN SMALL LETTER RMEDEFAIDRIN SMALL LETTER OMEDEFAIDRIN SMALL LETTER AI" +
"MEDEFAIDRIN SMALL LETTER YMEDEFAIDRIN DIGIT ZEROMEDEFAIDRIN DIGIT ONEMED" +
"EFAIDRIN DIGIT TWOMEDEFAIDRIN DIGIT THREEMEDEFAIDRIN DIGIT FOURMEDEFAIDR" +
"IN DIGIT FIVEMEDEFAIDRIN DIGIT SIXMEDEFAIDRIN DIGIT SEVENMEDEFAIDRIN DIG" +
"IT EIGHTMEDEFAIDRIN DIGIT NINEMEDEFAIDRIN NUMBER TENMEDEFAIDRIN NUMBER E" +
"LEVENMEDEFAIDRIN NUMBER TWELVEMEDEFAIDRIN NUMBER THIRTEENMEDEFAIDRIN NUM" +
"BER FOURTEENMEDEFAIDRIN NUMBER FIFTEENMEDEFAIDRIN NUMBER SIXTEENMEDEFAID" +
"RIN NUMBER SEVENTEENMEDEFAIDRIN NUMBER EIGHTEENMEDEFAIDRIN NUMBER NINETE" +
"ENMEDEFAIDRIN DIGIT ONE ALTERNATE FORMMEDEFAIDRIN DIGIT TWO ALTERNATE FO" +
"RMMEDEFAIDRIN DIGIT THREE ALTERNATE FORMMEDEFAIDRIN COMMAMEDEFAIDRIN FUL" +
"L STOPMEDEFAIDRIN SYMBOL AIVAMEDEFAIDRIN EXCLAMATION OHBERIA ERFE CAPITA" +
"L LETTER ARKABBERIA ERFE CAPITAL LETTER BASIGNABERIA ERFE CAPITAL LETTER" +
" DARBAIBERIA ERFE CAPITAL LETTER EHBERIA ERFE CAPITAL LETTER FITKOBERIA " +
"ERFE CAPITAL LETTER GOWAYBERIA ERFE CAPITAL LETTER HIRDEABOBERIA ERFE CA" +
"PITAL LETTER IBERIA ERFE CAPITAL LETTER DJAIBERIA ERFE CAPITAL LETTER KO" +
"BOBERIA ERFE CAPITAL LETTER LAKKOBERIA ERFE CAPITAL LETTER MERIBERIA ERF" +
"E CAPITAL LETTER NINIBERIA ERFE CAPITAL LETTER GNABERIA ERFE CAPITAL LET" +
"TER NGAYBERIA ERFE CAPITAL LETTER OIBERIA ERFE CAPITAL LETTER PIBERIA ER" +
"FE CAPITAL LETTER ERIGOBERIA ERFE CAPITAL LETTER ERIGO TAMURABERIA ERFE " +
"CAPITAL LETTER SERIBERIA ERFE CAPITAL LETTER SHEPBERIA ERFE CAPITAL LETT" +
"ER TATASOUEBERIA ERFE CAPITAL LETTER UIBERIA ERFE CAPITAL LETTER WASSEBE" +
"RIA ERFE CAPITAL LETTER AYBERIA ERFE SMALL LETTER ARKABBERIA ERFE SMALL " +
"LETTER BASIGNABERIA ERFE SMALL LETTER DARBAIBERIA ERFE SMALL LETTER EHBE" +
"RIA ERFE SMALL LETTER FITKOBERIA ERFE SMALL LETTER GOWAYBERIA ERFE SMALL" +
" LETTER HIRDEABOBERIA ERFE SMALL LETTER IBERIA ERFE SMALL LETTER DJAIBER" +
"IA ERFE SMALL LETTER KOBOBERIA ERFE SMALL LETTER LAKKOBERIA ERFE SMALL L" +
"ETTER MERIBERIA ERFE SMALL LETTER NINIBERIA ERFE SMALL LETTER GNABERIA E" +
"RFE SMALL LETTER NGAYBERIA ERFE SMALL LETTER OIBERIA ERFE SMALL LETTER P" +
"IBERIA ERFE SMALL LETTER ERIGOBERIA ERFE SMALL LETTER ERIGO TAMURABERIA " +
"ERFE SMALL LETTER SERIBERIA ERFE SMALL LETTER SHEPBERIA ERFE SMALL LETTE" +
"R TATASOUEBERIA ERFE SMALL LETTER UIBERIA ERFE SMALL LETTER WASSEBERIA E" +
"RFE SMALL LETTER AYMIAO LETTER PAMIAO LETTER BAMIAO LETTER YI PAMIAO LET" +
"TER PLAMIAO LETTER MAMIAO LETTER MHAMIAO LETTER ARCHAIC MAMIAO LETTER FA" +
"MIAO LETTER VAMIAO LETTER VFAMIAO LETTER TAMIAO LETTER DAMIAO LETTER YI ") + ("" +
"TTAMIAO LETTER YI TAMIAO LETTER TTAMIAO LETTER DDAMIAO LETTER NAMIAO LET" +
"TER NHAMIAO LETTER YI NNAMIAO LETTER ARCHAIC NAMIAO LETTER NNAMIAO LETTE" +
"R NNHAMIAO LETTER LAMIAO LETTER LYAMIAO LETTER LHAMIAO LETTER LHYAMIAO L" +
"ETTER TLHAMIAO LETTER DLHAMIAO LETTER TLHYAMIAO LETTER DLHYAMIAO LETTER " +
"KAMIAO LETTER GAMIAO LETTER YI KAMIAO LETTER QAMIAO LETTER QGAMIAO LETTE" +
"R NGAMIAO LETTER NGHAMIAO LETTER ARCHAIC NGAMIAO LETTER HAMIAO LETTER XA" +
"MIAO LETTER GHAMIAO LETTER GHHAMIAO LETTER TSSAMIAO LETTER DZZAMIAO LETT" +
"ER NYAMIAO LETTER NYHAMIAO LETTER TSHAMIAO LETTER DZHAMIAO LETTER YI TSH" +
"AMIAO LETTER YI DZHAMIAO LETTER REFORMED TSHAMIAO LETTER SHAMIAO LETTER " +
"SSAMIAO LETTER ZHAMIAO LETTER ZSHAMIAO LETTER TSAMIAO LETTER DZAMIAO LET" +
"TER YI TSAMIAO LETTER SAMIAO LETTER ZAMIAO LETTER ZSAMIAO LETTER ZZAMIAO" +
" LETTER ZZSAMIAO LETTER ARCHAIC ZZAMIAO LETTER ZZYAMIAO LETTER ZZSYAMIAO" +
" LETTER WAMIAO LETTER AHMIAO LETTER HHAMIAO LETTER BRIMIAO LETTER SYIMIA" +
"O LETTER DZYIMIAO LETTER TEMIAO LETTER TSEMIAO LETTER RTEMIAO SIGN CONSO" +
"NANT MODIFIER BARMIAO LETTER NASALIZATIONMIAO SIGN ASPIRATIONMIAO SIGN R" +
"EFORMED VOICINGMIAO SIGN REFORMED ASPIRATIONMIAO VOWEL SIGN AMIAO VOWEL " +
"SIGN AAMIAO VOWEL SIGN AHHMIAO VOWEL SIGN ANMIAO VOWEL SIGN ANGMIAO VOWE" +
"L 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 VOW" +
"EL SIGN IOMIAO VOWEL SIGN IEMIAO VOWEL SIGN IIMIAO VOWEL SIGN IUMIAO VOW" +
"EL SIGN INGMIAO VOWEL SIGN UMIAO VOWEL SIGN UAMIAO VOWEL SIGN UANMIAO VO" +
"WEL SIGN UANGMIAO VOWEL SIGN UUMIAO VOWEL SIGN UEIMIAO VOWEL SIGN UNGMIA" +
"O VOWEL SIGN YMIAO VOWEL SIGN YIMIAO VOWEL SIGN AEMIAO VOWEL SIGN AEEMIA" +
"O VOWEL SIGN ERRMIAO VOWEL SIGN ROUNDED ERRMIAO VOWEL SIGN ERMIAO VOWEL " +
"SIGN ROUNDED ERMIAO VOWEL SIGN AIMIAO VOWEL SIGN EIMIAO VOWEL SIGN AUMIA" +
"O VOWEL SIGN OUMIAO VOWEL SIGN NMIAO VOWEL SIGN NGMIAO VOWEL SIGN UOGMIA" +
"O VOWEL SIGN YUIMIAO VOWEL SIGN OGMIAO VOWEL SIGN OERMIAO VOWEL SIGN VWM" +
"IAO VOWEL SIGN IGMIAO VOWEL SIGN EAMIAO VOWEL SIGN IONGMIAO VOWEL SIGN U" +
"IMIAO TONE RIGHTMIAO TONE TOP RIGHTMIAO TONE ABOVEMIAO TONE BELOWMIAO LE" +
"TTER TONE-2MIAO LETTER TONE-3MIAO LETTER TONE-4MIAO LETTER TONE-5MIAO LE" +
"TTER TONE-6MIAO LETTER TONE-7MIAO LETTER TONE-8MIAO LETTER REFORMED TONE" +
"-1MIAO LETTER REFORMED TONE-2MIAO LETTER REFORMED TONE-4MIAO LETTER REFO" +
"RMED TONE-5MIAO LETTER REFORMED TONE-6MIAO LETTER REFORMED TONE-8TANGUT " +
"ITERATION MARKNUSHU ITERATION MARKOLD CHINESE HOOK MARKOLD CHINESE ITERA" +
"TION MARKKHITAN SMALL SCRIPT FILLERVIETNAMESE ALTERNATE READING MARK CAV" +
"IETNAMESE ALTERNATE READING MARK NHAYCHINESE SMALL SIMPLIFIED ERCHINESE " +
"SMALL TRADITIONAL ERYANGQIN SIGN SLOW ONE BEATYANGQIN SIGN SLOW THREE HA" +
"LF BEATSYANGQIN SIGN SLOW TWO BEATSTANGUT COMPONENT-001TANGUT COMPONENT-" +
"002TANGUT COMPONENT-003TANGUT COMPONENT-004TANGUT COMPONENT-005TANGUT CO" +
"MPONENT-006TANGUT COMPONENT-007TANGUT COMPONENT-008TANGUT COMPONENT-009T" +
"ANGUT COMPONENT-010TANGUT COMPONENT-011TANGUT COMPONENT-012TANGUT COMPON" +
"ENT-013TANGUT COMPONENT-014TANGUT COMPONENT-015TANGUT COMPONENT-016TANGU" +
"T COMPONENT-017TANGUT COMPONENT-018TANGUT COMPONENT-019TANGUT COMPONENT-" +
"020TANGUT COMPONENT-021TANGUT COMPONENT-022TANGUT COMPONENT-023TANGUT CO" +
"MPONENT-024TANGUT COMPONENT-025TANGUT COMPONENT-026TANGUT COMPONENT-027T" +
"ANGUT COMPONENT-028TANGUT COMPONENT-029TANGUT COMPONENT-030TANGUT COMPON" +
"ENT-031TANGUT COMPONENT-032TANGUT COMPONENT-033TANGUT COMPONENT-034TANGU" +
"T COMPONENT-035TANGUT COMPONENT-036TANGUT COMPONENT-037TANGUT COMPONENT-" +
"038TANGUT COMPONENT-039TANGUT COMPONENT-040TANGUT COMPONENT-041TANGUT CO" +
"MPONENT-042TANGUT COMPONENT-043TANGUT COMPONENT-044TANGUT COMPONENT-045T" +
"ANGUT COMPONENT-046TANGUT COMPONENT-047TANGUT COMPONENT-048TANGUT COMPON" +
"ENT-049TANGUT COMPONENT-050TANGUT COMPONENT-051TANGUT COMPONENT-052TANGU" +
"T COMPONENT-053TANGUT COMPONENT-054TANGUT COMPONENT-055TANGUT COMPONENT-" +
"056TANGUT COMPONENT-057TANGUT COMPONENT-058TANGUT COMPONENT-059TANGUT CO" +
"MPONENT-060TANGUT COMPONENT-061TANGUT COMPONENT-062TANGUT COMPONENT-063T" +
"ANGUT COMPONENT-064TANGUT COMPONENT-065TANGUT COMPONENT-066TANGUT COMPON" +
"ENT-067TANGUT COMPONENT-068TANGUT COMPONENT-069TANGUT COMPONENT-070TANGU" +
"T COMPONENT-071TANGUT COMPONENT-072TANGUT COMPONENT-073TANGUT COMPONENT-" +
"074TANGUT COMPONENT-075TANGUT COMPONENT-076TANGUT COMPONENT-077TANGUT CO" +
"MPONENT-078TANGUT COMPONENT-079TANGUT COMPONENT-080TANGUT COMPONENT-081T" +
"ANGUT COMPONENT-082TANGUT COMPONENT-083TANGUT COMPONENT-084TANGUT COMPON" +
"ENT-085TANGUT COMPONENT-086TANGUT COMPONENT-087TANGUT COMPONENT-088TANGU" +
"T COMPONENT-089TANGUT COMPONENT-090TANGUT COMPONENT-091TANGUT COMPONENT-") + ("" +
"092TANGUT COMPONENT-093TANGUT COMPONENT-094TANGUT COMPONENT-095TANGUT CO" +
"MPONENT-096TANGUT COMPONENT-097TANGUT COMPONENT-098TANGUT COMPONENT-099T" +
"ANGUT COMPONENT-100TANGUT COMPONENT-101TANGUT COMPONENT-102TANGUT COMPON" +
"ENT-103TANGUT COMPONENT-104TANGUT COMPONENT-105TANGUT COMPONENT-106TANGU" +
"T COMPONENT-107TANGUT COMPONENT-108TANGUT COMPONENT-109TANGUT COMPONENT-" +
"110TANGUT COMPONENT-111TANGUT COMPONENT-112TANGUT COMPONENT-113TANGUT CO" +
"MPONENT-114TANGUT COMPONENT-115TANGUT COMPONENT-116TANGUT COMPONENT-117T" +
"ANGUT COMPONENT-118TANGUT COMPONENT-119TANGUT COMPONENT-120TANGUT COMPON" +
"ENT-121TANGUT COMPONENT-122TANGUT COMPONENT-123TANGUT COMPONENT-124TANGU" +
"T COMPONENT-125TANGUT COMPONENT-126TANGUT COMPONENT-127TANGUT COMPONENT-" +
"128TANGUT COMPONENT-129TANGUT COMPONENT-130TANGUT COMPONENT-131TANGUT CO" +
"MPONENT-132TANGUT COMPONENT-133TANGUT COMPONENT-134TANGUT COMPONENT-135T" +
"ANGUT COMPONENT-136TANGUT COMPONENT-137TANGUT COMPONENT-138TANGUT COMPON" +
"ENT-139TANGUT COMPONENT-140TANGUT COMPONENT-141TANGUT COMPONENT-142TANGU" +
"T COMPONENT-143TANGUT COMPONENT-144TANGUT COMPONENT-145TANGUT COMPONENT-" +
"146TANGUT COMPONENT-147TANGUT COMPONENT-148TANGUT COMPONENT-149TANGUT CO" +
"MPONENT-150TANGUT COMPONENT-151TANGUT COMPONENT-152TANGUT COMPONENT-153T" +
"ANGUT COMPONENT-154TANGUT COMPONENT-155TANGUT COMPONENT-156TANGUT COMPON" +
"ENT-157TANGUT COMPONENT-158TANGUT COMPONENT-159TANGUT COMPONENT-160TANGU" +
"T COMPONENT-161TANGUT COMPONENT-162TANGUT COMPONENT-163TANGUT COMPONENT-" +
"164TANGUT COMPONENT-165TANGUT COMPONENT-166TANGUT COMPONENT-167TANGUT CO" +
"MPONENT-168TANGUT COMPONENT-169TANGUT COMPONENT-170TANGUT COMPONENT-171T" +
"ANGUT COMPONENT-172TANGUT COMPONENT-173TANGUT COMPONENT-174TANGUT COMPON" +
"ENT-175TANGUT COMPONENT-176TANGUT COMPONENT-177TANGUT COMPONENT-178TANGU" +
"T COMPONENT-179TANGUT COMPONENT-180TANGUT COMPONENT-181TANGUT COMPONENT-" +
"182TANGUT COMPONENT-183TANGUT COMPONENT-184TANGUT COMPONENT-185TANGUT CO" +
"MPONENT-186TANGUT COMPONENT-187TANGUT COMPONENT-188TANGUT COMPONENT-189T" +
"ANGUT COMPONENT-190TANGUT COMPONENT-191TANGUT COMPONENT-192TANGUT COMPON" +
"ENT-193TANGUT COMPONENT-194TANGUT COMPONENT-195TANGUT COMPONENT-196TANGU" +
"T COMPONENT-197TANGUT COMPONENT-198TANGUT COMPONENT-199TANGUT COMPONENT-" +
"200TANGUT COMPONENT-201TANGUT COMPONENT-202TANGUT COMPONENT-203TANGUT CO" +
"MPONENT-204TANGUT COMPONENT-205TANGUT COMPONENT-206TANGUT COMPONENT-207T" +
"ANGUT COMPONENT-208TANGUT COMPONENT-209TANGUT COMPONENT-210TANGUT COMPON" +
"ENT-211TANGUT COMPONENT-212TANGUT COMPONENT-213TANGUT COMPONENT-214TANGU" +
"T COMPONENT-215TANGUT COMPONENT-216TANGUT COMPONENT-217TANGUT COMPONENT-" +
"218TANGUT COMPONENT-219TANGUT COMPONENT-220TANGUT COMPONENT-221TANGUT CO" +
"MPONENT-222TANGUT COMPONENT-223TANGUT COMPONENT-224TANGUT COMPONENT-225T" +
"ANGUT COMPONENT-226TANGUT COMPONENT-227TANGUT COMPONENT-228TANGUT COMPON" +
"ENT-229TANGUT COMPONENT-230TANGUT COMPONENT-231TANGUT COMPONENT-232TANGU" +
"T COMPONENT-233TANGUT COMPONENT-234TANGUT COMPONENT-235TANGUT COMPONENT-" +
"236TANGUT COMPONENT-237TANGUT COMPONENT-238TANGUT COMPONENT-239TANGUT CO" +
"MPONENT-240TANGUT COMPONENT-241TANGUT COMPONENT-242TANGUT COMPONENT-243T" +
"ANGUT COMPONENT-244TANGUT COMPONENT-245TANGUT COMPONENT-246TANGUT COMPON" +
"ENT-247TANGUT COMPONENT-248TANGUT COMPONENT-249TANGUT COMPONENT-250TANGU" +
"T COMPONENT-251TANGUT COMPONENT-252TANGUT COMPONENT-253TANGUT COMPONENT-" +
"254TANGUT COMPONENT-255TANGUT COMPONENT-256TANGUT COMPONENT-257TANGUT CO" +
"MPONENT-258TANGUT COMPONENT-259TANGUT COMPONENT-260TANGUT COMPONENT-261T" +
"ANGUT COMPONENT-262TANGUT COMPONENT-263TANGUT COMPONENT-264TANGUT COMPON" +
"ENT-265TANGUT COMPONENT-266TANGUT COMPONENT-267TANGUT COMPONENT-268TANGU" +
"T COMPONENT-269TANGUT COMPONENT-270TANGUT COMPONENT-271TANGUT COMPONENT-" +
"272TANGUT COMPONENT-273TANGUT COMPONENT-274TANGUT COMPONENT-275TANGUT CO" +
"MPONENT-276TANGUT COMPONENT-277TANGUT COMPONENT-278TANGUT COMPONENT-279T" +
"ANGUT COMPONENT-280TANGUT COMPONENT-281TANGUT COMPONENT-282TANGUT COMPON" +
"ENT-283TANGUT COMPONENT-284TANGUT COMPONENT-285TANGUT COMPONENT-286TANGU" +
"T COMPONENT-287TANGUT COMPONENT-288TANGUT COMPONENT-289TANGUT COMPONENT-" +
"290TANGUT COMPONENT-291TANGUT COMPONENT-292TANGUT COMPONENT-293TANGUT CO" +
"MPONENT-294TANGUT COMPONENT-295TANGUT COMPONENT-296TANGUT COMPONENT-297T" +
"ANGUT COMPONENT-298TANGUT COMPONENT-299TANGUT COMPONENT-300TANGUT COMPON" +
"ENT-301TANGUT COMPONENT-302TANGUT COMPONENT-303TANGUT COMPONENT-304TANGU" +
"T COMPONENT-305TANGUT COMPONENT-306TANGUT COMPONENT-307TANGUT COMPONENT-" +
"308TANGUT COMPONENT-309TANGUT COMPONENT-310TANGUT COMPONENT-311TANGUT CO" +
"MPONENT-312TANGUT COMPONENT-313TANGUT COMPONENT-314TANGUT COMPONENT-315T" +
"ANGUT COMPONENT-316TANGUT COMPONENT-317TANGUT COMPONENT-318TANGUT COMPON" +
"ENT-319TANGUT COMPONENT-320TANGUT COMPONENT-321TANGUT COMPONENT-322TANGU") + ("" +
"T COMPONENT-323TANGUT COMPONENT-324TANGUT COMPONENT-325TANGUT COMPONENT-" +
"326TANGUT COMPONENT-327TANGUT COMPONENT-328TANGUT COMPONENT-329TANGUT CO" +
"MPONENT-330TANGUT COMPONENT-331TANGUT COMPONENT-332TANGUT COMPONENT-333T" +
"ANGUT COMPONENT-334TANGUT COMPONENT-335TANGUT COMPONENT-336TANGUT COMPON" +
"ENT-337TANGUT COMPONENT-338TANGUT COMPONENT-339TANGUT COMPONENT-340TANGU" +
"T COMPONENT-341TANGUT COMPONENT-342TANGUT COMPONENT-343TANGUT COMPONENT-" +
"344TANGUT COMPONENT-345TANGUT COMPONENT-346TANGUT COMPONENT-347TANGUT CO" +
"MPONENT-348TANGUT COMPONENT-349TANGUT COMPONENT-350TANGUT COMPONENT-351T" +
"ANGUT COMPONENT-352TANGUT COMPONENT-353TANGUT COMPONENT-354TANGUT COMPON" +
"ENT-355TANGUT COMPONENT-356TANGUT COMPONENT-357TANGUT COMPONENT-358TANGU" +
"T COMPONENT-359TANGUT COMPONENT-360TANGUT COMPONENT-361TANGUT COMPONENT-" +
"362TANGUT COMPONENT-363TANGUT COMPONENT-364TANGUT COMPONENT-365TANGUT CO" +
"MPONENT-366TANGUT COMPONENT-367TANGUT COMPONENT-368TANGUT COMPONENT-369T" +
"ANGUT COMPONENT-370TANGUT COMPONENT-371TANGUT COMPONENT-372TANGUT COMPON" +
"ENT-373TANGUT COMPONENT-374TANGUT COMPONENT-375TANGUT COMPONENT-376TANGU" +
"T COMPONENT-377TANGUT COMPONENT-378TANGUT COMPONENT-379TANGUT COMPONENT-" +
"380TANGUT COMPONENT-381TANGUT COMPONENT-382TANGUT COMPONENT-383TANGUT CO" +
"MPONENT-384TANGUT COMPONENT-385TANGUT COMPONENT-386TANGUT COMPONENT-387T" +
"ANGUT COMPONENT-388TANGUT COMPONENT-389TANGUT COMPONENT-390TANGUT COMPON" +
"ENT-391TANGUT COMPONENT-392TANGUT COMPONENT-393TANGUT COMPONENT-394TANGU" +
"T COMPONENT-395TANGUT COMPONENT-396TANGUT COMPONENT-397TANGUT COMPONENT-" +
"398TANGUT COMPONENT-399TANGUT COMPONENT-400TANGUT COMPONENT-401TANGUT CO" +
"MPONENT-402TANGUT COMPONENT-403TANGUT COMPONENT-404TANGUT COMPONENT-405T" +
"ANGUT COMPONENT-406TANGUT COMPONENT-407TANGUT COMPONENT-408TANGUT COMPON" +
"ENT-409TANGUT COMPONENT-410TANGUT COMPONENT-411TANGUT COMPONENT-412TANGU" +
"T COMPONENT-413TANGUT COMPONENT-414TANGUT COMPONENT-415TANGUT COMPONENT-" +
"416TANGUT COMPONENT-417TANGUT COMPONENT-418TANGUT COMPONENT-419TANGUT CO" +
"MPONENT-420TANGUT COMPONENT-421TANGUT COMPONENT-422TANGUT COMPONENT-423T" +
"ANGUT COMPONENT-424TANGUT COMPONENT-425TANGUT COMPONENT-426TANGUT COMPON" +
"ENT-427TANGUT COMPONENT-428TANGUT COMPONENT-429TANGUT COMPONENT-430TANGU" +
"T COMPONENT-431TANGUT COMPONENT-432TANGUT COMPONENT-433TANGUT COMPONENT-" +
"434TANGUT COMPONENT-435TANGUT COMPONENT-436TANGUT COMPONENT-437TANGUT CO" +
"MPONENT-438TANGUT COMPONENT-439TANGUT COMPONENT-440TANGUT COMPONENT-441T" +
"ANGUT COMPONENT-442TANGUT COMPONENT-443TANGUT COMPONENT-444TANGUT COMPON" +
"ENT-445TANGUT COMPONENT-446TANGUT COMPONENT-447TANGUT COMPONENT-448TANGU" +
"T COMPONENT-449TANGUT COMPONENT-450TANGUT COMPONENT-451TANGUT COMPONENT-" +
"452TANGUT COMPONENT-453TANGUT COMPONENT-454TANGUT COMPONENT-455TANGUT CO" +
"MPONENT-456TANGUT COMPONENT-457TANGUT COMPONENT-458TANGUT COMPONENT-459T" +
"ANGUT COMPONENT-460TANGUT COMPONENT-461TANGUT COMPONENT-462TANGUT COMPON" +
"ENT-463TANGUT COMPONENT-464TANGUT COMPONENT-465TANGUT COMPONENT-466TANGU" +
"T COMPONENT-467TANGUT COMPONENT-468TANGUT COMPONENT-469TANGUT COMPONENT-" +
"470TANGUT COMPONENT-471TANGUT COMPONENT-472TANGUT COMPONENT-473TANGUT CO" +
"MPONENT-474TANGUT COMPONENT-475TANGUT COMPONENT-476TANGUT COMPONENT-477T" +
"ANGUT COMPONENT-478TANGUT COMPONENT-479TANGUT COMPONENT-480TANGUT COMPON" +
"ENT-481TANGUT COMPONENT-482TANGUT COMPONENT-483TANGUT COMPONENT-484TANGU" +
"T COMPONENT-485TANGUT COMPONENT-486TANGUT COMPONENT-487TANGUT COMPONENT-" +
"488TANGUT COMPONENT-489TANGUT COMPONENT-490TANGUT COMPONENT-491TANGUT CO" +
"MPONENT-492TANGUT COMPONENT-493TANGUT COMPONENT-494TANGUT COMPONENT-495T" +
"ANGUT COMPONENT-496TANGUT COMPONENT-497TANGUT COMPONENT-498TANGUT COMPON" +
"ENT-499TANGUT COMPONENT-500TANGUT COMPONENT-501TANGUT COMPONENT-502TANGU" +
"T COMPONENT-503TANGUT COMPONENT-504TANGUT COMPONENT-505TANGUT COMPONENT-" +
"506TANGUT COMPONENT-507TANGUT COMPONENT-508TANGUT COMPONENT-509TANGUT CO" +
"MPONENT-510TANGUT COMPONENT-511TANGUT COMPONENT-512TANGUT COMPONENT-513T" +
"ANGUT COMPONENT-514TANGUT COMPONENT-515TANGUT COMPONENT-516TANGUT COMPON" +
"ENT-517TANGUT COMPONENT-518TANGUT COMPONENT-519TANGUT COMPONENT-520TANGU" +
"T COMPONENT-521TANGUT COMPONENT-522TANGUT COMPONENT-523TANGUT COMPONENT-" +
"524TANGUT COMPONENT-525TANGUT COMPONENT-526TANGUT COMPONENT-527TANGUT CO" +
"MPONENT-528TANGUT COMPONENT-529TANGUT COMPONENT-530TANGUT COMPONENT-531T" +
"ANGUT COMPONENT-532TANGUT COMPONENT-533TANGUT COMPONENT-534TANGUT COMPON" +
"ENT-535TANGUT COMPONENT-536TANGUT COMPONENT-537TANGUT COMPONENT-538TANGU" +
"T COMPONENT-539TANGUT COMPONENT-540TANGUT COMPONENT-541TANGUT COMPONENT-" +
"542TANGUT COMPONENT-543TANGUT COMPONENT-544TANGUT COMPONENT-545TANGUT CO" +
"MPONENT-546TANGUT COMPONENT-547TANGUT COMPONENT-548TANGUT COMPONENT-549T" +
"ANGUT COMPONENT-550TANGUT COMPONENT-551TANGUT COMPONENT-552TANGUT COMPON") + ("" +
"ENT-553TANGUT COMPONENT-554TANGUT COMPONENT-555TANGUT COMPONENT-556TANGU" +
"T COMPONENT-557TANGUT COMPONENT-558TANGUT COMPONENT-559TANGUT COMPONENT-" +
"560TANGUT COMPONENT-561TANGUT COMPONENT-562TANGUT COMPONENT-563TANGUT CO" +
"MPONENT-564TANGUT COMPONENT-565TANGUT COMPONENT-566TANGUT COMPONENT-567T" +
"ANGUT COMPONENT-568TANGUT COMPONENT-569TANGUT COMPONENT-570TANGUT COMPON" +
"ENT-571TANGUT COMPONENT-572TANGUT COMPONENT-573TANGUT COMPONENT-574TANGU" +
"T COMPONENT-575TANGUT COMPONENT-576TANGUT COMPONENT-577TANGUT COMPONENT-" +
"578TANGUT COMPONENT-579TANGUT COMPONENT-580TANGUT COMPONENT-581TANGUT CO" +
"MPONENT-582TANGUT COMPONENT-583TANGUT COMPONENT-584TANGUT COMPONENT-585T" +
"ANGUT COMPONENT-586TANGUT COMPONENT-587TANGUT COMPONENT-588TANGUT COMPON" +
"ENT-589TANGUT COMPONENT-590TANGUT COMPONENT-591TANGUT COMPONENT-592TANGU" +
"T COMPONENT-593TANGUT COMPONENT-594TANGUT COMPONENT-595TANGUT COMPONENT-" +
"596TANGUT COMPONENT-597TANGUT COMPONENT-598TANGUT COMPONENT-599TANGUT CO" +
"MPONENT-600TANGUT COMPONENT-601TANGUT COMPONENT-602TANGUT COMPONENT-603T" +
"ANGUT COMPONENT-604TANGUT COMPONENT-605TANGUT COMPONENT-606TANGUT COMPON" +
"ENT-607TANGUT COMPONENT-608TANGUT COMPONENT-609TANGUT COMPONENT-610TANGU" +
"T COMPONENT-611TANGUT COMPONENT-612TANGUT COMPONENT-613TANGUT COMPONENT-" +
"614TANGUT COMPONENT-615TANGUT COMPONENT-616TANGUT COMPONENT-617TANGUT CO" +
"MPONENT-618TANGUT COMPONENT-619TANGUT COMPONENT-620TANGUT COMPONENT-621T" +
"ANGUT COMPONENT-622TANGUT COMPONENT-623TANGUT COMPONENT-624TANGUT COMPON" +
"ENT-625TANGUT COMPONENT-626TANGUT COMPONENT-627TANGUT COMPONENT-628TANGU" +
"T COMPONENT-629TANGUT COMPONENT-630TANGUT COMPONENT-631TANGUT COMPONENT-" +
"632TANGUT COMPONENT-633TANGUT COMPONENT-634TANGUT COMPONENT-635TANGUT CO" +
"MPONENT-636TANGUT COMPONENT-637TANGUT COMPONENT-638TANGUT COMPONENT-639T" +
"ANGUT COMPONENT-640TANGUT COMPONENT-641TANGUT COMPONENT-642TANGUT COMPON" +
"ENT-643TANGUT COMPONENT-644TANGUT COMPONENT-645TANGUT COMPONENT-646TANGU" +
"T COMPONENT-647TANGUT COMPONENT-648TANGUT COMPONENT-649TANGUT COMPONENT-" +
"650TANGUT COMPONENT-651TANGUT COMPONENT-652TANGUT COMPONENT-653TANGUT CO" +
"MPONENT-654TANGUT COMPONENT-655TANGUT COMPONENT-656TANGUT COMPONENT-657T" +
"ANGUT COMPONENT-658TANGUT COMPONENT-659TANGUT COMPONENT-660TANGUT COMPON" +
"ENT-661TANGUT COMPONENT-662TANGUT COMPONENT-663TANGUT COMPONENT-664TANGU" +
"T COMPONENT-665TANGUT COMPONENT-666TANGUT COMPONENT-667TANGUT COMPONENT-" +
"668TANGUT COMPONENT-669TANGUT COMPONENT-670TANGUT COMPONENT-671TANGUT CO" +
"MPONENT-672TANGUT COMPONENT-673TANGUT COMPONENT-674TANGUT COMPONENT-675T" +
"ANGUT COMPONENT-676TANGUT COMPONENT-677TANGUT COMPONENT-678TANGUT COMPON" +
"ENT-679TANGUT COMPONENT-680TANGUT COMPONENT-681TANGUT COMPONENT-682TANGU" +
"T COMPONENT-683TANGUT COMPONENT-684TANGUT COMPONENT-685TANGUT COMPONENT-" +
"686TANGUT COMPONENT-687TANGUT COMPONENT-688TANGUT COMPONENT-689TANGUT CO" +
"MPONENT-690TANGUT COMPONENT-691TANGUT COMPONENT-692TANGUT COMPONENT-693T" +
"ANGUT COMPONENT-694TANGUT COMPONENT-695TANGUT COMPONENT-696TANGUT COMPON" +
"ENT-697TANGUT COMPONENT-698TANGUT COMPONENT-699TANGUT COMPONENT-700TANGU" +
"T COMPONENT-701TANGUT COMPONENT-702TANGUT COMPONENT-703TANGUT COMPONENT-" +
"704TANGUT COMPONENT-705TANGUT COMPONENT-706TANGUT COMPONENT-707TANGUT CO" +
"MPONENT-708TANGUT COMPONENT-709TANGUT COMPONENT-710TANGUT COMPONENT-711T" +
"ANGUT COMPONENT-712TANGUT COMPONENT-713TANGUT COMPONENT-714TANGUT COMPON" +
"ENT-715TANGUT COMPONENT-716TANGUT COMPONENT-717TANGUT COMPONENT-718TANGU" +
"T COMPONENT-719TANGUT COMPONENT-720TANGUT COMPONENT-721TANGUT COMPONENT-" +
"722TANGUT COMPONENT-723TANGUT COMPONENT-724TANGUT COMPONENT-725TANGUT CO" +
"MPONENT-726TANGUT COMPONENT-727TANGUT COMPONENT-728TANGUT COMPONENT-729T" +
"ANGUT COMPONENT-730TANGUT COMPONENT-731TANGUT COMPONENT-732TANGUT COMPON" +
"ENT-733TANGUT COMPONENT-734TANGUT COMPONENT-735TANGUT COMPONENT-736TANGU" +
"T COMPONENT-737TANGUT COMPONENT-738TANGUT COMPONENT-739TANGUT COMPONENT-" +
"740TANGUT COMPONENT-741TANGUT COMPONENT-742TANGUT COMPONENT-743TANGUT CO" +
"MPONENT-744TANGUT COMPONENT-745TANGUT COMPONENT-746TANGUT COMPONENT-747T" +
"ANGUT COMPONENT-748TANGUT COMPONENT-749TANGUT COMPONENT-750TANGUT COMPON" +
"ENT-751TANGUT COMPONENT-752TANGUT COMPONENT-753TANGUT COMPONENT-754TANGU" +
"T COMPONENT-755TANGUT COMPONENT-756TANGUT COMPONENT-757TANGUT COMPONENT-" +
"758TANGUT COMPONENT-759TANGUT COMPONENT-760TANGUT COMPONENT-761TANGUT CO" +
"MPONENT-762TANGUT COMPONENT-763TANGUT COMPONENT-764TANGUT COMPONENT-765T" +
"ANGUT COMPONENT-766TANGUT COMPONENT-767TANGUT COMPONENT-768KHITAN SMALL " +
"SCRIPT CHARACTER-18B00KHITAN SMALL SCRIPT CHARACTER-18B01KHITAN SMALL SC" +
"RIPT CHARACTER-18B02KHITAN SMALL SCRIPT CHARACTER-18B03KHITAN SMALL SCRI" +
"PT CHARACTER-18B04KHITAN SMALL SCRIPT CHARACTER-18B05KHITAN SMALL SCRIPT" +
" CHARACTER-18B06KHITAN SMALL SCRIPT CHARACTER-18B07KHITAN SMALL SCRIPT C") + ("" +
"HARACTER-18B08KHITAN SMALL SCRIPT CHARACTER-18B09KHITAN SMALL SCRIPT CHA" +
"RACTER-18B0AKHITAN SMALL SCRIPT CHARACTER-18B0BKHITAN SMALL SCRIPT CHARA" +
"CTER-18B0CKHITAN SMALL SCRIPT CHARACTER-18B0DKHITAN SMALL SCRIPT CHARACT" +
"ER-18B0EKHITAN SMALL SCRIPT CHARACTER-18B0FKHITAN SMALL SCRIPT CHARACTER" +
"-18B10KHITAN SMALL SCRIPT CHARACTER-18B11KHITAN SMALL SCRIPT CHARACTER-1" +
"8B12KHITAN SMALL SCRIPT CHARACTER-18B13KHITAN SMALL SCRIPT CHARACTER-18B" +
"14KHITAN SMALL SCRIPT CHARACTER-18B15KHITAN SMALL SCRIPT CHARACTER-18B16" +
"KHITAN SMALL SCRIPT CHARACTER-18B17KHITAN SMALL SCRIPT CHARACTER-18B18KH" +
"ITAN SMALL SCRIPT CHARACTER-18B19KHITAN SMALL SCRIPT CHARACTER-18B1AKHIT" +
"AN SMALL SCRIPT CHARACTER-18B1BKHITAN SMALL SCRIPT CHARACTER-18B1CKHITAN" +
" SMALL SCRIPT CHARACTER-18B1DKHITAN SMALL SCRIPT CHARACTER-18B1EKHITAN S" +
"MALL SCRIPT CHARACTER-18B1FKHITAN SMALL SCRIPT CHARACTER-18B20KHITAN SMA" +
"LL SCRIPT CHARACTER-18B21KHITAN SMALL SCRIPT CHARACTER-18B22KHITAN SMALL" +
" SCRIPT CHARACTER-18B23KHITAN SMALL SCRIPT CHARACTER-18B24KHITAN SMALL S" +
"CRIPT CHARACTER-18B25KHITAN SMALL SCRIPT CHARACTER-18B26KHITAN SMALL SCR" +
"IPT CHARACTER-18B27KHITAN SMALL SCRIPT CHARACTER-18B28KHITAN SMALL SCRIP" +
"T CHARACTER-18B29KHITAN SMALL SCRIPT CHARACTER-18B2AKHITAN SMALL SCRIPT " +
"CHARACTER-18B2BKHITAN SMALL SCRIPT CHARACTER-18B2CKHITAN SMALL SCRIPT CH" +
"ARACTER-18B2DKHITAN SMALL SCRIPT CHARACTER-18B2EKHITAN SMALL SCRIPT CHAR" +
"ACTER-18B2FKHITAN SMALL SCRIPT CHARACTER-18B30KHITAN SMALL SCRIPT CHARAC" +
"TER-18B31KHITAN SMALL SCRIPT CHARACTER-18B32KHITAN SMALL SCRIPT CHARACTE" +
"R-18B33KHITAN SMALL SCRIPT CHARACTER-18B34KHITAN SMALL SCRIPT CHARACTER-" +
"18B35KHITAN SMALL SCRIPT CHARACTER-18B36KHITAN SMALL SCRIPT CHARACTER-18" +
"B37KHITAN SMALL SCRIPT CHARACTER-18B38KHITAN SMALL SCRIPT CHARACTER-18B3" +
"9KHITAN SMALL SCRIPT CHARACTER-18B3AKHITAN SMALL SCRIPT CHARACTER-18B3BK" +
"HITAN SMALL SCRIPT CHARACTER-18B3CKHITAN SMALL SCRIPT CHARACTER-18B3DKHI" +
"TAN SMALL SCRIPT CHARACTER-18B3EKHITAN SMALL SCRIPT CHARACTER-18B3FKHITA" +
"N SMALL SCRIPT CHARACTER-18B40KHITAN SMALL SCRIPT CHARACTER-18B41KHITAN " +
"SMALL SCRIPT CHARACTER-18B42KHITAN SMALL SCRIPT CHARACTER-18B43KHITAN SM" +
"ALL SCRIPT CHARACTER-18B44KHITAN SMALL SCRIPT CHARACTER-18B45KHITAN SMAL" +
"L SCRIPT CHARACTER-18B46KHITAN SMALL SCRIPT CHARACTER-18B47KHITAN SMALL " +
"SCRIPT CHARACTER-18B48KHITAN SMALL SCRIPT CHARACTER-18B49KHITAN SMALL SC" +
"RIPT CHARACTER-18B4AKHITAN SMALL SCRIPT CHARACTER-18B4BKHITAN SMALL SCRI" +
"PT CHARACTER-18B4CKHITAN SMALL SCRIPT CHARACTER-18B4DKHITAN SMALL SCRIPT" +
" CHARACTER-18B4EKHITAN SMALL SCRIPT CHARACTER-18B4FKHITAN SMALL SCRIPT C" +
"HARACTER-18B50KHITAN SMALL SCRIPT CHARACTER-18B51KHITAN SMALL SCRIPT CHA" +
"RACTER-18B52KHITAN SMALL SCRIPT CHARACTER-18B53KHITAN SMALL SCRIPT CHARA" +
"CTER-18B54KHITAN SMALL SCRIPT CHARACTER-18B55KHITAN SMALL SCRIPT CHARACT" +
"ER-18B56KHITAN SMALL SCRIPT CHARACTER-18B57KHITAN SMALL SCRIPT CHARACTER" +
"-18B58KHITAN SMALL SCRIPT CHARACTER-18B59KHITAN SMALL SCRIPT CHARACTER-1" +
"8B5AKHITAN SMALL SCRIPT CHARACTER-18B5BKHITAN SMALL SCRIPT CHARACTER-18B" +
"5CKHITAN SMALL SCRIPT CHARACTER-18B5DKHITAN SMALL SCRIPT CHARACTER-18B5E" +
"KHITAN SMALL SCRIPT CHARACTER-18B5FKHITAN SMALL SCRIPT CHARACTER-18B60KH" +
"ITAN SMALL SCRIPT CHARACTER-18B61KHITAN SMALL SCRIPT CHARACTER-18B62KHIT" +
"AN SMALL SCRIPT CHARACTER-18B63KHITAN SMALL SCRIPT CHARACTER-18B64KHITAN" +
" SMALL SCRIPT CHARACTER-18B65KHITAN SMALL SCRIPT CHARACTER-18B66KHITAN S" +
"MALL SCRIPT CHARACTER-18B67KHITAN SMALL SCRIPT CHARACTER-18B68KHITAN SMA" +
"LL SCRIPT CHARACTER-18B69KHITAN SMALL SCRIPT CHARACTER-18B6AKHITAN SMALL" +
" SCRIPT CHARACTER-18B6BKHITAN SMALL SCRIPT CHARACTER-18B6CKHITAN SMALL S" +
"CRIPT CHARACTER-18B6DKHITAN SMALL SCRIPT CHARACTER-18B6EKHITAN SMALL SCR" +
"IPT CHARACTER-18B6FKHITAN SMALL SCRIPT CHARACTER-18B70KHITAN SMALL SCRIP" +
"T CHARACTER-18B71KHITAN SMALL SCRIPT CHARACTER-18B72KHITAN SMALL SCRIPT " +
"CHARACTER-18B73KHITAN SMALL SCRIPT CHARACTER-18B74KHITAN SMALL SCRIPT CH" +
"ARACTER-18B75KHITAN SMALL SCRIPT CHARACTER-18B76KHITAN SMALL SCRIPT CHAR" +
"ACTER-18B77KHITAN SMALL SCRIPT CHARACTER-18B78KHITAN SMALL SCRIPT CHARAC" +
"TER-18B79KHITAN SMALL SCRIPT CHARACTER-18B7AKHITAN SMALL SCRIPT CHARACTE" +
"R-18B7BKHITAN SMALL SCRIPT CHARACTER-18B7CKHITAN SMALL SCRIPT CHARACTER-" +
"18B7DKHITAN SMALL SCRIPT CHARACTER-18B7EKHITAN SMALL SCRIPT CHARACTER-18" +
"B7FKHITAN SMALL SCRIPT CHARACTER-18B80KHITAN SMALL SCRIPT CHARACTER-18B8" +
"1KHITAN SMALL SCRIPT CHARACTER-18B82KHITAN SMALL SCRIPT CHARACTER-18B83K" +
"HITAN SMALL SCRIPT CHARACTER-18B84KHITAN SMALL SCRIPT CHARACTER-18B85KHI" +
"TAN SMALL SCRIPT CHARACTER-18B86KHITAN SMALL SCRIPT CHARACTER-18B87KHITA" +
"N SMALL SCRIPT CHARACTER-18B88KHITAN SMALL SCRIPT CHARACTER-18B89KHITAN " +
"SMALL SCRIPT CHARACTER-18B8AKHITAN SMALL SCRIPT CHARACTER-18B8BKHITAN SM") + ("" +
"ALL SCRIPT CHARACTER-18B8CKHITAN SMALL SCRIPT CHARACTER-18B8DKHITAN SMAL" +
"L SCRIPT CHARACTER-18B8EKHITAN SMALL SCRIPT CHARACTER-18B8FKHITAN SMALL " +
"SCRIPT CHARACTER-18B90KHITAN SMALL SCRIPT CHARACTER-18B91KHITAN SMALL SC" +
"RIPT CHARACTER-18B92KHITAN SMALL SCRIPT CHARACTER-18B93KHITAN SMALL SCRI" +
"PT CHARACTER-18B94KHITAN SMALL SCRIPT CHARACTER-18B95KHITAN SMALL SCRIPT" +
" CHARACTER-18B96KHITAN SMALL SCRIPT CHARACTER-18B97KHITAN SMALL SCRIPT C" +
"HARACTER-18B98KHITAN SMALL SCRIPT CHARACTER-18B99KHITAN SMALL SCRIPT CHA" +
"RACTER-18B9AKHITAN SMALL SCRIPT CHARACTER-18B9BKHITAN SMALL SCRIPT CHARA" +
"CTER-18B9CKHITAN SMALL SCRIPT CHARACTER-18B9DKHITAN SMALL SCRIPT CHARACT" +
"ER-18B9EKHITAN SMALL SCRIPT CHARACTER-18B9FKHITAN SMALL SCRIPT CHARACTER" +
"-18BA0KHITAN SMALL SCRIPT CHARACTER-18BA1KHITAN SMALL SCRIPT CHARACTER-1" +
"8BA2KHITAN SMALL SCRIPT CHARACTER-18BA3KHITAN SMALL SCRIPT CHARACTER-18B" +
"A4KHITAN SMALL SCRIPT CHARACTER-18BA5KHITAN SMALL SCRIPT CHARACTER-18BA6" +
"KHITAN SMALL SCRIPT CHARACTER-18BA7KHITAN SMALL SCRIPT CHARACTER-18BA8KH" +
"ITAN SMALL SCRIPT CHARACTER-18BA9KHITAN SMALL SCRIPT CHARACTER-18BAAKHIT" +
"AN SMALL SCRIPT CHARACTER-18BABKHITAN SMALL SCRIPT CHARACTER-18BACKHITAN" +
" SMALL SCRIPT CHARACTER-18BADKHITAN SMALL SCRIPT CHARACTER-18BAEKHITAN S" +
"MALL SCRIPT CHARACTER-18BAFKHITAN SMALL SCRIPT CHARACTER-18BB0KHITAN SMA" +
"LL SCRIPT CHARACTER-18BB1KHITAN SMALL SCRIPT CHARACTER-18BB2KHITAN SMALL" +
" SCRIPT CHARACTER-18BB3KHITAN SMALL SCRIPT CHARACTER-18BB4KHITAN SMALL S" +
"CRIPT CHARACTER-18BB5KHITAN SMALL SCRIPT CHARACTER-18BB6KHITAN SMALL SCR" +
"IPT CHARACTER-18BB7KHITAN SMALL SCRIPT CHARACTER-18BB8KHITAN SMALL SCRIP" +
"T CHARACTER-18BB9KHITAN SMALL SCRIPT CHARACTER-18BBAKHITAN SMALL SCRIPT " +
"CHARACTER-18BBBKHITAN SMALL SCRIPT CHARACTER-18BBCKHITAN SMALL SCRIPT CH" +
"ARACTER-18BBDKHITAN SMALL SCRIPT CHARACTER-18BBEKHITAN SMALL SCRIPT CHAR" +
"ACTER-18BBFKHITAN SMALL SCRIPT CHARACTER-18BC0KHITAN SMALL SCRIPT CHARAC" +
"TER-18BC1KHITAN SMALL SCRIPT CHARACTER-18BC2KHITAN SMALL SCRIPT CHARACTE" +
"R-18BC3KHITAN SMALL SCRIPT CHARACTER-18BC4KHITAN SMALL SCRIPT CHARACTER-" +
"18BC5KHITAN SMALL SCRIPT CHARACTER-18BC6KHITAN SMALL SCRIPT CHARACTER-18" +
"BC7KHITAN SMALL SCRIPT CHARACTER-18BC8KHITAN SMALL SCRIPT CHARACTER-18BC" +
"9KHITAN SMALL SCRIPT CHARACTER-18BCAKHITAN SMALL SCRIPT CHARACTER-18BCBK" +
"HITAN SMALL SCRIPT CHARACTER-18BCCKHITAN SMALL SCRIPT CHARACTER-18BCDKHI" +
"TAN SMALL SCRIPT CHARACTER-18BCEKHITAN SMALL SCRIPT CHARACTER-18BCFKHITA" +
"N SMALL SCRIPT CHARACTER-18BD0KHITAN SMALL SCRIPT CHARACTER-18BD1KHITAN " +
"SMALL SCRIPT CHARACTER-18BD2KHITAN SMALL SCRIPT CHARACTER-18BD3KHITAN SM" +
"ALL SCRIPT CHARACTER-18BD4KHITAN SMALL SCRIPT CHARACTER-18BD5KHITAN SMAL" +
"L SCRIPT CHARACTER-18BD6KHITAN SMALL SCRIPT CHARACTER-18BD7KHITAN SMALL " +
"SCRIPT CHARACTER-18BD8KHITAN SMALL SCRIPT CHARACTER-18BD9KHITAN SMALL SC" +
"RIPT CHARACTER-18BDAKHITAN SMALL SCRIPT CHARACTER-18BDBKHITAN SMALL SCRI" +
"PT CHARACTER-18BDCKHITAN SMALL SCRIPT CHARACTER-18BDDKHITAN SMALL SCRIPT" +
" CHARACTER-18BDEKHITAN SMALL SCRIPT CHARACTER-18BDFKHITAN SMALL SCRIPT C" +
"HARACTER-18BE0KHITAN SMALL SCRIPT CHARACTER-18BE1KHITAN SMALL SCRIPT CHA" +
"RACTER-18BE2KHITAN SMALL SCRIPT CHARACTER-18BE3KHITAN SMALL SCRIPT CHARA" +
"CTER-18BE4KHITAN SMALL SCRIPT CHARACTER-18BE5KHITAN SMALL SCRIPT CHARACT" +
"ER-18BE6KHITAN SMALL SCRIPT CHARACTER-18BE7KHITAN SMALL SCRIPT CHARACTER" +
"-18BE8KHITAN SMALL SCRIPT CHARACTER-18BE9KHITAN SMALL SCRIPT CHARACTER-1" +
"8BEAKHITAN SMALL SCRIPT CHARACTER-18BEBKHITAN SMALL SCRIPT CHARACTER-18B" +
"ECKHITAN SMALL SCRIPT CHARACTER-18BEDKHITAN SMALL SCRIPT CHARACTER-18BEE" +
"KHITAN SMALL SCRIPT CHARACTER-18BEFKHITAN SMALL SCRIPT CHARACTER-18BF0KH" +
"ITAN SMALL SCRIPT CHARACTER-18BF1KHITAN SMALL SCRIPT CHARACTER-18BF2KHIT" +
"AN SMALL SCRIPT CHARACTER-18BF3KHITAN SMALL SCRIPT CHARACTER-18BF4KHITAN" +
" SMALL SCRIPT CHARACTER-18BF5KHITAN SMALL SCRIPT CHARACTER-18BF6KHITAN S" +
"MALL SCRIPT CHARACTER-18BF7KHITAN SMALL SCRIPT CHARACTER-18BF8KHITAN SMA" +
"LL SCRIPT CHARACTER-18BF9KHITAN SMALL SCRIPT CHARACTER-18BFAKHITAN SMALL" +
" SCRIPT CHARACTER-18BFBKHITAN SMALL SCRIPT CHARACTER-18BFCKHITAN SMALL S" +
"CRIPT CHARACTER-18BFDKHITAN SMALL SCRIPT CHARACTER-18BFEKHITAN SMALL SCR" +
"IPT CHARACTER-18BFFKHITAN SMALL SCRIPT CHARACTER-18C00KHITAN SMALL SCRIP" +
"T CHARACTER-18C01KHITAN SMALL SCRIPT CHARACTER-18C02KHITAN SMALL SCRIPT " +
"CHARACTER-18C03KHITAN SMALL SCRIPT CHARACTER-18C04KHITAN SMALL SCRIPT CH" +
"ARACTER-18C05KHITAN SMALL SCRIPT CHARACTER-18C06KHITAN SMALL SCRIPT CHAR" +
"ACTER-18C07KHITAN SMALL SCRIPT CHARACTER-18C08KHITAN SMALL SCRIPT CHARAC" +
"TER-18C09KHITAN SMALL SCRIPT CHARACTER-18C0AKHITAN SMALL SCRIPT CHARACTE" +
"R-18C0BKHITAN SMALL SCRIPT CHARACTER-18C0CKHITAN SMALL SCRIPT CHARACTER-" +
"18C0DKHITAN SMALL SCRIPT CHARACTER-18C0EKHITAN SMALL SCRIPT CHARACTER-18") + ("" +
"C0FKHITAN SMALL SCRIPT CHARACTER-18C10KHITAN SMALL SCRIPT CHARACTER-18C1" +
"1KHITAN SMALL SCRIPT CHARACTER-18C12KHITAN SMALL SCRIPT CHARACTER-18C13K" +
"HITAN SMALL SCRIPT CHARACTER-18C14KHITAN SMALL SCRIPT CHARACTER-18C15KHI" +
"TAN SMALL SCRIPT CHARACTER-18C16KHITAN SMALL SCRIPT CHARACTER-18C17KHITA" +
"N SMALL SCRIPT CHARACTER-18C18KHITAN SMALL SCRIPT CHARACTER-18C19KHITAN " +
"SMALL SCRIPT CHARACTER-18C1AKHITAN SMALL SCRIPT CHARACTER-18C1BKHITAN SM" +
"ALL SCRIPT CHARACTER-18C1CKHITAN SMALL SCRIPT CHARACTER-18C1DKHITAN SMAL" +
"L SCRIPT CHARACTER-18C1EKHITAN SMALL SCRIPT CHARACTER-18C1FKHITAN SMALL " +
"SCRIPT CHARACTER-18C20KHITAN SMALL SCRIPT CHARACTER-18C21KHITAN SMALL SC" +
"RIPT CHARACTER-18C22KHITAN SMALL SCRIPT CHARACTER-18C23KHITAN SMALL SCRI" +
"PT CHARACTER-18C24KHITAN SMALL SCRIPT CHARACTER-18C25KHITAN SMALL SCRIPT" +
" CHARACTER-18C26KHITAN SMALL SCRIPT CHARACTER-18C27KHITAN SMALL SCRIPT C" +
"HARACTER-18C28KHITAN SMALL SCRIPT CHARACTER-18C29KHITAN SMALL SCRIPT CHA" +
"RACTER-18C2AKHITAN SMALL SCRIPT CHARACTER-18C2BKHITAN SMALL SCRIPT CHARA" +
"CTER-18C2CKHITAN SMALL SCRIPT CHARACTER-18C2DKHITAN SMALL SCRIPT CHARACT" +
"ER-18C2EKHITAN SMALL SCRIPT CHARACTER-18C2FKHITAN SMALL SCRIPT CHARACTER" +
"-18C30KHITAN SMALL SCRIPT CHARACTER-18C31KHITAN SMALL SCRIPT CHARACTER-1" +
"8C32KHITAN SMALL SCRIPT CHARACTER-18C33KHITAN SMALL SCRIPT CHARACTER-18C" +
"34KHITAN SMALL SCRIPT CHARACTER-18C35KHITAN SMALL SCRIPT CHARACTER-18C36" +
"KHITAN SMALL SCRIPT CHARACTER-18C37KHITAN SMALL SCRIPT CHARACTER-18C38KH" +
"ITAN SMALL SCRIPT CHARACTER-18C39KHITAN SMALL SCRIPT CHARACTER-18C3AKHIT" +
"AN SMALL SCRIPT CHARACTER-18C3BKHITAN SMALL SCRIPT CHARACTER-18C3CKHITAN" +
" SMALL SCRIPT CHARACTER-18C3DKHITAN SMALL SCRIPT CHARACTER-18C3EKHITAN S" +
"MALL SCRIPT CHARACTER-18C3FKHITAN SMALL SCRIPT CHARACTER-18C40KHITAN SMA" +
"LL SCRIPT CHARACTER-18C41KHITAN SMALL SCRIPT CHARACTER-18C42KHITAN SMALL" +
" SCRIPT CHARACTER-18C43KHITAN SMALL SCRIPT CHARACTER-18C44KHITAN SMALL S" +
"CRIPT CHARACTER-18C45KHITAN SMALL SCRIPT CHARACTER-18C46KHITAN SMALL SCR" +
"IPT CHARACTER-18C47KHITAN SMALL SCRIPT CHARACTER-18C48KHITAN SMALL SCRIP" +
"T CHARACTER-18C49KHITAN SMALL SCRIPT CHARACTER-18C4AKHITAN SMALL SCRIPT " +
"CHARACTER-18C4BKHITAN SMALL SCRIPT CHARACTER-18C4CKHITAN SMALL SCRIPT CH" +
"ARACTER-18C4DKHITAN SMALL SCRIPT CHARACTER-18C4EKHITAN SMALL SCRIPT CHAR" +
"ACTER-18C4FKHITAN SMALL SCRIPT CHARACTER-18C50KHITAN SMALL SCRIPT CHARAC" +
"TER-18C51KHITAN SMALL SCRIPT CHARACTER-18C52KHITAN SMALL SCRIPT CHARACTE" +
"R-18C53KHITAN SMALL SCRIPT CHARACTER-18C54KHITAN SMALL SCRIPT CHARACTER-" +
"18C55KHITAN SMALL SCRIPT CHARACTER-18C56KHITAN SMALL SCRIPT CHARACTER-18" +
"C57KHITAN SMALL SCRIPT CHARACTER-18C58KHITAN SMALL SCRIPT CHARACTER-18C5" +
"9KHITAN SMALL SCRIPT CHARACTER-18C5AKHITAN SMALL SCRIPT CHARACTER-18C5BK" +
"HITAN SMALL SCRIPT CHARACTER-18C5CKHITAN SMALL SCRIPT CHARACTER-18C5DKHI" +
"TAN SMALL SCRIPT CHARACTER-18C5EKHITAN SMALL SCRIPT CHARACTER-18C5FKHITA" +
"N SMALL SCRIPT CHARACTER-18C60KHITAN SMALL SCRIPT CHARACTER-18C61KHITAN " +
"SMALL SCRIPT CHARACTER-18C62KHITAN SMALL SCRIPT CHARACTER-18C63KHITAN SM" +
"ALL SCRIPT CHARACTER-18C64KHITAN SMALL SCRIPT CHARACTER-18C65KHITAN SMAL" +
"L SCRIPT CHARACTER-18C66KHITAN SMALL SCRIPT CHARACTER-18C67KHITAN SMALL " +
"SCRIPT CHARACTER-18C68KHITAN SMALL SCRIPT CHARACTER-18C69KHITAN SMALL SC" +
"RIPT CHARACTER-18C6AKHITAN SMALL SCRIPT CHARACTER-18C6BKHITAN SMALL SCRI" +
"PT CHARACTER-18C6CKHITAN SMALL SCRIPT CHARACTER-18C6DKHITAN SMALL SCRIPT" +
" CHARACTER-18C6EKHITAN SMALL SCRIPT CHARACTER-18C6FKHITAN SMALL SCRIPT C" +
"HARACTER-18C70KHITAN SMALL SCRIPT CHARACTER-18C71KHITAN SMALL SCRIPT CHA" +
"RACTER-18C72KHITAN SMALL SCRIPT CHARACTER-18C73KHITAN SMALL SCRIPT CHARA" +
"CTER-18C74KHITAN SMALL SCRIPT CHARACTER-18C75KHITAN SMALL SCRIPT CHARACT" +
"ER-18C76KHITAN SMALL SCRIPT CHARACTER-18C77KHITAN SMALL SCRIPT CHARACTER" +
"-18C78KHITAN SMALL SCRIPT CHARACTER-18C79KHITAN SMALL SCRIPT CHARACTER-1" +
"8C7AKHITAN SMALL SCRIPT CHARACTER-18C7BKHITAN SMALL SCRIPT CHARACTER-18C" +
"7CKHITAN SMALL SCRIPT CHARACTER-18C7DKHITAN SMALL SCRIPT CHARACTER-18C7E" +
"KHITAN SMALL SCRIPT CHARACTER-18C7FKHITAN SMALL SCRIPT CHARACTER-18C80KH" +
"ITAN SMALL SCRIPT CHARACTER-18C81KHITAN SMALL SCRIPT CHARACTER-18C82KHIT" +
"AN SMALL SCRIPT CHARACTER-18C83KHITAN SMALL SCRIPT CHARACTER-18C84KHITAN" +
" SMALL SCRIPT CHARACTER-18C85KHITAN SMALL SCRIPT CHARACTER-18C86KHITAN S" +
"MALL SCRIPT CHARACTER-18C87KHITAN SMALL SCRIPT CHARACTER-18C88KHITAN SMA" +
"LL SCRIPT CHARACTER-18C89KHITAN SMALL SCRIPT CHARACTER-18C8AKHITAN SMALL" +
" SCRIPT CHARACTER-18C8BKHITAN SMALL SCRIPT CHARACTER-18C8CKHITAN SMALL S" +
"CRIPT CHARACTER-18C8DKHITAN SMALL SCRIPT CHARACTER-18C8EKHITAN SMALL SCR" +
"IPT CHARACTER-18C8FKHITAN SMALL SCRIPT CHARACTER-18C90KHITAN SMALL SCRIP" +
"T CHARACTER-18C91KHITAN SMALL SCRIPT CHARACTER-18C92KHITAN SMALL SCRIPT ") + ("" +
"CHARACTER-18C93KHITAN SMALL SCRIPT CHARACTER-18C94KHITAN SMALL SCRIPT CH" +
"ARACTER-18C95KHITAN SMALL SCRIPT CHARACTER-18C96KHITAN SMALL SCRIPT CHAR" +
"ACTER-18C97KHITAN SMALL SCRIPT CHARACTER-18C98KHITAN SMALL SCRIPT CHARAC" +
"TER-18C99KHITAN SMALL SCRIPT CHARACTER-18C9AKHITAN SMALL SCRIPT CHARACTE" +
"R-18C9BKHITAN SMALL SCRIPT CHARACTER-18C9CKHITAN SMALL SCRIPT CHARACTER-" +
"18C9DKHITAN SMALL SCRIPT CHARACTER-18C9EKHITAN SMALL SCRIPT CHARACTER-18" +
"C9FKHITAN SMALL SCRIPT CHARACTER-18CA0KHITAN SMALL SCRIPT CHARACTER-18CA" +
"1KHITAN SMALL SCRIPT CHARACTER-18CA2KHITAN SMALL SCRIPT CHARACTER-18CA3K" +
"HITAN SMALL SCRIPT CHARACTER-18CA4KHITAN SMALL SCRIPT CHARACTER-18CA5KHI" +
"TAN SMALL SCRIPT CHARACTER-18CA6KHITAN SMALL SCRIPT CHARACTER-18CA7KHITA" +
"N SMALL SCRIPT CHARACTER-18CA8KHITAN SMALL SCRIPT CHARACTER-18CA9KHITAN " +
"SMALL SCRIPT CHARACTER-18CAAKHITAN SMALL SCRIPT CHARACTER-18CABKHITAN SM" +
"ALL SCRIPT CHARACTER-18CACKHITAN SMALL SCRIPT CHARACTER-18CADKHITAN SMAL" +
"L SCRIPT CHARACTER-18CAEKHITAN SMALL SCRIPT CHARACTER-18CAFKHITAN SMALL " +
"SCRIPT CHARACTER-18CB0KHITAN SMALL SCRIPT CHARACTER-18CB1KHITAN SMALL SC" +
"RIPT CHARACTER-18CB2KHITAN SMALL SCRIPT CHARACTER-18CB3KHITAN SMALL SCRI" +
"PT CHARACTER-18CB4KHITAN SMALL SCRIPT CHARACTER-18CB5KHITAN SMALL SCRIPT" +
" CHARACTER-18CB6KHITAN SMALL SCRIPT CHARACTER-18CB7KHITAN SMALL SCRIPT C" +
"HARACTER-18CB8KHITAN SMALL SCRIPT CHARACTER-18CB9KHITAN SMALL SCRIPT CHA" +
"RACTER-18CBAKHITAN SMALL SCRIPT CHARACTER-18CBBKHITAN SMALL SCRIPT CHARA" +
"CTER-18CBCKHITAN SMALL SCRIPT CHARACTER-18CBDKHITAN SMALL SCRIPT CHARACT" +
"ER-18CBEKHITAN SMALL SCRIPT CHARACTER-18CBFKHITAN SMALL SCRIPT CHARACTER" +
"-18CC0KHITAN SMALL SCRIPT CHARACTER-18CC1KHITAN SMALL SCRIPT CHARACTER-1" +
"8CC2KHITAN SMALL SCRIPT CHARACTER-18CC3KHITAN SMALL SCRIPT CHARACTER-18C" +
"C4KHITAN SMALL SCRIPT CHARACTER-18CC5KHITAN SMALL SCRIPT CHARACTER-18CC6" +
"KHITAN SMALL SCRIPT CHARACTER-18CC7KHITAN SMALL SCRIPT CHARACTER-18CC8KH" +
"ITAN SMALL SCRIPT CHARACTER-18CC9KHITAN SMALL SCRIPT CHARACTER-18CCAKHIT" +
"AN SMALL SCRIPT CHARACTER-18CCBKHITAN SMALL SCRIPT CHARACTER-18CCCKHITAN" +
" SMALL SCRIPT CHARACTER-18CCDKHITAN SMALL SCRIPT CHARACTER-18CCEKHITAN S" +
"MALL SCRIPT CHARACTER-18CCFKHITAN SMALL SCRIPT CHARACTER-18CD0KHITAN SMA" +
"LL SCRIPT CHARACTER-18CD1KHITAN SMALL SCRIPT CHARACTER-18CD2KHITAN SMALL" +
" SCRIPT CHARACTER-18CD3KHITAN SMALL SCRIPT CHARACTER-18CD4KHITAN SMALL S" +
"CRIPT CHARACTER-18CD5KHITAN SMALL SCRIPT CHARACTER-18CFFTANGUT COMPONENT" +
"-769TANGUT COMPONENT-770TANGUT COMPONENT-771TANGUT COMPONENT-772TANGUT C" +
"OMPONENT-773TANGUT COMPONENT-774TANGUT COMPONENT-775TANGUT COMPONENT-776" +
"TANGUT COMPONENT-777TANGUT COMPONENT-778TANGUT COMPONENT-779TANGUT COMPO" +
"NENT-780TANGUT COMPONENT-781TANGUT COMPONENT-782TANGUT COMPONENT-783TANG" +
"UT COMPONENT-784TANGUT COMPONENT-785TANGUT COMPONENT-786TANGUT COMPONENT" +
"-787TANGUT COMPONENT-788TANGUT COMPONENT-789TANGUT COMPONENT-790TANGUT C" +
"OMPONENT-791TANGUT COMPONENT-792TANGUT COMPONENT-793TANGUT COMPONENT-794" +
"TANGUT COMPONENT-795TANGUT COMPONENT-796TANGUT COMPONENT-797TANGUT COMPO" +
"NENT-798TANGUT COMPONENT-799TANGUT COMPONENT-800TANGUT COMPONENT-801TANG" +
"UT COMPONENT-802TANGUT COMPONENT-803TANGUT COMPONENT-804TANGUT COMPONENT" +
"-805TANGUT COMPONENT-806TANGUT COMPONENT-807TANGUT COMPONENT-808TANGUT C" +
"OMPONENT-809TANGUT COMPONENT-810TANGUT COMPONENT-811TANGUT COMPONENT-812" +
"TANGUT COMPONENT-813TANGUT COMPONENT-814TANGUT COMPONENT-815TANGUT COMPO" +
"NENT-816TANGUT COMPONENT-817TANGUT COMPONENT-818TANGUT COMPONENT-819TANG" +
"UT COMPONENT-820TANGUT COMPONENT-821TANGUT COMPONENT-822TANGUT COMPONENT" +
"-823TANGUT COMPONENT-824TANGUT COMPONENT-825TANGUT COMPONENT-826TANGUT C" +
"OMPONENT-827TANGUT COMPONENT-828TANGUT COMPONENT-829TANGUT COMPONENT-830" +
"TANGUT COMPONENT-831TANGUT COMPONENT-832TANGUT COMPONENT-833TANGUT COMPO" +
"NENT-834TANGUT COMPONENT-835TANGUT COMPONENT-836TANGUT COMPONENT-837TANG" +
"UT COMPONENT-838TANGUT COMPONENT-839TANGUT COMPONENT-840TANGUT COMPONENT" +
"-841TANGUT COMPONENT-842TANGUT COMPONENT-843TANGUT COMPONENT-844TANGUT C" +
"OMPONENT-845TANGUT COMPONENT-846TANGUT COMPONENT-847TANGUT COMPONENT-848" +
"TANGUT COMPONENT-849TANGUT COMPONENT-850TANGUT COMPONENT-851TANGUT COMPO" +
"NENT-852TANGUT COMPONENT-853TANGUT COMPONENT-854TANGUT COMPONENT-855TANG" +
"UT COMPONENT-856TANGUT COMPONENT-857TANGUT COMPONENT-858TANGUT COMPONENT" +
"-859TANGUT COMPONENT-860TANGUT COMPONENT-861TANGUT COMPONENT-862TANGUT C" +
"OMPONENT-863TANGUT COMPONENT-864TANGUT COMPONENT-865TANGUT COMPONENT-866" +
"TANGUT COMPONENT-867TANGUT COMPONENT-868TANGUT COMPONENT-869TANGUT COMPO" +
"NENT-870TANGUT COMPONENT-871TANGUT COMPONENT-872TANGUT COMPONENT-873TANG" +
"UT COMPONENT-874TANGUT COMPONENT-875TANGUT COMPONENT-876TANGUT COMPONENT" +
"-877TANGUT COMPONENT-878TANGUT COMPONENT-879TANGUT COMPONENT-880TANGUT C") + ("" +
"OMPONENT-881TANGUT COMPONENT-882TANGUT COMPONENT-883KATAKANA LETTER MINN" +
"AN TONE-2KATAKANA LETTER MINNAN TONE-3KATAKANA LETTER MINNAN TONE-4KATAK" +
"ANA LETTER MINNAN TONE-5KATAKANA LETTER MINNAN TONE-7KATAKANA LETTER MIN" +
"NAN TONE-8KATAKANA LETTER MINNAN NASALIZED TONE-1KATAKANA LETTER MINNAN " +
"NASALIZED TONE-2KATAKANA LETTER MINNAN NASALIZED TONE-3KATAKANA LETTER M" +
"INNAN NASALIZED TONE-4KATAKANA LETTER MINNAN NASALIZED TONE-5KATAKANA LE" +
"TTER MINNAN NASALIZED TONE-7KATAKANA LETTER MINNAN NASALIZED TONE-8KATAK" +
"ANA LETTER ARCHAIC EHIRAGANA LETTER ARCHAIC YEHENTAIGANA LETTER A-1HENTA" +
"IGANA LETTER A-2HENTAIGANA LETTER A-3HENTAIGANA LETTER A-WOHENTAIGANA LE" +
"TTER I-1HENTAIGANA LETTER I-2HENTAIGANA LETTER I-3HENTAIGANA LETTER I-4H" +
"ENTAIGANA LETTER U-1HENTAIGANA LETTER U-2HENTAIGANA LETTER U-3HENTAIGANA" +
" LETTER U-4HENTAIGANA LETTER U-5HENTAIGANA LETTER E-2HENTAIGANA LETTER E" +
"-3HENTAIGANA LETTER E-4HENTAIGANA LETTER E-5HENTAIGANA LETTER E-6HENTAIG" +
"ANA LETTER O-1HENTAIGANA LETTER O-2HENTAIGANA LETTER O-3HENTAIGANA LETTE" +
"R KA-1HENTAIGANA LETTER KA-2HENTAIGANA LETTER KA-3HENTAIGANA LETTER KA-4" +
"HENTAIGANA LETTER KA-5HENTAIGANA LETTER KA-6HENTAIGANA LETTER KA-7HENTAI" +
"GANA LETTER KA-8HENTAIGANA LETTER KA-9HENTAIGANA LETTER KA-10HENTAIGANA " +
"LETTER KA-11HENTAIGANA LETTER KA-KEHENTAIGANA LETTER KI-1HENTAIGANA LETT" +
"ER KI-2HENTAIGANA LETTER KI-3HENTAIGANA LETTER KI-4HENTAIGANA LETTER KI-" +
"5HENTAIGANA LETTER KI-6HENTAIGANA LETTER KI-7HENTAIGANA LETTER KI-8HENTA" +
"IGANA LETTER KU-1HENTAIGANA LETTER KU-2HENTAIGANA LETTER KU-3HENTAIGANA " +
"LETTER KU-4HENTAIGANA LETTER KU-5HENTAIGANA LETTER KU-6HENTAIGANA LETTER" +
" KU-7HENTAIGANA LETTER KE-1HENTAIGANA LETTER KE-2HENTAIGANA LETTER KE-3H" +
"ENTAIGANA LETTER KE-4HENTAIGANA LETTER KE-5HENTAIGANA LETTER KE-6HENTAIG" +
"ANA LETTER KO-1HENTAIGANA LETTER KO-2HENTAIGANA LETTER KO-3HENTAIGANA LE" +
"TTER KO-KIHENTAIGANA LETTER SA-1HENTAIGANA LETTER SA-2HENTAIGANA LETTER " +
"SA-3HENTAIGANA LETTER SA-4HENTAIGANA LETTER SA-5HENTAIGANA LETTER SA-6HE" +
"NTAIGANA LETTER SA-7HENTAIGANA LETTER SA-8HENTAIGANA LETTER SI-1HENTAIGA" +
"NA LETTER SI-2HENTAIGANA LETTER SI-3HENTAIGANA LETTER SI-4HENTAIGANA LET" +
"TER SI-5HENTAIGANA LETTER SI-6HENTAIGANA LETTER SU-1HENTAIGANA LETTER SU" +
"-2HENTAIGANA LETTER SU-3HENTAIGANA LETTER SU-4HENTAIGANA LETTER SU-5HENT" +
"AIGANA LETTER SU-6HENTAIGANA LETTER SU-7HENTAIGANA LETTER SU-8HENTAIGANA" +
" LETTER SE-1HENTAIGANA LETTER SE-2HENTAIGANA LETTER SE-3HENTAIGANA LETTE" +
"R SE-4HENTAIGANA LETTER SE-5HENTAIGANA LETTER SO-1HENTAIGANA LETTER SO-2" +
"HENTAIGANA LETTER SO-3HENTAIGANA LETTER SO-4HENTAIGANA LETTER SO-5HENTAI" +
"GANA LETTER SO-6HENTAIGANA LETTER SO-7HENTAIGANA LETTER TA-1HENTAIGANA L" +
"ETTER TA-2HENTAIGANA LETTER TA-3HENTAIGANA LETTER TA-4HENTAIGANA LETTER " +
"TI-1HENTAIGANA LETTER TI-2HENTAIGANA LETTER TI-3HENTAIGANA LETTER TI-4HE" +
"NTAIGANA LETTER TI-5HENTAIGANA LETTER TI-6HENTAIGANA LETTER TI-7HENTAIGA" +
"NA LETTER TU-1HENTAIGANA LETTER TU-2HENTAIGANA LETTER TU-3HENTAIGANA LET" +
"TER TU-4HENTAIGANA LETTER TU-TOHENTAIGANA LETTER TE-1HENTAIGANA LETTER T" +
"E-2HENTAIGANA LETTER TE-3HENTAIGANA LETTER TE-4HENTAIGANA LETTER TE-5HEN" +
"TAIGANA LETTER TE-6HENTAIGANA LETTER TE-7HENTAIGANA LETTER TE-8HENTAIGAN" +
"A LETTER TE-9HENTAIGANA LETTER TO-1HENTAIGANA LETTER TO-2HENTAIGANA LETT" +
"ER TO-3HENTAIGANA LETTER TO-4HENTAIGANA LETTER TO-5HENTAIGANA LETTER TO-" +
"6HENTAIGANA LETTER TO-RAHENTAIGANA LETTER NA-1HENTAIGANA LETTER NA-2HENT" +
"AIGANA LETTER NA-3HENTAIGANA LETTER NA-4HENTAIGANA LETTER NA-5HENTAIGANA" +
" LETTER NA-6HENTAIGANA LETTER NA-7HENTAIGANA LETTER NA-8HENTAIGANA LETTE" +
"R NA-9HENTAIGANA LETTER NI-1HENTAIGANA LETTER NI-2HENTAIGANA LETTER NI-3" +
"HENTAIGANA LETTER NI-4HENTAIGANA LETTER NI-5HENTAIGANA LETTER NI-6HENTAI" +
"GANA LETTER NI-7HENTAIGANA LETTER NI-TEHENTAIGANA LETTER NU-1HENTAIGANA " +
"LETTER NU-2HENTAIGANA LETTER NU-3HENTAIGANA LETTER NE-1HENTAIGANA LETTER" +
" NE-2HENTAIGANA LETTER NE-3HENTAIGANA LETTER NE-4HENTAIGANA LETTER NE-5H" +
"ENTAIGANA LETTER NE-6HENTAIGANA LETTER NE-KOHENTAIGANA LETTER NO-1HENTAI" +
"GANA LETTER NO-2HENTAIGANA LETTER NO-3HENTAIGANA LETTER NO-4HENTAIGANA L" +
"ETTER NO-5HENTAIGANA LETTER HA-1HENTAIGANA LETTER HA-2HENTAIGANA LETTER " +
"HA-3HENTAIGANA LETTER HA-4HENTAIGANA LETTER HA-5HENTAIGANA LETTER HA-6HE" +
"NTAIGANA LETTER HA-7HENTAIGANA LETTER HA-8HENTAIGANA LETTER HA-9HENTAIGA" +
"NA LETTER HA-10HENTAIGANA LETTER HA-11HENTAIGANA LETTER HI-1HENTAIGANA L" +
"ETTER HI-2HENTAIGANA LETTER HI-3HENTAIGANA LETTER HI-4HENTAIGANA LETTER " +
"HI-5HENTAIGANA LETTER HI-6HENTAIGANA LETTER HI-7HENTAIGANA LETTER HU-1HE" +
"NTAIGANA LETTER HU-2HENTAIGANA LETTER HU-3HENTAIGANA LETTER HE-1HENTAIGA" +
"NA LETTER HE-2HENTAIGANA LETTER HE-3HENTAIGANA LETTER HE-4HENTAIGANA LET" +
"TER HE-5HENTAIGANA LETTER HE-6HENTAIGANA LETTER HE-7HENTAIGANA LETTER HO") + ("" +
"-1HENTAIGANA LETTER HO-2HENTAIGANA LETTER HO-3HENTAIGANA LETTER HO-4HENT" +
"AIGANA LETTER HO-5HENTAIGANA LETTER HO-6HENTAIGANA LETTER HO-7HENTAIGANA" +
" LETTER HO-8HENTAIGANA LETTER MA-1HENTAIGANA LETTER MA-2HENTAIGANA LETTE" +
"R MA-3HENTAIGANA LETTER MA-4HENTAIGANA LETTER MA-5HENTAIGANA LETTER MA-6" +
"HENTAIGANA LETTER MA-7HENTAIGANA LETTER MI-1HENTAIGANA LETTER MI-2HENTAI" +
"GANA LETTER MI-3HENTAIGANA LETTER MI-4HENTAIGANA LETTER MI-5HENTAIGANA L" +
"ETTER MI-6HENTAIGANA LETTER MI-7HENTAIGANA LETTER MU-1HENTAIGANA LETTER " +
"MU-2HENTAIGANA LETTER MU-3HENTAIGANA LETTER MU-4HENTAIGANA LETTER ME-1HE" +
"NTAIGANA LETTER ME-2HENTAIGANA LETTER ME-MAHENTAIGANA LETTER MO-1HENTAIG" +
"ANA LETTER MO-2HENTAIGANA LETTER MO-3HENTAIGANA LETTER MO-4HENTAIGANA LE" +
"TTER MO-5HENTAIGANA LETTER MO-6HENTAIGANA LETTER YA-1HENTAIGANA LETTER Y" +
"A-2HENTAIGANA LETTER YA-3HENTAIGANA LETTER YA-4HENTAIGANA LETTER YA-5HEN" +
"TAIGANA LETTER YA-YOHENTAIGANA LETTER YU-1HENTAIGANA LETTER YU-2HENTAIGA" +
"NA LETTER YU-3HENTAIGANA LETTER YU-4HENTAIGANA LETTER YO-1HENTAIGANA LET" +
"TER YO-2HENTAIGANA LETTER YO-3HENTAIGANA LETTER YO-4HENTAIGANA LETTER YO" +
"-5HENTAIGANA LETTER YO-6HENTAIGANA LETTER RA-1HENTAIGANA LETTER RA-2HENT" +
"AIGANA LETTER RA-3HENTAIGANA LETTER RA-4HENTAIGANA LETTER RI-1HENTAIGANA" +
" LETTER RI-2HENTAIGANA LETTER RI-3HENTAIGANA LETTER RI-4HENTAIGANA LETTE" +
"R RI-5HENTAIGANA LETTER RI-6HENTAIGANA LETTER RI-7HENTAIGANA LETTER RU-1" +
"HENTAIGANA LETTER RU-2HENTAIGANA LETTER RU-3HENTAIGANA LETTER RU-4HENTAI" +
"GANA LETTER RU-5HENTAIGANA LETTER RU-6HENTAIGANA LETTER RE-1HENTAIGANA L" +
"ETTER RE-2HENTAIGANA LETTER RE-3HENTAIGANA LETTER RE-4HENTAIGANA LETTER " +
"RO-1HENTAIGANA LETTER RO-2HENTAIGANA LETTER RO-3HENTAIGANA LETTER RO-4HE" +
"NTAIGANA LETTER RO-5HENTAIGANA LETTER RO-6HENTAIGANA LETTER WA-1HENTAIGA" +
"NA LETTER WA-2HENTAIGANA LETTER WA-3HENTAIGANA LETTER WA-4HENTAIGANA LET" +
"TER WA-5HENTAIGANA LETTER WI-1HENTAIGANA LETTER WI-2HENTAIGANA LETTER WI" +
"-3HENTAIGANA LETTER WI-4HENTAIGANA LETTER WI-5HENTAIGANA LETTER WE-1HENT" +
"AIGANA LETTER WE-2HENTAIGANA LETTER WE-3HENTAIGANA LETTER WE-4HENTAIGANA" +
" LETTER WO-1HENTAIGANA LETTER WO-2HENTAIGANA LETTER WO-3HENTAIGANA LETTE" +
"R WO-4HENTAIGANA LETTER WO-5HENTAIGANA LETTER WO-6HENTAIGANA LETTER WO-7" +
"HENTAIGANA LETTER N-MU-MO-1HENTAIGANA LETTER N-MU-MO-2HIRAGANA LETTER AR" +
"CHAIC WUKATAKANA LETTER ARCHAIC YIKATAKANA LETTER ARCHAIC YEKATAKANA LET" +
"TER ARCHAIC WUHIRAGANA LETTER SMALL KOHIRAGANA LETTER SMALL WIHIRAGANA L" +
"ETTER SMALL WEHIRAGANA LETTER SMALL WOKATAKANA LETTER SMALL KOKATAKANA L" +
"ETTER SMALL WIKATAKANA LETTER SMALL WEKATAKANA LETTER SMALL WOKATAKANA L" +
"ETTER SMALL NNUSHU CHARACTER-1B170NUSHU CHARACTER-1B171NUSHU CHARACTER-1" +
"B172NUSHU CHARACTER-1B173NUSHU CHARACTER-1B174NUSHU CHARACTER-1B175NUSHU" +
" CHARACTER-1B176NUSHU CHARACTER-1B177NUSHU CHARACTER-1B178NUSHU CHARACTE" +
"R-1B179NUSHU CHARACTER-1B17ANUSHU CHARACTER-1B17BNUSHU CHARACTER-1B17CNU" +
"SHU CHARACTER-1B17DNUSHU CHARACTER-1B17ENUSHU CHARACTER-1B17FNUSHU CHARA" +
"CTER-1B180NUSHU CHARACTER-1B181NUSHU CHARACTER-1B182NUSHU CHARACTER-1B18" +
"3NUSHU CHARACTER-1B184NUSHU CHARACTER-1B185NUSHU CHARACTER-1B186NUSHU CH" +
"ARACTER-1B187NUSHU CHARACTER-1B188NUSHU CHARACTER-1B189NUSHU CHARACTER-1" +
"B18ANUSHU CHARACTER-1B18BNUSHU CHARACTER-1B18CNUSHU CHARACTER-1B18DNUSHU" +
" CHARACTER-1B18ENUSHU CHARACTER-1B18FNUSHU CHARACTER-1B190NUSHU CHARACTE" +
"R-1B191NUSHU CHARACTER-1B192NUSHU CHARACTER-1B193NUSHU CHARACTER-1B194NU" +
"SHU CHARACTER-1B195NUSHU CHARACTER-1B196NUSHU CHARACTER-1B197NUSHU CHARA" +
"CTER-1B198NUSHU CHARACTER-1B199NUSHU CHARACTER-1B19ANUSHU CHARACTER-1B19" +
"BNUSHU CHARACTER-1B19CNUSHU CHARACTER-1B19DNUSHU CHARACTER-1B19ENUSHU CH" +
"ARACTER-1B19FNUSHU CHARACTER-1B1A0NUSHU CHARACTER-1B1A1NUSHU CHARACTER-1" +
"B1A2NUSHU CHARACTER-1B1A3NUSHU CHARACTER-1B1A4NUSHU CHARACTER-1B1A5NUSHU" +
" CHARACTER-1B1A6NUSHU CHARACTER-1B1A7NUSHU CHARACTER-1B1A8NUSHU CHARACTE" +
"R-1B1A9NUSHU CHARACTER-1B1AANUSHU CHARACTER-1B1ABNUSHU CHARACTER-1B1ACNU" +
"SHU CHARACTER-1B1ADNUSHU CHARACTER-1B1AENUSHU CHARACTER-1B1AFNUSHU CHARA" +
"CTER-1B1B0NUSHU CHARACTER-1B1B1NUSHU CHARACTER-1B1B2NUSHU CHARACTER-1B1B" +
"3NUSHU CHARACTER-1B1B4NUSHU CHARACTER-1B1B5NUSHU CHARACTER-1B1B6NUSHU CH" +
"ARACTER-1B1B7NUSHU CHARACTER-1B1B8NUSHU CHARACTER-1B1B9NUSHU CHARACTER-1" +
"B1BANUSHU CHARACTER-1B1BBNUSHU CHARACTER-1B1BCNUSHU CHARACTER-1B1BDNUSHU" +
" CHARACTER-1B1BENUSHU CHARACTER-1B1BFNUSHU CHARACTER-1B1C0NUSHU CHARACTE" +
"R-1B1C1NUSHU CHARACTER-1B1C2NUSHU CHARACTER-1B1C3NUSHU CHARACTER-1B1C4NU" +
"SHU CHARACTER-1B1C5NUSHU CHARACTER-1B1C6NUSHU CHARACTER-1B1C7NUSHU CHARA" +
"CTER-1B1C8NUSHU CHARACTER-1B1C9NUSHU CHARACTER-1B1CANUSHU CHARACTER-1B1C" +
"BNUSHU CHARACTER-1B1CCNUSHU CHARACTER-1B1CDNUSHU CHARACTER-1B1CENUSHU CH" +
"ARACTER-1B1CFNUSHU CHARACTER-1B1D0NUSHU CHARACTER-1B1D1NUSHU CHARACTER-1") + ("" +
"B1D2NUSHU CHARACTER-1B1D3NUSHU CHARACTER-1B1D4NUSHU CHARACTER-1B1D5NUSHU" +
" CHARACTER-1B1D6NUSHU CHARACTER-1B1D7NUSHU CHARACTER-1B1D8NUSHU CHARACTE" +
"R-1B1D9NUSHU CHARACTER-1B1DANUSHU CHARACTER-1B1DBNUSHU CHARACTER-1B1DCNU" +
"SHU CHARACTER-1B1DDNUSHU CHARACTER-1B1DENUSHU CHARACTER-1B1DFNUSHU CHARA" +
"CTER-1B1E0NUSHU CHARACTER-1B1E1NUSHU CHARACTER-1B1E2NUSHU CHARACTER-1B1E" +
"3NUSHU CHARACTER-1B1E4NUSHU CHARACTER-1B1E5NUSHU CHARACTER-1B1E6NUSHU CH" +
"ARACTER-1B1E7NUSHU CHARACTER-1B1E8NUSHU CHARACTER-1B1E9NUSHU CHARACTER-1" +
"B1EANUSHU CHARACTER-1B1EBNUSHU CHARACTER-1B1ECNUSHU CHARACTER-1B1EDNUSHU" +
" CHARACTER-1B1EENUSHU CHARACTER-1B1EFNUSHU CHARACTER-1B1F0NUSHU CHARACTE" +
"R-1B1F1NUSHU CHARACTER-1B1F2NUSHU CHARACTER-1B1F3NUSHU CHARACTER-1B1F4NU" +
"SHU CHARACTER-1B1F5NUSHU CHARACTER-1B1F6NUSHU CHARACTER-1B1F7NUSHU CHARA" +
"CTER-1B1F8NUSHU CHARACTER-1B1F9NUSHU CHARACTER-1B1FANUSHU CHARACTER-1B1F" +
"BNUSHU CHARACTER-1B1FCNUSHU CHARACTER-1B1FDNUSHU CHARACTER-1B1FENUSHU CH" +
"ARACTER-1B1FFNUSHU CHARACTER-1B200NUSHU CHARACTER-1B201NUSHU CHARACTER-1" +
"B202NUSHU CHARACTER-1B203NUSHU CHARACTER-1B204NUSHU CHARACTER-1B205NUSHU" +
" CHARACTER-1B206NUSHU CHARACTER-1B207NUSHU CHARACTER-1B208NUSHU CHARACTE" +
"R-1B209NUSHU CHARACTER-1B20ANUSHU CHARACTER-1B20BNUSHU CHARACTER-1B20CNU" +
"SHU CHARACTER-1B20DNUSHU CHARACTER-1B20ENUSHU CHARACTER-1B20FNUSHU CHARA" +
"CTER-1B210NUSHU CHARACTER-1B211NUSHU CHARACTER-1B212NUSHU CHARACTER-1B21" +
"3NUSHU CHARACTER-1B214NUSHU CHARACTER-1B215NUSHU CHARACTER-1B216NUSHU CH" +
"ARACTER-1B217NUSHU CHARACTER-1B218NUSHU CHARACTER-1B219NUSHU CHARACTER-1" +
"B21ANUSHU CHARACTER-1B21BNUSHU CHARACTER-1B21CNUSHU CHARACTER-1B21DNUSHU" +
" CHARACTER-1B21ENUSHU CHARACTER-1B21FNUSHU CHARACTER-1B220NUSHU CHARACTE" +
"R-1B221NUSHU CHARACTER-1B222NUSHU CHARACTER-1B223NUSHU CHARACTER-1B224NU" +
"SHU CHARACTER-1B225NUSHU CHARACTER-1B226NUSHU CHARACTER-1B227NUSHU CHARA" +
"CTER-1B228NUSHU CHARACTER-1B229NUSHU CHARACTER-1B22ANUSHU CHARACTER-1B22" +
"BNUSHU CHARACTER-1B22CNUSHU CHARACTER-1B22DNUSHU CHARACTER-1B22ENUSHU CH" +
"ARACTER-1B22FNUSHU CHARACTER-1B230NUSHU CHARACTER-1B231NUSHU CHARACTER-1" +
"B232NUSHU CHARACTER-1B233NUSHU CHARACTER-1B234NUSHU CHARACTER-1B235NUSHU" +
" CHARACTER-1B236NUSHU CHARACTER-1B237NUSHU CHARACTER-1B238NUSHU CHARACTE" +
"R-1B239NUSHU CHARACTER-1B23ANUSHU CHARACTER-1B23BNUSHU CHARACTER-1B23CNU" +
"SHU CHARACTER-1B23DNUSHU CHARACTER-1B23ENUSHU CHARACTER-1B23FNUSHU CHARA" +
"CTER-1B240NUSHU CHARACTER-1B241NUSHU CHARACTER-1B242NUSHU CHARACTER-1B24" +
"3NUSHU CHARACTER-1B244NUSHU CHARACTER-1B245NUSHU CHARACTER-1B246NUSHU CH" +
"ARACTER-1B247NUSHU CHARACTER-1B248NUSHU CHARACTER-1B249NUSHU CHARACTER-1" +
"B24ANUSHU CHARACTER-1B24BNUSHU CHARACTER-1B24CNUSHU CHARACTER-1B24DNUSHU" +
" CHARACTER-1B24ENUSHU CHARACTER-1B24FNUSHU CHARACTER-1B250NUSHU CHARACTE" +
"R-1B251NUSHU CHARACTER-1B252NUSHU CHARACTER-1B253NUSHU CHARACTER-1B254NU" +
"SHU CHARACTER-1B255NUSHU CHARACTER-1B256NUSHU CHARACTER-1B257NUSHU CHARA" +
"CTER-1B258NUSHU CHARACTER-1B259NUSHU CHARACTER-1B25ANUSHU CHARACTER-1B25" +
"BNUSHU CHARACTER-1B25CNUSHU CHARACTER-1B25DNUSHU CHARACTER-1B25ENUSHU CH" +
"ARACTER-1B25FNUSHU CHARACTER-1B260NUSHU CHARACTER-1B261NUSHU CHARACTER-1" +
"B262NUSHU CHARACTER-1B263NUSHU CHARACTER-1B264NUSHU CHARACTER-1B265NUSHU" +
" CHARACTER-1B266NUSHU CHARACTER-1B267NUSHU CHARACTER-1B268NUSHU CHARACTE" +
"R-1B269NUSHU CHARACTER-1B26ANUSHU CHARACTER-1B26BNUSHU CHARACTER-1B26CNU" +
"SHU CHARACTER-1B26DNUSHU CHARACTER-1B26ENUSHU CHARACTER-1B26FNUSHU CHARA" +
"CTER-1B270NUSHU CHARACTER-1B271NUSHU CHARACTER-1B272NUSHU CHARACTER-1B27" +
"3NUSHU CHARACTER-1B274NUSHU CHARACTER-1B275NUSHU CHARACTER-1B276NUSHU CH" +
"ARACTER-1B277NUSHU CHARACTER-1B278NUSHU CHARACTER-1B279NUSHU CHARACTER-1" +
"B27ANUSHU CHARACTER-1B27BNUSHU CHARACTER-1B27CNUSHU CHARACTER-1B27DNUSHU" +
" CHARACTER-1B27ENUSHU CHARACTER-1B27FNUSHU CHARACTER-1B280NUSHU CHARACTE" +
"R-1B281NUSHU CHARACTER-1B282NUSHU CHARACTER-1B283NUSHU CHARACTER-1B284NU" +
"SHU CHARACTER-1B285NUSHU CHARACTER-1B286NUSHU CHARACTER-1B287NUSHU CHARA" +
"CTER-1B288NUSHU CHARACTER-1B289NUSHU CHARACTER-1B28ANUSHU CHARACTER-1B28" +
"BNUSHU CHARACTER-1B28CNUSHU CHARACTER-1B28DNUSHU CHARACTER-1B28ENUSHU CH" +
"ARACTER-1B28FNUSHU CHARACTER-1B290NUSHU CHARACTER-1B291NUSHU CHARACTER-1" +
"B292NUSHU CHARACTER-1B293NUSHU CHARACTER-1B294NUSHU CHARACTER-1B295NUSHU" +
" CHARACTER-1B296NUSHU CHARACTER-1B297NUSHU CHARACTER-1B298NUSHU CHARACTE" +
"R-1B299NUSHU CHARACTER-1B29ANUSHU CHARACTER-1B29BNUSHU CHARACTER-1B29CNU" +
"SHU CHARACTER-1B29DNUSHU CHARACTER-1B29ENUSHU CHARACTER-1B29FNUSHU CHARA" +
"CTER-1B2A0NUSHU CHARACTER-1B2A1NUSHU CHARACTER-1B2A2NUSHU CHARACTER-1B2A" +
"3NUSHU CHARACTER-1B2A4NUSHU CHARACTER-1B2A5NUSHU CHARACTER-1B2A6NUSHU CH" +
"ARACTER-1B2A7NUSHU CHARACTER-1B2A8NUSHU CHARACTER-1B2A9NUSHU CHARACTER-1" +
"B2AANUSHU CHARACTER-1B2ABNUSHU CHARACTER-1B2ACNUSHU CHARACTER-1B2ADNUSHU") + ("" +
" CHARACTER-1B2AENUSHU CHARACTER-1B2AFNUSHU CHARACTER-1B2B0NUSHU CHARACTE" +
"R-1B2B1NUSHU CHARACTER-1B2B2NUSHU CHARACTER-1B2B3NUSHU CHARACTER-1B2B4NU" +
"SHU CHARACTER-1B2B5NUSHU CHARACTER-1B2B6NUSHU CHARACTER-1B2B7NUSHU CHARA" +
"CTER-1B2B8NUSHU CHARACTER-1B2B9NUSHU CHARACTER-1B2BANUSHU CHARACTER-1B2B" +
"BNUSHU CHARACTER-1B2BCNUSHU CHARACTER-1B2BDNUSHU CHARACTER-1B2BENUSHU CH" +
"ARACTER-1B2BFNUSHU CHARACTER-1B2C0NUSHU CHARACTER-1B2C1NUSHU CHARACTER-1" +
"B2C2NUSHU CHARACTER-1B2C3NUSHU CHARACTER-1B2C4NUSHU CHARACTER-1B2C5NUSHU" +
" CHARACTER-1B2C6NUSHU CHARACTER-1B2C7NUSHU CHARACTER-1B2C8NUSHU CHARACTE" +
"R-1B2C9NUSHU CHARACTER-1B2CANUSHU CHARACTER-1B2CBNUSHU CHARACTER-1B2CCNU" +
"SHU CHARACTER-1B2CDNUSHU CHARACTER-1B2CENUSHU CHARACTER-1B2CFNUSHU CHARA" +
"CTER-1B2D0NUSHU CHARACTER-1B2D1NUSHU CHARACTER-1B2D2NUSHU CHARACTER-1B2D" +
"3NUSHU CHARACTER-1B2D4NUSHU CHARACTER-1B2D5NUSHU CHARACTER-1B2D6NUSHU CH" +
"ARACTER-1B2D7NUSHU CHARACTER-1B2D8NUSHU CHARACTER-1B2D9NUSHU CHARACTER-1" +
"B2DANUSHU CHARACTER-1B2DBNUSHU CHARACTER-1B2DCNUSHU CHARACTER-1B2DDNUSHU" +
" CHARACTER-1B2DENUSHU CHARACTER-1B2DFNUSHU CHARACTER-1B2E0NUSHU CHARACTE" +
"R-1B2E1NUSHU CHARACTER-1B2E2NUSHU CHARACTER-1B2E3NUSHU CHARACTER-1B2E4NU" +
"SHU CHARACTER-1B2E5NUSHU CHARACTER-1B2E6NUSHU CHARACTER-1B2E7NUSHU CHARA" +
"CTER-1B2E8NUSHU CHARACTER-1B2E9NUSHU CHARACTER-1B2EANUSHU CHARACTER-1B2E" +
"BNUSHU CHARACTER-1B2ECNUSHU CHARACTER-1B2EDNUSHU CHARACTER-1B2EENUSHU CH" +
"ARACTER-1B2EFNUSHU CHARACTER-1B2F0NUSHU CHARACTER-1B2F1NUSHU CHARACTER-1" +
"B2F2NUSHU CHARACTER-1B2F3NUSHU CHARACTER-1B2F4NUSHU CHARACTER-1B2F5NUSHU" +
" CHARACTER-1B2F6NUSHU CHARACTER-1B2F7NUSHU CHARACTER-1B2F8NUSHU CHARACTE" +
"R-1B2F9NUSHU CHARACTER-1B2FANUSHU CHARACTER-1B2FBDUPLOYAN LETTER HDUPLOY" +
"AN LETTER XDUPLOYAN LETTER PDUPLOYAN LETTER TDUPLOYAN LETTER FDUPLOYAN L" +
"ETTER KDUPLOYAN LETTER LDUPLOYAN LETTER BDUPLOYAN LETTER DDUPLOYAN LETTE" +
"R VDUPLOYAN LETTER GDUPLOYAN LETTER RDUPLOYAN LETTER P NDUPLOYAN LETTER " +
"D SDUPLOYAN LETTER F NDUPLOYAN LETTER K MDUPLOYAN LETTER R SDUPLOYAN LET" +
"TER THDUPLOYAN LETTER SLOAN DHDUPLOYAN LETTER DHDUPLOYAN LETTER KKDUPLOY" +
"AN LETTER SLOAN JDUPLOYAN LETTER HLDUPLOYAN LETTER LHDUPLOYAN LETTER RHD" +
"UPLOYAN LETTER MDUPLOYAN LETTER NDUPLOYAN LETTER JDUPLOYAN LETTER SDUPLO" +
"YAN LETTER M NDUPLOYAN LETTER N MDUPLOYAN LETTER J MDUPLOYAN LETTER S JD" +
"UPLOYAN LETTER M WITH DOTDUPLOYAN LETTER N WITH DOTDUPLOYAN LETTER J WIT" +
"H DOTDUPLOYAN LETTER J WITH DOTS INSIDE AND ABOVEDUPLOYAN LETTER S WITH " +
"DOTDUPLOYAN LETTER S WITH DOT BELOWDUPLOYAN LETTER M SDUPLOYAN LETTER N " +
"SDUPLOYAN LETTER J SDUPLOYAN LETTER S SDUPLOYAN LETTER M N SDUPLOYAN LET" +
"TER N M SDUPLOYAN LETTER J M SDUPLOYAN LETTER S J SDUPLOYAN LETTER J S W" +
"ITH DOTDUPLOYAN LETTER J NDUPLOYAN LETTER J N SDUPLOYAN LETTER S TDUPLOY" +
"AN LETTER S T RDUPLOYAN LETTER S PDUPLOYAN LETTER S P RDUPLOYAN LETTER T" +
" SDUPLOYAN LETTER T R SDUPLOYAN LETTER WDUPLOYAN LETTER WHDUPLOYAN LETTE" +
"R W RDUPLOYAN LETTER S NDUPLOYAN LETTER S MDUPLOYAN LETTER K R SDUPLOYAN" +
" LETTER G R SDUPLOYAN LETTER S KDUPLOYAN LETTER S K RDUPLOYAN LETTER ADU" +
"PLOYAN LETTER SLOAN OWDUPLOYAN LETTER OADUPLOYAN LETTER ODUPLOYAN LETTER" +
" AOUDUPLOYAN LETTER IDUPLOYAN LETTER EDUPLOYAN LETTER IEDUPLOYAN LETTER " +
"SHORT IDUPLOYAN LETTER UIDUPLOYAN LETTER EEDUPLOYAN LETTER SLOAN EHDUPLO" +
"YAN LETTER ROMANIAN IDUPLOYAN LETTER SLOAN EEDUPLOYAN LETTER LONG IDUPLO" +
"YAN LETTER YEDUPLOYAN LETTER UDUPLOYAN LETTER EUDUPLOYAN LETTER XWDUPLOY" +
"AN LETTER U NDUPLOYAN LETTER LONG UDUPLOYAN LETTER ROMANIAN UDUPLOYAN LE" +
"TTER UHDUPLOYAN LETTER SLOAN UDUPLOYAN LETTER OOHDUPLOYAN LETTER OWDUPLO" +
"YAN LETTER OUDUPLOYAN LETTER WADUPLOYAN LETTER WODUPLOYAN LETTER WIDUPLO" +
"YAN LETTER WEIDUPLOYAN LETTER WOWDUPLOYAN LETTER NASAL UDUPLOYAN LETTER " +
"NASAL ODUPLOYAN LETTER NASAL IDUPLOYAN LETTER NASAL ADUPLOYAN LETTER PER" +
"NIN ANDUPLOYAN LETTER PERNIN AMDUPLOYAN LETTER SLOAN ENDUPLOYAN LETTER S" +
"LOAN ANDUPLOYAN LETTER SLOAN ONDUPLOYAN LETTER VOCALIC MDUPLOYAN AFFIX L" +
"EFT HORIZONTAL SECANTDUPLOYAN AFFIX MID HORIZONTAL SECANTDUPLOYAN AFFIX " +
"RIGHT HORIZONTAL SECANTDUPLOYAN AFFIX LOW VERTICAL SECANTDUPLOYAN AFFIX " +
"MID VERTICAL SECANTDUPLOYAN AFFIX HIGH VERTICAL SECANTDUPLOYAN AFFIX ATT" +
"ACHED SECANTDUPLOYAN AFFIX ATTACHED LEFT-TO-RIGHT SECANTDUPLOYAN AFFIX A" +
"TTACHED TANGENTDUPLOYAN AFFIX ATTACHED TAILDUPLOYAN AFFIX ATTACHED E HOO" +
"KDUPLOYAN AFFIX ATTACHED I HOOKDUPLOYAN AFFIX ATTACHED TANGENT HOOKDUPLO" +
"YAN AFFIX HIGH ACUTEDUPLOYAN AFFIX HIGH TIGHT ACUTEDUPLOYAN AFFIX HIGH G" +
"RAVEDUPLOYAN AFFIX HIGH LONG GRAVEDUPLOYAN AFFIX HIGH DOTDUPLOYAN AFFIX " +
"HIGH CIRCLEDUPLOYAN AFFIX HIGH LINEDUPLOYAN AFFIX HIGH WAVEDUPLOYAN AFFI" +
"X HIGH VERTICALDUPLOYAN AFFIX LOW ACUTEDUPLOYAN AFFIX LOW TIGHT ACUTEDUP" +
"LOYAN AFFIX LOW GRAVEDUPLOYAN AFFIX LOW LONG GRAVEDUPLOYAN AFFIX LOW DOT") + ("" +
"DUPLOYAN AFFIX LOW CIRCLEDUPLOYAN AFFIX LOW LINEDUPLOYAN AFFIX LOW WAVED" +
"UPLOYAN AFFIX LOW VERTICALDUPLOYAN AFFIX LOW ARROWDUPLOYAN SIGN O WITH C" +
"ROSSDUPLOYAN THICK LETTER SELECTORDUPLOYAN DOUBLE MARKDUPLOYAN PUNCTUATI" +
"ON CHINOOK FULL STOPSHORTHAND FORMAT LETTER OVERLAPSHORTHAND FORMAT CONT" +
"INUING OVERLAPSHORTHAND FORMAT DOWN STEPSHORTHAND FORMAT UP STEPUP-POINT" +
"ING GO-KARTRIGHT-POINTING GO-KARTLEFT-POINTING STICK FIGURERIGHT-POINTIN" +
"G STICK FIGUREDOWN-POINTING STICK FIGURELOWER HORIZONTAL RULER SEGMENTRI" +
"GHT VERTICAL RULER SEGMENTLOWER RIGHT RULER SEGMENTANTENNAHORIZONTAL RES" +
"ISTOR SEGMENTVERTICAL RESISTOR SEGMENTLEFT THIRD INDUCTORMIDDLE THIRD IN" +
"DUCTORRIGHT THIRD INDUCTORLEFT-POINTING DIODERIGHT-POINTING DIODENPN TRA" +
"NSISTORPNP TRANSISTORRECEPTACLEHORIZONTAL CAPACITORVERTICAL CAPACITORLOG" +
"IC GATE ORLOGIC GATE ANDLOGIC GATE INVERTED INPUTSLOGIC GATE INVERTED OU" +
"TPUTLOGIC GATE BUFFERLOGIC GATE BUFFER WITH INVERTED INPUTBOX DRAWINGS L" +
"IGHT HORIZONTAL AND UPPER RIGHTBOX DRAWINGS LIGHT HORIZONTAL AND LOWER R" +
"IGHTBOX DRAWINGS LIGHT TOP AND UPPER LEFTBOX DRAWINGS LIGHT BOTTOM AND L" +
"OWER LEFTBOX DRAWINGS DOUBLE DIAGONAL UPPER RIGHT TO LOWER LEFTBOX DRAWI" +
"NGS DOUBLE DIAGONAL UPPER LEFT TO LOWER RIGHTSEPARATED BLOCK QUADRANT-1S" +
"EPARATED BLOCK QUADRANT-2SEPARATED BLOCK QUADRANT-12SEPARATED BLOCK QUAD" +
"RANT-3SEPARATED BLOCK QUADRANT-13SEPARATED BLOCK QUADRANT-23SEPARATED BL" +
"OCK QUADRANT-123SEPARATED BLOCK QUADRANT-4SEPARATED BLOCK QUADRANT-14SEP" +
"ARATED BLOCK QUADRANT-24SEPARATED BLOCK QUADRANT-124SEPARATED BLOCK QUAD" +
"RANT-34SEPARATED BLOCK QUADRANT-134SEPARATED BLOCK QUADRANT-234SEPARATED" +
" BLOCK QUADRANT-1234UPPER LEFT TWELFTH CIRCLEUPPER CENTRE LEFT TWELFTH C" +
"IRCLEUPPER CENTRE RIGHT TWELFTH CIRCLEUPPER RIGHT TWELFTH CIRCLEUPPER MI" +
"DDLE LEFT TWELFTH CIRCLEUPPER LEFT QUARTER CIRCLEUPPER RIGHT QUARTER CIR" +
"CLEUPPER MIDDLE RIGHT TWELFTH CIRCLELOWER MIDDLE LEFT TWELFTH CIRCLELOWE" +
"R LEFT QUARTER CIRCLELOWER RIGHT QUARTER CIRCLELOWER MIDDLE RIGHT TWELFT" +
"H CIRCLELOWER LEFT TWELFTH CIRCLELOWER CENTRE LEFT TWELFTH CIRCLELOWER C" +
"ENTRE RIGHT TWELFTH CIRCLELOWER RIGHT TWELFTH CIRCLESPARSE HORIZONTAL FI" +
"LLSPARSE VERTICAL FILLORTHOGONAL CROSSHATCH FILLDIAGONAL CROSSHATCH FILL" +
"DENSE VERTICAL FILLDENSE HORIZONTAL FILLSPECKLE FILL FRAME-1SPECKLE FILL" +
" FRAME-2LEFT-FACING BASSINETRIGHT-FACING BASSINETFLYING SAUCER WITH BEAM" +
"SFLYING SAUCER WITHOUT BEAMSALIEN MONSTER OPEN JAWSALIEN MONSTER CLOSED " +
"JAWSALIEN SQUID OPEN TENTACLESALIEN SQUID CLOSED TENTACLESALIEN CRAB STE" +
"PPING RIGHTALIEN CRAB STEPPING LEFTALIEN SPIDER CROUCHINGALIEN SPIDER SP" +
"READALIEN MONSTER STEP-1ALIEN MONSTER STEP-2LEFT-POINTING ROCKET SHIPUP-" +
"POINTING ROCKET SHIPRIGHT-POINTING ROCKET SHIPDOWN-POINTING ROCKET SHIPT" +
"OP HALF LEFT-FACING ROBOTTOP HALF FORWARD-FACING ROBOTTOP HALF RIGHT-FAC" +
"ING ROBOTBOTTOM HALF LEFT-FACING ROBOTBOTTOM HALF FORWARD-FACING ROBOTBO" +
"TTOM HALF RIGHT-FACING ROBOTLEFT-POINTING ATOMIC BOMBUP-POINTING ATOMIC " +
"BOMBRIGHT-POINTING ATOMIC BOMBDOWN-POINTING ATOMIC BOMBMUSHROOM CLOUDLEF" +
"T-POINTING RIFLEUP-POINTING RIFLERIGHT-POINTING RIFLEDOWN-POINTING RIFLE" +
"EIGHT RAYS INWARDEIGHT RAYS OUTWARDBLACK LARGE CIRCLE MINUS LEFT QUARTER" +
" SECTIONBLACK LARGE CIRCLE MINUS UPPER QUARTER SECTIONBLACK LARGE CIRCLE" +
" MINUS RIGHT QUARTER SECTIONBLACK LARGE CIRCLE MINUS LOWER QUARTER SECTI" +
"ONBLACK NEUTRAL FACELEFT-FACING SNAKE HEAD WITH OPEN MOUTHUP-FACING SNAK" +
"E HEAD WITH OPEN MOUTHRIGHT-FACING SNAKE HEAD WITH OPEN MOUTHDOWN-FACING" +
" SNAKE HEAD WITH OPEN MOUTHLEFT-FACING SNAKE HEAD WITH CLOSED MOUTHUP-FA" +
"CING SNAKE HEAD WITH CLOSED MOUTHRIGHT-FACING SNAKE HEAD WITH CLOSED MOU" +
"THDOWN-FACING SNAKE HEAD WITH CLOSED MOUTHLEFT-POINTING ENERGY WAVEUP-PO" +
"INTING ENERGY WAVERIGHT-POINTING ENERGY WAVEDOWN-POINTING ENERGY WAVESQU" +
"ARE SPIRAL FROM TOP LEFTSQUARE SPIRAL FROM TOP RIGHTSQUARE SPIRAL FROM B" +
"OTTOM RIGHTSQUARE SPIRAL FROM BOTTOM LEFTSTRIPED LEFT-POINTING TRIANGLES" +
"TRIPED UP-POINTING TRIANGLESTRIPED RIGHT-POINTING TRIANGLESTRIPED DOWN-P" +
"OINTING TRIANGLEVERTICAL LADDERHORIZONTAL LADDERWHITE LOWER LEFT POINTER" +
"WHITE LOWER RIGHT POINTERTWO RINGS ALIGNED HORIZONTALLYSQUARE FOUR CORNE" +
"R SALTIRESSQUARE FOUR CORNER DIAGONALSSQUARE FOUR CORNER BLACK TRIANGLES" +
"SQUARE APERTUREINVERSE BLACK DIAMONDLEFT AND UPPER ONE EIGHTH BLOCK CONT" +
"AINING BLACK SMALL SQUAREINVERSE BLACK SMALL SQUAREVERTICAL LINE WITH FO" +
"UR TICK MARKSHORIZONTAL LINE WITH FOUR TICK MARKSLEFT-FACING FISHRIGHT-F" +
"ACING FISHLEFT-FACING FISH WITH OPEN MOUTHRIGHT-FACING FISH WITH OPEN MO" +
"UTHFLAPPING BIRDLEFT-POINTING RACING CARUP-POINTING RACING CARRIGHT-POIN" +
"TING RACING CARDOWN-POINTING RACING CARHORIZONTAL RACING CARVERTICAL RAC" +
"ING CARVERTICAL GO-KARTLEFT-POINTING TANKRIGHT-POINTING TANKLEFT-POINTIN") + ("" +
"G ROCKET BOOSTERRIGHT-POINTING ROCKET BOOSTERLEFT-POINTING ROLLER COASTE" +
"R CARRIGHT-POINTING ROLLER COASTER CARLEFT HALF FLYING SAUCERRIGHT HALF " +
"FLYING SAUCERUPPER LEFT QUADRANT FACE WITH OPEN EYESUPPER RIGHT QUADRANT" +
" FACE WITH OPEN EYESUPPER LEFT QUADRANT FACE WITH CLOSED EYESUPPER RIGHT" +
" QUADRANT FACE WITH CLOSED EYESLOWER LEFT QUADRANT SMILING FACELOWER RIG" +
"HT QUADRANT SMILING FACELOWER LEFT QUADRANT NEUTRAL FACELOWER RIGHT QUAD" +
"RANT NEUTRAL FACELOWER LEFT QUADRANT FACE WITH OPEN MOUTHLOWER RIGHT QUA" +
"DRANT FACE WITH OPEN MOUTHLOWER LEFT QUADRANT FROWNING FACELOWER RIGHT Q" +
"UADRANT FROWNING FACEUPPER LEFT QUADRANT TELEVISIONUPPER RIGHT QUADRANT " +
"TELEVISIONLOWER LEFT QUADRANT TELEVISIONLOWER RIGHT QUADRANT TELEVISIONU" +
"PPER LEFT QUADRANT MICROCOMPUTERUPPER RIGHT QUADRANT MICROCOMPUTERLOWER " +
"LEFT QUADRANT MICROCOMPUTERLOWER RIGHT QUADRANT MICROCOMPUTERUPPER LEFT " +
"QUADRANT CHESS KINGUPPER RIGHT QUADRANT CHESS KINGLOWER LEFT QUADRANT CH" +
"ESS KINGLOWER RIGHT QUADRANT CHESS KINGUPPER LEFT QUADRANT CHESS QUEENUP" +
"PER RIGHT QUADRANT CHESS QUEENLOWER LEFT QUADRANT CHESS QUEENLOWER RIGHT" +
" QUADRANT CHESS QUEENUPPER LEFT QUADRANT CHESS ROOKUPPER RIGHT QUADRANT " +
"CHESS ROOKLOWER LEFT QUADRANT CHESS ROOKLOWER RIGHT QUADRANT CHESS ROOKU" +
"PPER LEFT QUADRANT CHESS BISHOPUPPER RIGHT QUADRANT CHESS BISHOPLOWER LE" +
"FT QUADRANT CHESS BISHOPLOWER RIGHT QUADRANT CHESS BISHOPUPPER LEFT QUAD" +
"RANT CHESS KNIGHTUPPER RIGHT QUADRANT CHESS KNIGHTLOWER LEFT QUADRANT CH" +
"ESS KNIGHTLOWER RIGHT QUADRANT CHESS KNIGHTUPPER LEFT QUADRANT CHESS PAW" +
"NUPPER RIGHT QUADRANT CHESS PAWNLOWER LEFT QUADRANT CHESS PAWNLOWER RIGH" +
"T QUADRANT CHESS PAWNUPPER LEFT QUADRANT STANDING KNIGHTUPPER RIGHT QUAD" +
"RANT STANDING KNIGHTLOWER LEFT QUADRANT STANDING KNIGHTLOWER RIGHT QUADR" +
"ANT STANDING KNIGHTOUTLINED LATIN CAPITAL LETTER AOUTLINED LATIN CAPITAL" +
" LETTER BOUTLINED LATIN CAPITAL LETTER COUTLINED LATIN CAPITAL LETTER DO" +
"UTLINED LATIN CAPITAL LETTER EOUTLINED LATIN CAPITAL LETTER FOUTLINED LA" +
"TIN CAPITAL LETTER GOUTLINED LATIN CAPITAL LETTER HOUTLINED LATIN CAPITA" +
"L LETTER IOUTLINED LATIN CAPITAL LETTER JOUTLINED LATIN CAPITAL LETTER K" +
"OUTLINED LATIN CAPITAL LETTER LOUTLINED LATIN CAPITAL LETTER MOUTLINED L" +
"ATIN CAPITAL LETTER NOUTLINED LATIN CAPITAL LETTER OOUTLINED LATIN CAPIT" +
"AL LETTER POUTLINED LATIN CAPITAL LETTER QOUTLINED LATIN CAPITAL LETTER " +
"ROUTLINED LATIN CAPITAL LETTER SOUTLINED LATIN CAPITAL LETTER TOUTLINED " +
"LATIN CAPITAL LETTER UOUTLINED LATIN CAPITAL LETTER VOUTLINED LATIN CAPI" +
"TAL LETTER WOUTLINED LATIN CAPITAL LETTER XOUTLINED LATIN CAPITAL LETTER" +
" YOUTLINED LATIN CAPITAL LETTER ZOUTLINED DIGIT ZEROOUTLINED DIGIT ONEOU" +
"TLINED DIGIT TWOOUTLINED DIGIT THREEOUTLINED DIGIT FOUROUTLINED DIGIT FI" +
"VEOUTLINED DIGIT SIXOUTLINED DIGIT SEVENOUTLINED DIGIT EIGHTOUTLINED DIG" +
"IT NINESNAKE SYMBOLFLYING SAUCER SYMBOLNOSE SYMBOLBLOCK OCTANT-3BLOCK OC" +
"TANT-23BLOCK OCTANT-123BLOCK OCTANT-4BLOCK OCTANT-14BLOCK OCTANT-124BLOC" +
"K OCTANT-34BLOCK OCTANT-134BLOCK OCTANT-234BLOCK OCTANT-5BLOCK OCTANT-15" +
"BLOCK OCTANT-25BLOCK OCTANT-125BLOCK OCTANT-135BLOCK OCTANT-235BLOCK OCT" +
"ANT-1235BLOCK OCTANT-45BLOCK OCTANT-145BLOCK OCTANT-245BLOCK OCTANT-1245" +
"BLOCK OCTANT-345BLOCK OCTANT-1345BLOCK OCTANT-2345BLOCK OCTANT-12345BLOC" +
"K OCTANT-6BLOCK OCTANT-16BLOCK OCTANT-26BLOCK OCTANT-126BLOCK OCTANT-36B" +
"LOCK OCTANT-136BLOCK OCTANT-236BLOCK OCTANT-1236BLOCK OCTANT-146BLOCK OC" +
"TANT-246BLOCK OCTANT-1246BLOCK OCTANT-346BLOCK OCTANT-1346BLOCK OCTANT-2" +
"346BLOCK OCTANT-12346BLOCK OCTANT-56BLOCK OCTANT-156BLOCK OCTANT-256BLOC" +
"K OCTANT-1256BLOCK OCTANT-356BLOCK OCTANT-1356BLOCK OCTANT-2356BLOCK OCT" +
"ANT-12356BLOCK OCTANT-456BLOCK OCTANT-1456BLOCK OCTANT-2456BLOCK OCTANT-" +
"12456BLOCK OCTANT-3456BLOCK OCTANT-13456BLOCK OCTANT-23456BLOCK OCTANT-1" +
"7BLOCK OCTANT-27BLOCK OCTANT-127BLOCK OCTANT-37BLOCK OCTANT-137BLOCK OCT" +
"ANT-237BLOCK OCTANT-1237BLOCK OCTANT-47BLOCK OCTANT-147BLOCK OCTANT-247B" +
"LOCK OCTANT-1247BLOCK OCTANT-347BLOCK OCTANT-1347BLOCK OCTANT-2347BLOCK " +
"OCTANT-12347BLOCK OCTANT-157BLOCK OCTANT-257BLOCK OCTANT-1257BLOCK OCTAN" +
"T-357BLOCK OCTANT-2357BLOCK OCTANT-12357BLOCK OCTANT-457BLOCK OCTANT-145" +
"7BLOCK OCTANT-12457BLOCK OCTANT-3457BLOCK OCTANT-13457BLOCK OCTANT-23457" +
"BLOCK OCTANT-67BLOCK OCTANT-167BLOCK OCTANT-267BLOCK OCTANT-1267BLOCK OC" +
"TANT-367BLOCK OCTANT-1367BLOCK OCTANT-2367BLOCK OCTANT-12367BLOCK OCTANT" +
"-467BLOCK OCTANT-1467BLOCK OCTANT-2467BLOCK OCTANT-12467BLOCK OCTANT-346" +
"7BLOCK OCTANT-13467BLOCK OCTANT-23467BLOCK OCTANT-123467BLOCK OCTANT-567" +
"BLOCK OCTANT-1567BLOCK OCTANT-2567BLOCK OCTANT-12567BLOCK OCTANT-3567BLO" +
"CK OCTANT-13567BLOCK OCTANT-23567BLOCK OCTANT-123567BLOCK OCTANT-4567BLO" +
"CK OCTANT-14567BLOCK OCTANT-24567BLOCK OCTANT-124567BLOCK OCTANT-34567BL") + ("" +
"OCK OCTANT-134567BLOCK OCTANT-234567BLOCK OCTANT-1234567BLOCK OCTANT-18B" +
"LOCK OCTANT-28BLOCK OCTANT-128BLOCK OCTANT-38BLOCK OCTANT-138BLOCK OCTAN" +
"T-238BLOCK OCTANT-1238BLOCK OCTANT-48BLOCK OCTANT-148BLOCK OCTANT-248BLO" +
"CK OCTANT-1248BLOCK OCTANT-348BLOCK OCTANT-1348BLOCK OCTANT-2348BLOCK OC" +
"TANT-12348BLOCK OCTANT-58BLOCK OCTANT-158BLOCK OCTANT-258BLOCK OCTANT-12" +
"58BLOCK OCTANT-358BLOCK OCTANT-1358BLOCK OCTANT-2358BLOCK OCTANT-12358BL" +
"OCK OCTANT-458BLOCK OCTANT-1458BLOCK OCTANT-2458BLOCK OCTANT-12458BLOCK " +
"OCTANT-3458BLOCK OCTANT-13458BLOCK OCTANT-23458BLOCK OCTANT-123458BLOCK " +
"OCTANT-168BLOCK OCTANT-268BLOCK OCTANT-1268BLOCK OCTANT-368BLOCK OCTANT-" +
"2368BLOCK OCTANT-12368BLOCK OCTANT-468BLOCK OCTANT-1468BLOCK OCTANT-1246" +
"8BLOCK OCTANT-3468BLOCK OCTANT-13468BLOCK OCTANT-23468BLOCK OCTANT-568BL" +
"OCK OCTANT-1568BLOCK OCTANT-2568BLOCK OCTANT-12568BLOCK OCTANT-3568BLOCK" +
" OCTANT-13568BLOCK OCTANT-23568BLOCK OCTANT-123568BLOCK OCTANT-4568BLOCK" +
" OCTANT-14568BLOCK OCTANT-24568BLOCK OCTANT-124568BLOCK OCTANT-34568BLOC" +
"K OCTANT-134568BLOCK OCTANT-234568BLOCK OCTANT-1234568BLOCK OCTANT-178BL" +
"OCK OCTANT-278BLOCK OCTANT-1278BLOCK OCTANT-378BLOCK OCTANT-1378BLOCK OC" +
"TANT-2378BLOCK OCTANT-12378BLOCK OCTANT-478BLOCK OCTANT-1478BLOCK OCTANT" +
"-2478BLOCK OCTANT-12478BLOCK OCTANT-3478BLOCK OCTANT-13478BLOCK OCTANT-2" +
"3478BLOCK OCTANT-123478BLOCK OCTANT-578BLOCK OCTANT-1578BLOCK OCTANT-257" +
"8BLOCK OCTANT-12578BLOCK OCTANT-3578BLOCK OCTANT-13578BLOCK OCTANT-23578" +
"BLOCK OCTANT-123578BLOCK OCTANT-4578BLOCK OCTANT-14578BLOCK OCTANT-24578" +
"BLOCK OCTANT-124578BLOCK OCTANT-34578BLOCK OCTANT-134578BLOCK OCTANT-234" +
"578BLOCK OCTANT-1234578BLOCK OCTANT-678BLOCK OCTANT-1678BLOCK OCTANT-267" +
"8BLOCK OCTANT-12678BLOCK OCTANT-3678BLOCK OCTANT-13678BLOCK OCTANT-23678" +
"BLOCK OCTANT-123678BLOCK OCTANT-4678BLOCK OCTANT-14678BLOCK OCTANT-24678" +
"BLOCK OCTANT-124678BLOCK OCTANT-34678BLOCK OCTANT-134678BLOCK OCTANT-234" +
"678BLOCK OCTANT-1234678BLOCK OCTANT-15678BLOCK OCTANT-25678BLOCK OCTANT-" +
"125678BLOCK OCTANT-35678BLOCK OCTANT-235678BLOCK OCTANT-1235678BLOCK OCT" +
"ANT-45678BLOCK OCTANT-145678BLOCK OCTANT-1245678BLOCK OCTANT-1345678BLOC" +
"K OCTANT-2345678TOP HALF STANDING PERSONBOTTOM HALF STANDING PERSONTOP H" +
"ALF RIGHT-FACING RUNNER FRAME-1BOTTOM HALF RIGHT-FACING RUNNER FRAME-1TO" +
"P HALF RIGHT-FACING RUNNER FRAME-2BOTTOM HALF RIGHT-FACING RUNNER FRAME-" +
"2TOP HALF LEFT-FACING RUNNER FRAME-1BOTTOM HALF LEFT-FACING RUNNER FRAME" +
"-1TOP HALF LEFT-FACING RUNNER FRAME-2BOTTOM HALF LEFT-FACING RUNNER FRAM" +
"E-2TOP HALF FORWARD-FACING RUNNERBOTTOM HALF FORWARD-FACING RUNNER FRAME" +
"-1BOTTOM HALF FORWARD-FACING RUNNER FRAME-2BOTTOM HALF FORWARD-FACING RU" +
"NNER FRAME-3BOTTOM HALF FORWARD-FACING RUNNER FRAME-4MOON LANDERTOP HALF" +
" FLAILING ROBOT FRAME-1TOP HALF FLAILING ROBOT FRAME-2DOWN-POINTING AIRP" +
"LANELEFT-POINTING AIRPLANESMALL UP-POINTING AIRPLANEUP-POINTING FROGDOWN" +
"-POINTING FROGEXPLOSION FRAME-1EXPLOSION FRAME-2EXPLOSION FRAME-3RIGHT H" +
"ALF AND LEFT HALF WHITE CIRCLELOWER HALF AND UPPER HALF WHITE CIRCLEEXPL" +
"OSION AT HORIZONUPPER HALF HEAVY WHITE SQUARELOWER HALF HEAVY WHITE SQUA" +
"REHEAVY WHITE SQUARE CONTAINING BLACK VERY SMALL SQUAREWHITE VERTICAL RE" +
"CTANGLE WITH HORIZONTAL BARTOP LEFT BLACK LEFT-POINTING SMALL TRIANGLEFU" +
"NNELBOX DRAWINGS DOUBLE DIAGONAL LOWER LEFT TO MIDDLE CENTRE TO LOWER RI" +
"GHTBOX DRAWINGS DOUBLE DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO UPPER RIG" +
"HTLEFT HALF WHITE ELLIPSERIGHT HALF WHITE ELLIPSELEFT HALF TRIPLE DASH H" +
"ORIZONTALRIGHT HALF TRIPLE DASH HORIZONTALHORIZONTAL LINE WITH TICK MARK" +
"LEFT HALF HORIZONTAL LINE WITH THREE TICK MARKSRIGHT HALF HORIZONTAL LIN" +
"E WITH THREE TICK MARKSHORIZONTAL LINE WITH THREE TICK MARKSLOWER HALF V" +
"ERTICAL LINE WITH THREE TICK MARKSUPPER HALF VERTICAL LINE WITH THREE TI" +
"CK MARKSVERTICAL LINE WITH THREE TICK MARKSBOX DRAWINGS LIGHT VERTICAL A" +
"ND TOP RIGHTBOX DRAWINGS LIGHT VERTICAL AND BOTTOM RIGHTBOX DRAWINGS LIG" +
"HT VERTICAL AND TOP LEFTBOX DRAWINGS LIGHT VERTICAL AND BOTTOM LEFTLARGE" +
" TYPE PIECE UPPER LEFT ARCLARGE TYPE PIECE UPPER LEFT CORNERLARGE TYPE P" +
"IECE UPPER TERMINALLARGE TYPE PIECE UPPER LEFT CROTCHLARGE TYPE PIECE LE" +
"FT ARMLARGE TYPE PIECE CROSSBARLARGE TYPE PIECE CROSSBAR WITH LOWER STEM" +
"LARGE TYPE PIECE UPPER HALF VERTEX OF MLARGE TYPE PIECE DIAGONAL LOWER L" +
"EFTLARGE TYPE PIECE SHORT UPPER TERMINALLARGE TYPE PIECE UPPER RIGHT ARC" +
"LARGE TYPE PIECE RIGHT ARMLARGE TYPE PIECE UPPER RIGHT CROTCHLARGE TYPE " +
"PIECE UPPER RIGHT CORNERLARGE TYPE PIECE STEM WITH RIGHT CROSSBARLARGE T" +
"YPE PIECE STEMLARGE TYPE PIECE DIAGONAL UPPER RIGHT AND LOWER RIGHTLARGE" +
" TYPE PIECE DIAGONAL UPPER RIGHTLARGE TYPE PIECE DIAGONAL LOWER RIGHTLAR" +
"GE TYPE PIECE SHORT LOWER TERMINALLARGE TYPE PIECE LOWER LEFT AND UPPER ") + ("" +
"LEFT ARCLARGE TYPE PIECE CENTRE OF KLARGE TYPE PIECE LOWER HALF VERTEX O" +
"F MLARGE TYPE PIECE UPPER HALF VERTEX OF WLARGE TYPE PIECE CENTRE OF XLA" +
"RGE TYPE PIECE CENTRE OF YLARGE TYPE PIECE CENTRE OF Z WITH CROSSBARLARG" +
"E TYPE PIECE RAISED UPPER LEFT ARCLARGE TYPE PIECE STEM WITH LEFT CROSSB" +
"ARLARGE TYPE PIECE LOWER RIGHT AND UPPER RIGHT ARCLARGE TYPE PIECE DIAGO" +
"NAL UPPER LEFT AND LOWER LEFTLARGE TYPE PIECE STEM WITH LEFT JOINTLARGE " +
"TYPE PIECE STEM WITH CROSSBARLARGE TYPE PIECE DIAGONAL UPPER LEFTLARGE T" +
"YPE PIECE LOWER TERMINALLARGE TYPE PIECE LOWER LEFT CORNERLARGE TYPE PIE" +
"CE LOWER LEFT ARCLARGE TYPE PIECE LOWER LEFT CROTCHLARGE TYPE PIECE CROS" +
"SBAR WITH UPPER STEMLARGE TYPE PIECE VERTEX OF VLARGE TYPE PIECE LOWER H" +
"ALF VERTEX OF WLARGE TYPE PIECE LOWER RIGHT ARCLARGE TYPE PIECE LOWER RI" +
"GHT CORNERLARGE TYPE PIECE LOWER RIGHT ARC WITH TAILLARGE TYPE PIECE LOW" +
"ER RIGHT CROTCHLARGE TYPE PIECE STEM-45LARGE TYPE PIECE STEM-2345LARGE T" +
"YPE PIECE STEM-4LARGE TYPE PIECE STEM-34LARGE TYPE PIECE STEM-234LARGE T" +
"YPE PIECE STEM-1234LARGE TYPE PIECE STEM-3LARGE TYPE PIECE STEM-23LARGE " +
"TYPE PIECE STEM-2LARGE TYPE PIECE STEM-12SEPARATED BLOCK SEXTANT-1SEPARA" +
"TED BLOCK SEXTANT-2SEPARATED BLOCK SEXTANT-12SEPARATED BLOCK SEXTANT-3SE" +
"PARATED BLOCK SEXTANT-13SEPARATED BLOCK SEXTANT-23SEPARATED BLOCK SEXTAN" +
"T-123SEPARATED BLOCK SEXTANT-4SEPARATED BLOCK SEXTANT-14SEPARATED BLOCK " +
"SEXTANT-24SEPARATED BLOCK SEXTANT-124SEPARATED BLOCK SEXTANT-34SEPARATED" +
" BLOCK SEXTANT-134SEPARATED BLOCK SEXTANT-234SEPARATED BLOCK SEXTANT-123" +
"4SEPARATED BLOCK SEXTANT-5SEPARATED BLOCK SEXTANT-15SEPARATED BLOCK SEXT" +
"ANT-25SEPARATED BLOCK SEXTANT-125SEPARATED BLOCK SEXTANT-35SEPARATED BLO" +
"CK SEXTANT-135SEPARATED BLOCK SEXTANT-235SEPARATED BLOCK SEXTANT-1235SEP" +
"ARATED BLOCK SEXTANT-45SEPARATED BLOCK SEXTANT-145SEPARATED BLOCK SEXTAN" +
"T-245SEPARATED BLOCK SEXTANT-1245SEPARATED BLOCK SEXTANT-345SEPARATED BL" +
"OCK SEXTANT-1345SEPARATED BLOCK SEXTANT-2345SEPARATED BLOCK SEXTANT-1234" +
"5SEPARATED BLOCK SEXTANT-6SEPARATED BLOCK SEXTANT-16SEPARATED BLOCK SEXT" +
"ANT-26SEPARATED BLOCK SEXTANT-126SEPARATED BLOCK SEXTANT-36SEPARATED BLO" +
"CK SEXTANT-136SEPARATED BLOCK SEXTANT-236SEPARATED BLOCK SEXTANT-1236SEP" +
"ARATED BLOCK SEXTANT-46SEPARATED BLOCK SEXTANT-146SEPARATED BLOCK SEXTAN" +
"T-246SEPARATED BLOCK SEXTANT-1246SEPARATED BLOCK SEXTANT-346SEPARATED BL" +
"OCK SEXTANT-1346SEPARATED BLOCK SEXTANT-2346SEPARATED BLOCK SEXTANT-1234" +
"6SEPARATED BLOCK SEXTANT-56SEPARATED BLOCK SEXTANT-156SEPARATED BLOCK SE" +
"XTANT-256SEPARATED BLOCK SEXTANT-1256SEPARATED BLOCK SEXTANT-356SEPARATE" +
"D BLOCK SEXTANT-1356SEPARATED BLOCK SEXTANT-2356SEPARATED BLOCK SEXTANT-" +
"12356SEPARATED BLOCK SEXTANT-456SEPARATED BLOCK SEXTANT-1456SEPARATED BL" +
"OCK SEXTANT-2456SEPARATED BLOCK SEXTANT-12456SEPARATED BLOCK SEXTANT-345" +
"6SEPARATED BLOCK SEXTANT-13456SEPARATED BLOCK SEXTANT-23456SEPARATED BLO" +
"CK SEXTANT-123456UPPER LEFT ONE SIXTEENTH BLOCKUPPER CENTRE LEFT ONE SIX" +
"TEENTH BLOCKUPPER CENTRE RIGHT ONE SIXTEENTH BLOCKUPPER RIGHT ONE SIXTEE" +
"NTH BLOCKUPPER MIDDLE LEFT ONE SIXTEENTH BLOCKUPPER MIDDLE CENTRE LEFT O" +
"NE SIXTEENTH BLOCKUPPER MIDDLE CENTRE RIGHT ONE SIXTEENTH BLOCKUPPER MID" +
"DLE RIGHT ONE SIXTEENTH BLOCKLOWER MIDDLE LEFT ONE SIXTEENTH BLOCKLOWER " +
"MIDDLE CENTRE LEFT ONE SIXTEENTH BLOCKLOWER MIDDLE CENTRE RIGHT ONE SIXT" +
"EENTH BLOCKLOWER MIDDLE RIGHT ONE SIXTEENTH BLOCKLOWER LEFT ONE SIXTEENT" +
"H BLOCKLOWER CENTRE LEFT ONE SIXTEENTH BLOCKLOWER CENTRE RIGHT ONE SIXTE" +
"ENTH BLOCKLOWER RIGHT ONE SIXTEENTH BLOCKRIGHT HALF LOWER ONE QUARTER BL" +
"OCKRIGHT THREE QUARTERS LOWER ONE QUARTER BLOCKLEFT THREE QUARTERS LOWER" +
" ONE QUARTER BLOCKLEFT HALF LOWER ONE QUARTER BLOCKLOWER HALF LEFT ONE Q" +
"UARTER BLOCKLOWER THREE QUARTERS LEFT ONE QUARTER BLOCKUPPER THREE QUART" +
"ERS LEFT ONE QUARTER BLOCKUPPER HALF LEFT ONE QUARTER BLOCKLEFT HALF UPP" +
"ER ONE QUARTER BLOCKLEFT THREE QUARTERS UPPER ONE QUARTER BLOCKRIGHT THR" +
"EE QUARTERS UPPER ONE QUARTER BLOCKRIGHT HALF UPPER ONE QUARTER BLOCKUPP" +
"ER HALF RIGHT ONE QUARTER BLOCKUPPER THREE QUARTERS RIGHT ONE QUARTER BL" +
"OCKLOWER THREE QUARTERS RIGHT ONE QUARTER BLOCKLOWER HALF RIGHT ONE QUAR" +
"TER BLOCKHORIZONTAL ZIGZAG LINEKEYHOLEOLD PERSONAL COMPUTER WITH MONITOR" +
" IN PORTRAIT ORIENTATIONBLACK RIGHT TRIANGLE CARETFRAGILE SYMBOLOFFICE B" +
"UILDING SYMBOLTREE SYMBOLAPPLE SYMBOLCHERRY SYMBOLSTRAWBERRY SYMBOLHEBEI" +
"RISFLORAMETISPARTHENOPEVICTORIAEGERIAIRENEEUNOMIAPSYCHETHETISMELPOMENEFO" +
"RTUNAASTRONOMICAL SYMBOL FOR ASTEROID PROSERPINABELLONAAMPHITRITELEUKOTH" +
"EAGEOMANTIC FIGURE POPULUSGEOMANTIC FIGURE TRISTITIAGEOMANTIC FIGURE ALB" +
"USGEOMANTIC FIGURE FORTUNA MAJORGEOMANTIC FIGURE RUBEUSGEOMANTIC FIGURE " +
"ACQUISITIOGEOMANTIC FIGURE CONJUNCTIOGEOMANTIC FIGURE CAPUT DRACONISGEOM") + ("" +
"ANTIC FIGURE LAETITIAGEOMANTIC FIGURE CARCERGEOMANTIC FIGURE AMISSIOGEOM" +
"ANTIC FIGURE PUELLAGEOMANTIC FIGURE FORTUNA MINORGEOMANTIC FIGURE PUERGE" +
"OMANTIC FIGURE CAUDA DRACONISGEOMANTIC FIGURE VIAMEDIUM SMALL WHITE CIRC" +
"LE WITH HORIZONTAL BARZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON" +
" LEFTZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFTZNAMENNY COMBINING M" +
"ARK TSATA ON LEFTZNAMENNY COMBINING MARK GORAZDO NIZKO ON LEFTZNAMENNY C" +
"OMBINING MARK NIZKO ON LEFTZNAMENNY COMBINING MARK SREDNE ON LEFTZNAMENN" +
"Y COMBINING MARK MALO POVYSHE ON LEFTZNAMENNY COMBINING MARK POVYSHE ON " +
"LEFTZNAMENNY COMBINING MARK VYSOKO ON LEFTZNAMENNY COMBINING MARK MALO P" +
"OVYSHE S KHOKHLOM ON LEFTZNAMENNY COMBINING MARK POVYSHE S KHOKHLOM ON L" +
"EFTZNAMENNY COMBINING MARK VYSOKO S KHOKHLOM ON LEFTZNAMENNY COMBINING M" +
"ARK GORAZDO NIZKO S KRYZHEM ON RIGHTZNAMENNY COMBINING MARK NIZKO S KRYZ" +
"HEM ON RIGHTZNAMENNY COMBINING MARK TSATA ON RIGHTZNAMENNY COMBINING MAR" +
"K GORAZDO NIZKO ON RIGHTZNAMENNY COMBINING MARK NIZKO ON RIGHTZNAMENNY C" +
"OMBINING MARK SREDNE ON RIGHTZNAMENNY COMBINING MARK MALO POVYSHE ON RIG" +
"HTZNAMENNY COMBINING MARK POVYSHE ON RIGHTZNAMENNY COMBINING MARK VYSOKO" +
" ON RIGHTZNAMENNY COMBINING MARK MALO POVYSHE S KHOKHLOM ON RIGHTZNAMENN" +
"Y COMBINING MARK POVYSHE S KHOKHLOM ON RIGHTZNAMENNY COMBINING MARK VYSO" +
"KO S KHOKHLOM ON RIGHTZNAMENNY COMBINING MARK TSATA S KRYZHEMZNAMENNY CO" +
"MBINING MARK MALO POVYSHE S KRYZHEMZNAMENNY COMBINING MARK STRANNO MALO " +
"POVYSHEZNAMENNY COMBINING MARK POVYSHE S KRYZHEMZNAMENNY COMBINING MARK " +
"POVYSHE STRANNOZNAMENNY COMBINING MARK VYSOKO S KRYZHEMZNAMENNY COMBININ" +
"G MARK MALO POVYSHE STRANNOZNAMENNY COMBINING MARK GORAZDO VYSOKOZNAMENN" +
"Y COMBINING MARK ZELOZNAMENNY COMBINING MARK ONZNAMENNY COMBINING MARK R" +
"AVNOZNAMENNY COMBINING MARK TIKHAYAZNAMENNY COMBINING MARK BORZAYAZNAMEN" +
"NY COMBINING MARK UDARKAZNAMENNY COMBINING MARK PODVERTKAZNAMENNY COMBIN" +
"ING MARK LOMKAZNAMENNY COMBINING MARK KUPNAYAZNAMENNY COMBINING MARK KAC" +
"HKAZNAMENNY COMBINING MARK ZEVOKZNAMENNY COMBINING MARK SKOBAZNAMENNY CO" +
"MBINING MARK RAZSEKAZNAMENNY COMBINING MARK KRYZH ON LEFTZNAMENNY COMBIN" +
"ING TONAL RANGE MARK MRACHNOZNAMENNY COMBINING TONAL RANGE MARK SVETLOZN" +
"AMENNY COMBINING TONAL RANGE MARK TRESVETLOZNAMENNY COMBINING MARK ZADER" +
"ZHKAZNAMENNY COMBINING MARK DEMESTVENNY ZADERZHKAZNAMENNY COMBINING MARK" +
" OTSECHKAZNAMENNY COMBINING MARK PODCHASHIEZNAMENNY COMBINING MARK PODCH" +
"ASHIE WITH VERTICAL STROKEZNAMENNY COMBINING MARK CHASHKAZNAMENNY COMBIN" +
"ING MARK CHASHKA POLNAYAZNAMENNY COMBINING MARK OBLACHKOZNAMENNY COMBINI" +
"NG MARK SOROCHYA NOZHKAZNAMENNY COMBINING MARK TOCHKAZNAMENNY COMBINING " +
"MARK DVOETOCHIEZNAMENNY COMBINING ATTACHING VERTICAL OMETZNAMENNY COMBIN" +
"ING MARK CURVED OMETZNAMENNY COMBINING MARK KRYZHZNAMENNY COMBINING LOWE" +
"R TONAL RANGE INDICATORZNAMENNY PRIZNAK MODIFIER LEVEL-2ZNAMENNY PRIZNAK" +
" MODIFIER LEVEL-3ZNAMENNY PRIZNAK MODIFIER DIRECTION FLIPZNAMENNY PRIZNA" +
"K MODIFIER KRYZHZNAMENNY PRIZNAK MODIFIER ROGZNAMENNY NEUME KRYUKZNAMENN" +
"Y NEUME KRYUK TIKHYZNAMENNY NEUME PARAKLITZNAMENNY NEUME DVA V CHELNUZNA" +
"MENNY NEUME KLYUCHZNAMENNY NEUME ZANOZHEKZNAMENNY NEUME STOPITSAZNAMENNY" +
" NEUME STOPITSA S OCHKOMZNAMENNY NEUME PEREVODKAZNAMENNY NEUME PEREVODKA" +
" NEPOSTOYANNAYAZNAMENNY NEUME STOPITSA WITH SOROCHYA NOZHKAZNAMENNY NEUM" +
"E CHELYUSTKAZNAMENNY NEUME PALKAZNAMENNY NEUME ZAPYATAYAZNAMENNY NEUME G" +
"OLUBCHIK BORZYZNAMENNY NEUME GOLUBCHIK TIKHYZNAMENNY NEUME GOLUBCHIK MRA" +
"CHNYZNAMENNY NEUME GOLUBCHIK SVETLYZNAMENNY NEUME GOLUBCHIK TRESVETLYZNA" +
"MENNY NEUME VRAKHIYA PROSTAYAZNAMENNY NEUME VRAKHIYA MRACHNAYAZNAMENNY N" +
"EUME VRAKHIYA SVETLAYAZNAMENNY NEUME VRAKHIYA TRESVETLAYAZNAMENNY NEUME " +
"VRAKHIYA KLYUCHEVAYA PROSTAYAZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA MRACHNA" +
"YAZNAMENNY NEUME VRAKHIYA KLYUCHEVAYA SVETLAYAZNAMENNY NEUME VRAKHIYA KL" +
"YUCHEVAYA TRESVETLAYAZNAMENNY NEUME DOUBLE ZAPYATAYAZNAMENNY NEUME REVER" +
"SED CHELYUSTKAZNAMENNY NEUME DERBITSAZNAMENNY NEUME KHAMILOZNAMENNY NEUM" +
"E CHASHKAZNAMENNY NEUME PODCHASHIEZNAMENNY NEUME SKAMEYTSA MRACHNAYAZNAM" +
"ENNY NEUME SKAMEYTSA SVETLAYAZNAMENNY NEUME SKAMEYTSA TRESVETLAYAZNAMENN" +
"Y NEUME SKAMEYTSA TIKHAYAZNAMENNY NEUME DEMESTVENNY KLYUCHZNAMENNY NEUME" +
" SKAMEYTSA KLYUCHEVAYA SVETLAYAZNAMENNY NEUME SKAMEYTSA KLYUCHENEPOSTOYA" +
"NNAYAZNAMENNY NEUME SKAMEYTSA KLYUCHEVAYA TIKHAYAZNAMENNY NEUME SKAMEYTS" +
"A DVOECHELNAYA PROSTAYAZNAMENNY NEUME SKAMEYTSA DVOECHELNAYA SVETLAYAZNA" +
"MENNY NEUME SKAMEYTSA DVOECHELNAYA NEPOSTOYANNAYAZNAMENNY NEUME SKAMEYTS" +
"A DVOECHELNAYA KLYUCHEVAYAZNAMENNY NEUME SLOZHITIEZNAMENNY NEUME SLOZHIT" +
"IE S ZAPYATOYZNAMENNY NEUME SLOZHITIE ZAKRYTOEZNAMENNY NEUME SLOZHITIE S" +
" KRYZHEMZNAMENNY NEUME KRYZHZNAMENNY NEUME ROGZNAMENNY NEUME FITAZNAMENN") + ("" +
"Y NEUME KOBYLAZNAMENNY NEUME ZMEYTSAZNAMENNY NEUME STATYAZNAMENNY NEUME " +
"STATYA S ZAPYATOYZNAMENNY NEUME STATYA S KRYZHEMZNAMENNY NEUME STATYA S " +
"ZAPYATOY I KRYZHEMZNAMENNY NEUME STATYA S KRYZHEM I ZAPYATOYZNAMENNY NEU" +
"ME STATYA ZAKRYTAYAZNAMENNY NEUME STATYA ZAKRYTAYA S ZAPYATOYZNAMENNY NE" +
"UME STATYA S ROGOMZNAMENNY NEUME STATYA S DVUMYA ZAPYATYMIZNAMENNY NEUME" +
" STATYA S ZAPYATOY I PODCHASHIEMZNAMENNY NEUME POLKULIZMYZNAMENNY NEUME " +
"STATYA NEPOSTOYANNAYAZNAMENNY NEUME STRELA PROSTAYAZNAMENNY NEUME STRELA" +
" MRACHNOTIKHAYAZNAMENNY NEUME STRELA KRYZHEVAYAZNAMENNY NEUME STRELA POL" +
"UPOVODNAYAZNAMENNY NEUME STRELA POVODNAYAZNAMENNY NEUME STRELA NEPOSTOYA" +
"NNAYAZNAMENNY NEUME STRELA KLYUCHEPOVODNAYAZNAMENNY NEUME STRELA KLYUCHE" +
"NEPOSTOYANNAYAZNAMENNY NEUME STRELA TIKHAYA PUTNAYAZNAMENNY NEUME STRELA" +
" DVOECHELNAYAZNAMENNY NEUME STRELA DVOECHELNOKRYZHEVAYAZNAMENNY NEUME ST" +
"RELA DVOECHELNOPOVODNAYAZNAMENNY NEUME STRELA DVOECHELNAYA KLYUCHEVAYAZN" +
"AMENNY NEUME STRELA DVOECHELNOPOVODNAYA KLYUCHEVAYAZNAMENNY NEUME STRELA" +
" GROMNAYA WITH SINGLE ZAPYATAYAZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH" +
" SINGLE ZAPYATAYAZNAMENNY NEUME STRELA GROMNAYAZNAMENNY NEUME STRELA GRO" +
"MOPOVODNAYAZNAMENNY NEUME STRELA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYAZNA" +
"MENNY NEUME STRELA GROMOKRYZHEVAYAZNAMENNY NEUME STRELA GROMOKRYZHEVAYA " +
"POVODNAYAZNAMENNY NEUME MECHIKZNAMENNY NEUME MECHIK POVODNYZNAMENNY NEUM" +
"E MECHIK KLYUCHEVOYZNAMENNY NEUME MECHIK KLYUCHEPOVODNYZNAMENNY NEUME ME" +
"CHIK KLYUCHENEPOSTOYANNYZNAMENNY NEUME STRELA TRYASOGLASNAYAZNAMENNY NEU" +
"ME STRELA TRYASOPOVODNAYAZNAMENNY NEUME STRELA TRYASOSTRELNAYAZNAMENNY N" +
"EUME OSOKAZNAMENNY NEUME OSOKA SVETLAYAZNAMENNY NEUME OSOKA TRESVETLAYAZ" +
"NAMENNY NEUME OSOKA KRYUKOVAYA SVETLAYAZNAMENNY NEUME OSOKA KLYUCHEVAYA " +
"SVETLAYAZNAMENNY NEUME OSOKA KLYUCHEVAYA NEPOSTOYANNAYAZNAMENNY NEUME ST" +
"RELA KRYUKOVAYAZNAMENNY NEUME STRELA KRYUKOVAYA POVODNAYAZNAMENNY NEUME " +
"STRELA KRYUKOVAYA GROMNAYA WITH SINGLE ZAPYATAYAZNAMENNY NEUME STRELA KR" +
"YUKOVAYA GROMOPOVODNAYA WITH SINGLE ZAPYATAYAZNAMENNY NEUME STRELA KRYUK" +
"OVAYA GROMNAYAZNAMENNY NEUME STRELA KRYUKOVAYA GROMOPOVODNAYAZNAMENNY NE" +
"UME STRELA KRYUKOVAYA GROMOPOVODNAYA WITH DOUBLE ZAPYATAYAZNAMENNY NEUME" +
" STRELA KRYUKOVAYA GROMOKRYZHEVAYAZNAMENNY NEUME STRELA KRYUKOVAYA GROMO" +
"KRYZHEVAYA POVODNAYAZNAMENNY NEUME STRELA KRYUKOVAYA TRYASKAZNAMENNY NEU" +
"ME KUFISMAZNAMENNY NEUME OBLAKOZNAMENNY NEUME DUDAZNAMENNY NEUME NEMKAZN" +
"AMENNY NEUME PAUKBYZANTINE MUSICAL SYMBOL PSILIBYZANTINE MUSICAL SYMBOL " +
"DASEIABYZANTINE MUSICAL SYMBOL PERISPOMENIBYZANTINE MUSICAL SYMBOL OXEIA" +
" EKFONITIKONBYZANTINE MUSICAL SYMBOL OXEIA DIPLIBYZANTINE MUSICAL SYMBOL" +
" VAREIA EKFONITIKONBYZANTINE MUSICAL SYMBOL VAREIA DIPLIBYZANTINE MUSICA" +
"L SYMBOL KATHISTIBYZANTINE MUSICAL SYMBOL SYRMATIKIBYZANTINE MUSICAL SYM" +
"BOL PARAKLITIKIBYZANTINE MUSICAL SYMBOL YPOKRISISBYZANTINE MUSICAL SYMBO" +
"L YPOKRISIS DIPLIBYZANTINE MUSICAL SYMBOL KREMASTIBYZANTINE MUSICAL SYMB" +
"OL APESO EKFONITIKONBYZANTINE MUSICAL SYMBOL EXO EKFONITIKONBYZANTINE MU" +
"SICAL SYMBOL TELEIABYZANTINE MUSICAL SYMBOL KENTIMATABYZANTINE MUSICAL S" +
"YMBOL APOSTROFOSBYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLIBYZANTINE MUSIC" +
"AL SYMBOL SYNEVMABYZANTINE MUSICAL SYMBOL THITABYZANTINE MUSICAL SYMBOL " +
"OLIGON ARCHAIONBYZANTINE MUSICAL SYMBOL GORGON ARCHAIONBYZANTINE MUSICAL" +
" SYMBOL PSILONBYZANTINE MUSICAL SYMBOL CHAMILONBYZANTINE MUSICAL SYMBOL " +
"VATHYBYZANTINE MUSICAL SYMBOL ISON ARCHAIONBYZANTINE MUSICAL SYMBOL KENT" +
"IMA ARCHAIONBYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAIONBYZANTINE MUSICAL" +
" SYMBOL SAXIMATABYZANTINE MUSICAL SYMBOL PARICHONBYZANTINE MUSICAL SYMBO" +
"L STAVROS APODEXIABYZANTINE MUSICAL SYMBOL OXEIAI ARCHAIONBYZANTINE MUSI" +
"CAL SYMBOL VAREIAI ARCHAIONBYZANTINE MUSICAL SYMBOL APODERMA ARCHAIONBYZ" +
"ANTINE MUSICAL SYMBOL APOTHEMABYZANTINE MUSICAL SYMBOL KLASMABYZANTINE M" +
"USICAL SYMBOL REVMABYZANTINE MUSICAL SYMBOL PIASMA ARCHAIONBYZANTINE MUS" +
"ICAL SYMBOL TINAGMABYZANTINE MUSICAL SYMBOL ANATRICHISMABYZANTINE MUSICA" +
"L SYMBOL SEISMABYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAIONBYZANTINE MUSICA" +
"L SYMBOL SYNAGMA META STAVROUBYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION" +
"BYZANTINE MUSICAL SYMBOL THEMABYZANTINE MUSICAL SYMBOL LEMOIBYZANTINE MU" +
"SICAL SYMBOL DYOBYZANTINE MUSICAL SYMBOL TRIABYZANTINE MUSICAL SYMBOL TE" +
"SSERABYZANTINE MUSICAL SYMBOL KRATIMATABYZANTINE MUSICAL SYMBOL APESO EX" +
"O NEOBYZANTINE MUSICAL SYMBOL FTHORA ARCHAIONBYZANTINE MUSICAL SYMBOL IM" +
"IFTHORABYZANTINE MUSICAL SYMBOL TROMIKON ARCHAIONBYZANTINE MUSICAL SYMBO" +
"L KATAVA TROMIKONBYZANTINE MUSICAL SYMBOL PELASTONBYZANTINE MUSICAL SYMB" +
"OL PSIFISTONBYZANTINE MUSICAL SYMBOL KONTEVMABYZANTINE MUSICAL SYMBOL CH" +
"OREVMA ARCHAIONBYZANTINE MUSICAL SYMBOL RAPISMABYZANTINE MUSICAL SYMBOL ") + ("" +
"PARAKALESMA ARCHAIONBYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAIONBYZANTI" +
"NE MUSICAL SYMBOL ICHADINBYZANTINE MUSICAL SYMBOL NANABYZANTINE MUSICAL " +
"SYMBOL PETASMABYZANTINE MUSICAL SYMBOL KONTEVMA ALLOBYZANTINE MUSICAL SY" +
"MBOL TROMIKON ALLOBYZANTINE MUSICAL SYMBOL STRAGGISMATABYZANTINE MUSICAL" +
" SYMBOL GRONTHISMATABYZANTINE MUSICAL SYMBOL ISON NEOBYZANTINE MUSICAL S" +
"YMBOL OLIGON NEOBYZANTINE MUSICAL SYMBOL OXEIA NEOBYZANTINE MUSICAL SYMB" +
"OL PETASTIBYZANTINE MUSICAL SYMBOL KOUFISMABYZANTINE MUSICAL SYMBOL PETA" +
"STOKOUFISMABYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMABYZANTINE MUSICAL SYM" +
"BOL PELASTON NEOBYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANOBYZANTINE MUSI" +
"CAL SYMBOL KENTIMA NEO ANOBYZANTINE MUSICAL SYMBOL YPSILIBYZANTINE MUSIC" +
"AL SYMBOL APOSTROFOS NEOBYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NE" +
"OBYZANTINE MUSICAL SYMBOL YPORROIBYZANTINE MUSICAL SYMBOL KRATIMOYPORROO" +
"NBYZANTINE MUSICAL SYMBOL ELAFRONBYZANTINE MUSICAL SYMBOL CHAMILIBYZANTI" +
"NE MUSICAL SYMBOL MIKRON ISONBYZANTINE MUSICAL SYMBOL VAREIA NEOBYZANTIN" +
"E MUSICAL SYMBOL PIASMA NEOBYZANTINE MUSICAL SYMBOL PSIFISTON NEOBYZANTI" +
"NE MUSICAL SYMBOL OMALONBYZANTINE MUSICAL SYMBOL ANTIKENOMABYZANTINE MUS" +
"ICAL SYMBOL LYGISMABYZANTINE MUSICAL SYMBOL PARAKLITIKI NEOBYZANTINE MUS" +
"ICAL SYMBOL PARAKALESMA NEOBYZANTINE MUSICAL SYMBOL ETERON PARAKALESMABY" +
"ZANTINE MUSICAL SYMBOL KYLISMABYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMABY" +
"ZANTINE MUSICAL SYMBOL TROMIKON NEOBYZANTINE MUSICAL SYMBOL EKSTREPTONBY" +
"ZANTINE MUSICAL SYMBOL SYNAGMA NEOBYZANTINE MUSICAL SYMBOL SYRMABYZANTIN" +
"E MUSICAL SYMBOL CHOREVMA NEOBYZANTINE MUSICAL SYMBOL EPEGERMABYZANTINE " +
"MUSICAL SYMBOL SEISMA NEOBYZANTINE MUSICAL SYMBOL XIRON KLASMABYZANTINE " +
"MUSICAL SYMBOL TROMIKOPSIFISTONBYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMAB" +
"YZANTINE MUSICAL SYMBOL TROMIKOLYGISMABYZANTINE MUSICAL SYMBOL TROMIKOPA" +
"RAKALESMABYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMABYZANTINE MUSICAL S" +
"YMBOL TROMIKOSYNAGMABYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMABYZANTINE MU" +
"SICAL SYMBOL GORGOSYNTHETONBYZANTINE MUSICAL SYMBOL ARGOSYNTHETONBYZANTI" +
"NE MUSICAL SYMBOL ETERON ARGOSYNTHETONBYZANTINE MUSICAL SYMBOL OYRANISMA" +
" NEOBYZANTINE MUSICAL SYMBOL THEMATISMOS ESOBYZANTINE MUSICAL SYMBOL THE" +
"MATISMOS EXOBYZANTINE MUSICAL SYMBOL THEMA APLOUNBYZANTINE MUSICAL SYMBO" +
"L THES KAI APOTHESBYZANTINE MUSICAL SYMBOL KATAVASMABYZANTINE MUSICAL SY" +
"MBOL ENDOFONONBYZANTINE MUSICAL SYMBOL YFEN KATOBYZANTINE MUSICAL SYMBOL" +
" YFEN ANOBYZANTINE MUSICAL SYMBOL STAVROSBYZANTINE MUSICAL SYMBOL KLASMA" +
" ANOBYZANTINE MUSICAL SYMBOL DIPLI ARCHAIONBYZANTINE MUSICAL SYMBOL KRAT" +
"IMA ARCHAIONBYZANTINE MUSICAL SYMBOL KRATIMA ALLOBYZANTINE MUSICAL SYMBO" +
"L KRATIMA NEOBYZANTINE MUSICAL SYMBOL APODERMA NEOBYZANTINE MUSICAL SYMB" +
"OL APLIBYZANTINE MUSICAL SYMBOL DIPLIBYZANTINE MUSICAL SYMBOL TRIPLIBYZA" +
"NTINE MUSICAL SYMBOL TETRAPLIBYZANTINE MUSICAL SYMBOL KORONISBYZANTINE M" +
"USICAL SYMBOL LEIMMA ENOS CHRONOUBYZANTINE MUSICAL SYMBOL LEIMMA DYO CHR" +
"ONONBYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONONBYZANTINE MUSICAL SYMBO" +
"L LEIMMA TESSARON CHRONONBYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU" +
"BYZANTINE MUSICAL SYMBOL GORGON NEO ANOBYZANTINE MUSICAL SYMBOL GORGON P" +
"ARESTIGMENON ARISTERABYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA" +
"BYZANTINE MUSICAL SYMBOL DIGORGONBYZANTINE MUSICAL SYMBOL DIGORGON PARES" +
"TIGMENON ARISTERA KATOBYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON AR" +
"ISTERA ANOBYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIABYZANTINE" +
" MUSICAL SYMBOL TRIGORGONBYZANTINE MUSICAL SYMBOL ARGONBYZANTINE MUSICAL" +
" SYMBOL IMIDIARGONBYZANTINE MUSICAL SYMBOL DIARGONBYZANTINE MUSICAL SYMB" +
"OL AGOGI POLI ARGIBYZANTINE MUSICAL SYMBOL AGOGI ARGOTERIBYZANTINE MUSIC" +
"AL SYMBOL AGOGI ARGIBYZANTINE MUSICAL SYMBOL AGOGI METRIABYZANTINE MUSIC" +
"AL SYMBOL AGOGI MESIBYZANTINE MUSICAL SYMBOL AGOGI GORGIBYZANTINE MUSICA" +
"L SYMBOL AGOGI GORGOTERIBYZANTINE MUSICAL SYMBOL AGOGI POLI GORGIBYZANTI" +
"NE MUSICAL SYMBOL MARTYRIA PROTOS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA" +
" ALLI PROTOS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOSBYZANT" +
"INE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOSBYZANTINE MUSICAL SYMBOL " +
"MARTYRIA TRITOS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIASBYZANTIN" +
"E MUSICAL SYMBOL MARTYRIA TETARTOS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRI" +
"A TETARTOS LEGETOS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOSB" +
"YZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOSBYZANTINE MUSICAL SYMBOL I" +
"SAKIA TELOUS ICHIMATOSBYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMAT" +
"OSBYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIASBYZANTINE MUSICAL SYMBOL" +
" FANEROSIS MONOFONIASBYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIASBYZANTIN" +
"E MUSICAL SYMBOL MARTYRIA VARYS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA P") + ("" +
"ROTOVARYS ICHOSBYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOSB" +
"YZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUNBYZANTINE MUSICAL SYMBOL GORT" +
"HMIKON N DIPLOUNBYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOUBYZANTINE" +
" MUSICAL SYMBOL IMIFONONBYZANTINE MUSICAL SYMBOL IMIFTHORONBYZANTINE MUS" +
"ICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOUBYZANTINE MUSICAL SYMBOL FTHOR" +
"A DIATONIKI PABYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANABYZANTINE MU" +
"SICAL SYMBOL FTHORA NAOS ICHOSBYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI " +
"DIBYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DIBYZANTINE MUSICAL S" +
"YMBOL FTHORA DIATONIKI KEBYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZOBYZ" +
"ANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATOBYZANTINE MUSICAL SYMBOL F" +
"THORA DIATONIKI NI ANOBYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIF" +
"ONIASBYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIASBYZANTINE " +
"MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASISBYZANTINE MUSICAL SYMBOL FTHOR" +
"A SKLIRON CHROMA SYNAFIBYZANTINE MUSICAL SYMBOL FTHORA NENANOBYZANTINE M" +
"USICAL SYMBOL CHROA ZYGOSBYZANTINE MUSICAL SYMBOL CHROA KLITONBYZANTINE " +
"MUSICAL SYMBOL CHROA SPATHIBYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETA" +
"RTIMORIONBYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIABYZANTINE M" +
"USICAL SYMBOL YFESIS TRITIMORIONBYZANTINE MUSICAL SYMBOL DIESIS TRITIMOR" +
"IONBYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORIONBYZANTINE MUSICAL SYMBOL" +
" DIESIS APLI DYO DODEKATABYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TES" +
"SERA DODEKATABYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATABYZANT" +
"INE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATABYZANTINE MUSICAL SYMB" +
"OL YFESIS APLI DYO DODEKATABYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS T" +
"ESSERA DODEKATABYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATABYZA" +
"NTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATABYZANTINE MUSICAL SY" +
"MBOL GENIKI DIESISBYZANTINE MUSICAL SYMBOL GENIKI YFESISBYZANTINE MUSICA" +
"L SYMBOL DIASTOLI APLI MIKRIBYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGAL" +
"IBYZANTINE MUSICAL SYMBOL DIASTOLI DIPLIBYZANTINE MUSICAL SYMBOL DIASTOL" +
"I THESEOSBYZANTINE MUSICAL SYMBOL SIMANSIS THESEOSBYZANTINE MUSICAL SYMB" +
"OL SIMANSIS THESEOS DISIMOUBYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRI" +
"SIMOUBYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOUBYZANTINE MUSIC" +
"AL SYMBOL SIMANSIS ARSEOSBYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMO" +
"UBYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOUBYZANTINE MUSICAL SYMB" +
"OL SIMANSIS ARSEOS TETRASIMOUBYZANTINE MUSICAL SYMBOL DIGRAMMA GGBYZANTI" +
"NE MUSICAL SYMBOL DIFTOGGOS OUBYZANTINE MUSICAL SYMBOL STIGMABYZANTINE M" +
"USICAL SYMBOL ARKTIKO PABYZANTINE MUSICAL SYMBOL ARKTIKO VOUBYZANTINE MU" +
"SICAL SYMBOL ARKTIKO GABYZANTINE MUSICAL SYMBOL ARKTIKO DIBYZANTINE MUSI" +
"CAL SYMBOL ARKTIKO KEBYZANTINE MUSICAL SYMBOL ARKTIKO ZOBYZANTINE MUSICA" +
"L SYMBOL ARKTIKO NIBYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESOBYZANTINE " +
"MUSICAL SYMBOL KENTIMA NEO MESOBYZANTINE MUSICAL SYMBOL KENTIMATA NEO KA" +
"TOBYZANTINE MUSICAL SYMBOL KENTIMA NEO KATOBYZANTINE MUSICAL SYMBOL KLAS" +
"MA KATOBYZANTINE MUSICAL SYMBOL GORGON NEO KATOMUSICAL SYMBOL SINGLE BAR" +
"LINEMUSICAL SYMBOL DOUBLE BARLINEMUSICAL SYMBOL FINAL BARLINEMUSICAL SYM" +
"BOL REVERSE FINAL BARLINEMUSICAL SYMBOL DASHED BARLINEMUSICAL SYMBOL SHO" +
"RT BARLINEMUSICAL SYMBOL LEFT REPEAT SIGNMUSICAL SYMBOL RIGHT REPEAT SIG" +
"NMUSICAL SYMBOL REPEAT DOTSMUSICAL SYMBOL DAL SEGNOMUSICAL SYMBOL DA CAP" +
"OMUSICAL SYMBOL SEGNOMUSICAL SYMBOL CODAMUSICAL SYMBOL REPEATED FIGURE-1" +
"MUSICAL SYMBOL REPEATED FIGURE-2MUSICAL SYMBOL REPEATED FIGURE-3MUSICAL " +
"SYMBOL FERMATAMUSICAL SYMBOL FERMATA BELOWMUSICAL SYMBOL BREATH MARKMUSI" +
"CAL SYMBOL CAESURAMUSICAL SYMBOL BRACEMUSICAL SYMBOL BRACKETMUSICAL SYMB" +
"OL ONE-LINE STAFFMUSICAL SYMBOL TWO-LINE STAFFMUSICAL SYMBOL THREE-LINE " +
"STAFFMUSICAL SYMBOL FOUR-LINE STAFFMUSICAL SYMBOL FIVE-LINE STAFFMUSICAL" +
" SYMBOL SIX-LINE STAFFMUSICAL SYMBOL SIX-STRING FRETBOARDMUSICAL SYMBOL " +
"FOUR-STRING FRETBOARDMUSICAL SYMBOL G CLEFMUSICAL SYMBOL G CLEF OTTAVA A" +
"LTAMUSICAL SYMBOL G CLEF OTTAVA BASSAMUSICAL SYMBOL C CLEFMUSICAL SYMBOL" +
" F CLEFMUSICAL SYMBOL F CLEF OTTAVA ALTAMUSICAL SYMBOL F CLEF OTTAVA BAS" +
"SAMUSICAL SYMBOL DRUM CLEF-1MUSICAL SYMBOL DRUM CLEF-2MUSICAL SYMBOL MUL" +
"TIPLE MEASURE RESTMUSICAL SYMBOL DOUBLE SHARPMUSICAL SYMBOL DOUBLE FLATM" +
"USICAL SYMBOL FLAT UPMUSICAL SYMBOL FLAT DOWNMUSICAL SYMBOL NATURAL UPMU" +
"SICAL SYMBOL NATURAL DOWNMUSICAL SYMBOL SHARP UPMUSICAL SYMBOL SHARP DOW" +
"NMUSICAL SYMBOL QUARTER TONE SHARPMUSICAL SYMBOL QUARTER TONE FLATMUSICA" +
"L SYMBOL COMMON TIMEMUSICAL SYMBOL CUT TIMEMUSICAL SYMBOL OTTAVA ALTAMUS" +
"ICAL SYMBOL OTTAVA BASSAMUSICAL SYMBOL QUINDICESIMA ALTAMUSICAL SYMBOL Q" +
"UINDICESIMA BASSAMUSICAL SYMBOL MULTI RESTMUSICAL SYMBOL WHOLE RESTMUSIC") + ("" +
"AL SYMBOL HALF RESTMUSICAL SYMBOL QUARTER RESTMUSICAL SYMBOL EIGHTH REST" +
"MUSICAL SYMBOL SIXTEENTH RESTMUSICAL SYMBOL THIRTY-SECOND RESTMUSICAL SY" +
"MBOL SIXTY-FOURTH RESTMUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH RESTMUSIC" +
"AL SYMBOL X NOTEHEADMUSICAL SYMBOL PLUS NOTEHEADMUSICAL SYMBOL CIRCLE X " +
"NOTEHEADMUSICAL SYMBOL SQUARE NOTEHEAD WHITEMUSICAL SYMBOL SQUARE NOTEHE" +
"AD BLACKMUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITEMUSICAL SYMBOL TRIANGLE" +
" NOTEHEAD UP BLACKMUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITEMUSICAL SYM" +
"BOL TRIANGLE NOTEHEAD LEFT BLACKMUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT W" +
"HITEMUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACKMUSICAL SYMBOL TRIANGLE " +
"NOTEHEAD DOWN WHITEMUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACKMUSICAL SY" +
"MBOL TRIANGLE NOTEHEAD UP RIGHT WHITEMUSICAL SYMBOL TRIANGLE NOTEHEAD UP" +
" RIGHT BLACKMUSICAL SYMBOL MOON NOTEHEAD WHITEMUSICAL SYMBOL MOON NOTEHE" +
"AD BLACKMUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITEMUSICAL SYMBOL " +
"TRIANGLE-ROUND NOTEHEAD DOWN BLACKMUSICAL SYMBOL PARENTHESIS NOTEHEADMUS" +
"ICAL SYMBOL VOID NOTEHEADMUSICAL SYMBOL NOTEHEAD BLACKMUSICAL SYMBOL NUL" +
"L NOTEHEADMUSICAL SYMBOL CLUSTER NOTEHEAD WHITEMUSICAL SYMBOL CLUSTER NO" +
"TEHEAD BLACKMUSICAL SYMBOL BREVEMUSICAL SYMBOL WHOLE NOTEMUSICAL SYMBOL " +
"HALF NOTEMUSICAL SYMBOL QUARTER NOTEMUSICAL SYMBOL EIGHTH NOTEMUSICAL SY" +
"MBOL SIXTEENTH NOTEMUSICAL SYMBOL THIRTY-SECOND NOTEMUSICAL SYMBOL SIXTY" +
"-FOURTH NOTEMUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTEMUSICAL SYMBOL " +
"COMBINING STEMMUSICAL SYMBOL COMBINING SPRECHGESANG STEMMUSICAL SYMBOL C" +
"OMBINING TREMOLO-1MUSICAL SYMBOL COMBINING TREMOLO-2MUSICAL SYMBOL COMBI" +
"NING TREMOLO-3MUSICAL SYMBOL FINGERED TREMOLO-1MUSICAL SYMBOL FINGERED T" +
"REMOLO-2MUSICAL SYMBOL FINGERED TREMOLO-3MUSICAL SYMBOL COMBINING AUGMEN" +
"TATION DOTMUSICAL SYMBOL COMBINING FLAG-1MUSICAL SYMBOL COMBINING FLAG-2" +
"MUSICAL SYMBOL COMBINING FLAG-3MUSICAL SYMBOL COMBINING FLAG-4MUSICAL SY" +
"MBOL COMBINING FLAG-5MUSICAL SYMBOL BEGIN BEAMMUSICAL SYMBOL END BEAMMUS" +
"ICAL SYMBOL BEGIN TIEMUSICAL SYMBOL END TIEMUSICAL SYMBOL BEGIN SLURMUSI" +
"CAL SYMBOL END SLURMUSICAL SYMBOL BEGIN PHRASEMUSICAL SYMBOL END PHRASEM" +
"USICAL SYMBOL COMBINING ACCENTMUSICAL SYMBOL COMBINING STACCATOMUSICAL S" +
"YMBOL COMBINING TENUTOMUSICAL SYMBOL COMBINING STACCATISSIMOMUSICAL SYMB" +
"OL COMBINING MARCATOMUSICAL SYMBOL COMBINING MARCATO-STACCATOMUSICAL SYM" +
"BOL COMBINING ACCENT-STACCATOMUSICAL SYMBOL COMBINING LOUREMUSICAL SYMBO" +
"L ARPEGGIATO UPMUSICAL SYMBOL ARPEGGIATO DOWNMUSICAL SYMBOL COMBINING DO" +
"ITMUSICAL SYMBOL COMBINING RIPMUSICAL SYMBOL COMBINING FLIPMUSICAL SYMBO" +
"L COMBINING SMEARMUSICAL SYMBOL COMBINING BENDMUSICAL SYMBOL COMBINING D" +
"OUBLE TONGUEMUSICAL SYMBOL COMBINING TRIPLE TONGUEMUSICAL SYMBOL RINFORZ" +
"ANDOMUSICAL SYMBOL SUBITOMUSICAL SYMBOL ZMUSICAL SYMBOL PIANOMUSICAL SYM" +
"BOL MEZZOMUSICAL SYMBOL FORTEMUSICAL SYMBOL CRESCENDOMUSICAL SYMBOL DECR" +
"ESCENDOMUSICAL SYMBOL GRACE NOTE SLASHMUSICAL SYMBOL GRACE NOTE NO SLASH" +
"MUSICAL SYMBOL TRMUSICAL SYMBOL TURNMUSICAL SYMBOL INVERTED TURNMUSICAL " +
"SYMBOL TURN SLASHMUSICAL SYMBOL TURN UPMUSICAL SYMBOL ORNAMENT STROKE-1M" +
"USICAL SYMBOL ORNAMENT STROKE-2MUSICAL SYMBOL ORNAMENT STROKE-3MUSICAL S" +
"YMBOL ORNAMENT STROKE-4MUSICAL SYMBOL ORNAMENT STROKE-5MUSICAL SYMBOL OR" +
"NAMENT STROKE-6MUSICAL SYMBOL ORNAMENT STROKE-7MUSICAL SYMBOL ORNAMENT S" +
"TROKE-8MUSICAL SYMBOL ORNAMENT STROKE-9MUSICAL SYMBOL ORNAMENT STROKE-10" +
"MUSICAL SYMBOL ORNAMENT STROKE-11MUSICAL SYMBOL HAUPTSTIMMEMUSICAL SYMBO" +
"L NEBENSTIMMEMUSICAL SYMBOL END OF STIMMEMUSICAL SYMBOL DEGREE SLASHMUSI" +
"CAL SYMBOL COMBINING DOWN BOWMUSICAL SYMBOL COMBINING UP BOWMUSICAL SYMB" +
"OL COMBINING HARMONICMUSICAL SYMBOL COMBINING SNAP PIZZICATOMUSICAL SYMB" +
"OL PEDAL MARKMUSICAL SYMBOL PEDAL UP MARKMUSICAL SYMBOL HALF PEDAL MARKM" +
"USICAL SYMBOL GLISSANDO UPMUSICAL SYMBOL GLISSANDO DOWNMUSICAL SYMBOL WI" +
"TH FINGERNAILSMUSICAL SYMBOL DAMPMUSICAL SYMBOL DAMP ALLMUSICAL SYMBOL M" +
"AXIMAMUSICAL SYMBOL LONGAMUSICAL SYMBOL BREVISMUSICAL SYMBOL SEMIBREVIS " +
"WHITEMUSICAL SYMBOL SEMIBREVIS BLACKMUSICAL SYMBOL MINIMAMUSICAL SYMBOL " +
"MINIMA BLACKMUSICAL SYMBOL SEMIMINIMA WHITEMUSICAL SYMBOL SEMIMINIMA BLA" +
"CKMUSICAL SYMBOL FUSA WHITEMUSICAL SYMBOL FUSA BLACKMUSICAL SYMBOL LONGA" +
" PERFECTA RESTMUSICAL SYMBOL LONGA IMPERFECTA RESTMUSICAL SYMBOL BREVIS " +
"RESTMUSICAL SYMBOL SEMIBREVIS RESTMUSICAL SYMBOL MINIMA RESTMUSICAL SYMB" +
"OL SEMIMINIMA RESTMUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECT" +
"AMUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTAMUSICAL SYMBOL" +
" TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1MUSICAL SYMBOL TEM" +
"PUS IMPERFECTUM CUM PROLATIONE PERFECTAMUSICAL SYMBOL TEMPUS IMPERFECTUM" +
" CUM PROLATIONE IMPERFECTAMUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIO") + ("" +
"NE IMPERFECTA DIMINUTION-1MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIO" +
"NE IMPERFECTA DIMINUTION-2MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIO" +
"NE IMPERFECTA DIMINUTION-3MUSICAL SYMBOL CROIXMUSICAL SYMBOL GREGORIAN C" +
" CLEFMUSICAL SYMBOL GREGORIAN F CLEFMUSICAL SYMBOL SQUARE BMUSICAL SYMBO" +
"L VIRGAMUSICAL SYMBOL PODATUSMUSICAL SYMBOL CLIVISMUSICAL SYMBOL SCANDIC" +
"USMUSICAL SYMBOL CLIMACUSMUSICAL SYMBOL TORCULUSMUSICAL SYMBOL PORRECTUS" +
"MUSICAL SYMBOL PORRECTUS FLEXUSMUSICAL SYMBOL SCANDICUS FLEXUSMUSICAL SY" +
"MBOL TORCULUS RESUPINUSMUSICAL SYMBOL PES SUBPUNCTISMUSICAL SYMBOL KIEVA" +
"N C CLEFMUSICAL SYMBOL KIEVAN END OF PIECEMUSICAL SYMBOL KIEVAN FINAL NO" +
"TEMUSICAL SYMBOL KIEVAN RECITATIVE MARKMUSICAL SYMBOL KIEVAN WHOLE NOTEM" +
"USICAL SYMBOL KIEVAN HALF NOTEMUSICAL SYMBOL KIEVAN QUARTER NOTE STEM DO" +
"WNMUSICAL SYMBOL KIEVAN QUARTER NOTE STEM UPMUSICAL SYMBOL KIEVAN EIGHTH" +
" NOTE STEM DOWNMUSICAL SYMBOL KIEVAN EIGHTH NOTE STEM UPMUSICAL SYMBOL K" +
"IEVAN FLAT SIGNMUSICAL SYMBOL SORIMUSICAL SYMBOL KORONGREEK VOCAL NOTATI" +
"ON SYMBOL-1GREEK VOCAL NOTATION SYMBOL-2GREEK VOCAL NOTATION SYMBOL-3GRE" +
"EK VOCAL NOTATION SYMBOL-4GREEK VOCAL NOTATION SYMBOL-5GREEK VOCAL NOTAT" +
"ION SYMBOL-6GREEK VOCAL NOTATION SYMBOL-7GREEK VOCAL NOTATION SYMBOL-8GR" +
"EEK VOCAL NOTATION SYMBOL-9GREEK VOCAL NOTATION SYMBOL-10GREEK VOCAL NOT" +
"ATION SYMBOL-11GREEK VOCAL NOTATION SYMBOL-12GREEK VOCAL NOTATION SYMBOL" +
"-13GREEK VOCAL NOTATION SYMBOL-14GREEK VOCAL NOTATION SYMBOL-15GREEK VOC" +
"AL NOTATION SYMBOL-16GREEK VOCAL NOTATION SYMBOL-17GREEK VOCAL NOTATION " +
"SYMBOL-18GREEK VOCAL NOTATION SYMBOL-19GREEK VOCAL NOTATION SYMBOL-20GRE" +
"EK VOCAL NOTATION SYMBOL-21GREEK VOCAL NOTATION SYMBOL-22GREEK VOCAL NOT" +
"ATION SYMBOL-23GREEK VOCAL NOTATION SYMBOL-24GREEK VOCAL NOTATION SYMBOL" +
"-50GREEK VOCAL NOTATION SYMBOL-51GREEK VOCAL NOTATION SYMBOL-52GREEK VOC" +
"AL NOTATION SYMBOL-53GREEK VOCAL NOTATION SYMBOL-54GREEK INSTRUMENTAL NO" +
"TATION SYMBOL-1GREEK INSTRUMENTAL NOTATION SYMBOL-2GREEK INSTRUMENTAL NO" +
"TATION SYMBOL-4GREEK INSTRUMENTAL NOTATION SYMBOL-5GREEK INSTRUMENTAL NO" +
"TATION SYMBOL-7GREEK INSTRUMENTAL NOTATION SYMBOL-8GREEK INSTRUMENTAL NO" +
"TATION SYMBOL-11GREEK INSTRUMENTAL NOTATION SYMBOL-12GREEK INSTRUMENTAL " +
"NOTATION SYMBOL-13GREEK INSTRUMENTAL NOTATION SYMBOL-14GREEK INSTRUMENTA" +
"L NOTATION SYMBOL-17GREEK INSTRUMENTAL NOTATION SYMBOL-18GREEK INSTRUMEN" +
"TAL NOTATION SYMBOL-19GREEK INSTRUMENTAL NOTATION SYMBOL-23GREEK INSTRUM" +
"ENTAL NOTATION SYMBOL-24GREEK INSTRUMENTAL NOTATION SYMBOL-25GREEK INSTR" +
"UMENTAL NOTATION SYMBOL-26GREEK INSTRUMENTAL NOTATION SYMBOL-27GREEK INS" +
"TRUMENTAL NOTATION SYMBOL-29GREEK INSTRUMENTAL NOTATION SYMBOL-30GREEK I" +
"NSTRUMENTAL NOTATION SYMBOL-32GREEK INSTRUMENTAL NOTATION SYMBOL-36GREEK" +
" INSTRUMENTAL NOTATION SYMBOL-37GREEK INSTRUMENTAL NOTATION SYMBOL-38GRE" +
"EK INSTRUMENTAL NOTATION SYMBOL-39GREEK INSTRUMENTAL NOTATION SYMBOL-40G" +
"REEK INSTRUMENTAL NOTATION SYMBOL-42GREEK INSTRUMENTAL NOTATION SYMBOL-4" +
"3GREEK INSTRUMENTAL NOTATION SYMBOL-45GREEK INSTRUMENTAL NOTATION SYMBOL" +
"-47GREEK INSTRUMENTAL NOTATION SYMBOL-48GREEK INSTRUMENTAL NOTATION SYMB" +
"OL-49GREEK INSTRUMENTAL NOTATION SYMBOL-50GREEK INSTRUMENTAL NOTATION SY" +
"MBOL-51GREEK INSTRUMENTAL NOTATION SYMBOL-52GREEK INSTRUMENTAL NOTATION " +
"SYMBOL-53GREEK INSTRUMENTAL NOTATION SYMBOL-54COMBINING GREEK MUSICAL TR" +
"ISEMECOMBINING GREEK MUSICAL TETRASEMECOMBINING GREEK MUSICAL PENTASEMEG" +
"REEK MUSICAL LEIMMAKAKTOVIK NUMERAL ZEROKAKTOVIK NUMERAL ONEKAKTOVIK NUM" +
"ERAL TWOKAKTOVIK NUMERAL THREEKAKTOVIK NUMERAL FOURKAKTOVIK NUMERAL FIVE" +
"KAKTOVIK NUMERAL SIXKAKTOVIK NUMERAL SEVENKAKTOVIK NUMERAL EIGHTKAKTOVIK" +
" NUMERAL NINEKAKTOVIK NUMERAL TENKAKTOVIK NUMERAL ELEVENKAKTOVIK NUMERAL" +
" TWELVEKAKTOVIK NUMERAL THIRTEENKAKTOVIK NUMERAL FOURTEENKAKTOVIK NUMERA" +
"L FIFTEENKAKTOVIK NUMERAL SIXTEENKAKTOVIK NUMERAL SEVENTEENKAKTOVIK NUME" +
"RAL EIGHTEENKAKTOVIK NUMERAL NINETEENMAYAN NUMERAL ZEROMAYAN NUMERAL ONE" +
"MAYAN NUMERAL TWOMAYAN NUMERAL THREEMAYAN NUMERAL FOURMAYAN NUMERAL FIVE" +
"MAYAN NUMERAL SIXMAYAN NUMERAL SEVENMAYAN NUMERAL EIGHTMAYAN NUMERAL NIN" +
"EMAYAN NUMERAL TENMAYAN NUMERAL ELEVENMAYAN NUMERAL TWELVEMAYAN NUMERAL " +
"THIRTEENMAYAN NUMERAL FOURTEENMAYAN NUMERAL FIFTEENMAYAN NUMERAL SIXTEEN" +
"MAYAN NUMERAL SEVENTEENMAYAN NUMERAL EIGHTEENMAYAN NUMERAL NINETEENMONOG" +
"RAM FOR EARTHDIGRAM FOR HEAVENLY EARTHDIGRAM FOR HUMAN EARTHDIGRAM FOR E" +
"ARTHLY HEAVENDIGRAM FOR EARTHLY HUMANDIGRAM FOR EARTHTETRAGRAM FOR CENTR" +
"ETETRAGRAM FOR FULL CIRCLETETRAGRAM FOR MIREDTETRAGRAM FOR BARRIERTETRAG" +
"RAM FOR KEEPING SMALLTETRAGRAM FOR CONTRARIETYTETRAGRAM FOR ASCENTTETRAG" +
"RAM FOR OPPOSITIONTETRAGRAM FOR BRANCHING OUTTETRAGRAM FOR DEFECTIVENESS" +
" OR DISTORTIONTETRAGRAM FOR DIVERGENCETETRAGRAM FOR YOUTHFULNESSTETRAGRA") + ("" +
"M FOR INCREASETETRAGRAM FOR PENETRATIONTETRAGRAM FOR REACHTETRAGRAM FOR " +
"CONTACTTETRAGRAM FOR HOLDING BACKTETRAGRAM FOR WAITINGTETRAGRAM FOR FOLL" +
"OWINGTETRAGRAM FOR ADVANCETETRAGRAM FOR RELEASETETRAGRAM FOR RESISTANCET" +
"ETRAGRAM FOR EASETETRAGRAM FOR JOYTETRAGRAM FOR CONTENTIONTETRAGRAM FOR " +
"ENDEAVOURTETRAGRAM FOR DUTIESTETRAGRAM FOR CHANGETETRAGRAM FOR DECISIVEN" +
"ESSTETRAGRAM FOR BOLD RESOLUTIONTETRAGRAM FOR PACKINGTETRAGRAM FOR LEGIO" +
"NTETRAGRAM FOR CLOSENESSTETRAGRAM FOR KINSHIPTETRAGRAM FOR GATHERINGTETR" +
"AGRAM FOR STRENGTHTETRAGRAM FOR PURITYTETRAGRAM FOR FULLNESSTETRAGRAM FO" +
"R RESIDENCETETRAGRAM FOR LAW OR MODELTETRAGRAM FOR RESPONSETETRAGRAM FOR" +
" GOING TO MEETTETRAGRAM FOR ENCOUNTERSTETRAGRAM FOR STOVETETRAGRAM FOR G" +
"REATNESSTETRAGRAM FOR ENLARGEMENTTETRAGRAM FOR PATTERNTETRAGRAM FOR RITU" +
"ALTETRAGRAM FOR FLIGHTTETRAGRAM FOR VASTNESS OR WASTINGTETRAGRAM FOR CON" +
"STANCYTETRAGRAM FOR MEASURETETRAGRAM FOR ETERNITYTETRAGRAM FOR UNITYTETR" +
"AGRAM FOR DIMINISHMENTTETRAGRAM FOR CLOSED MOUTHTETRAGRAM FOR GUARDEDNES" +
"STETRAGRAM FOR GATHERING INTETRAGRAM FOR MASSINGTETRAGRAM FOR ACCUMULATI" +
"ONTETRAGRAM FOR EMBELLISHMENTTETRAGRAM FOR DOUBTTETRAGRAM FOR WATCHTETRA" +
"GRAM FOR SINKINGTETRAGRAM FOR INNERTETRAGRAM FOR DEPARTURETETRAGRAM FOR " +
"DARKENINGTETRAGRAM FOR DIMMINGTETRAGRAM FOR EXHAUSTIONTETRAGRAM FOR SEVE" +
"RANCETETRAGRAM FOR STOPPAGETETRAGRAM FOR HARDNESSTETRAGRAM FOR COMPLETIO" +
"NTETRAGRAM FOR CLOSURETETRAGRAM FOR FAILURETETRAGRAM FOR AGGRAVATIONTETR" +
"AGRAM FOR COMPLIANCETETRAGRAM FOR ON THE VERGETETRAGRAM FOR DIFFICULTIES" +
"TETRAGRAM FOR LABOURINGTETRAGRAM FOR FOSTERINGCOUNTING ROD UNIT DIGIT ON" +
"ECOUNTING ROD UNIT DIGIT TWOCOUNTING ROD UNIT DIGIT THREECOUNTING ROD UN" +
"IT DIGIT FOURCOUNTING ROD UNIT DIGIT FIVECOUNTING ROD UNIT DIGIT SIXCOUN" +
"TING ROD UNIT DIGIT SEVENCOUNTING ROD UNIT DIGIT EIGHTCOUNTING ROD UNIT " +
"DIGIT NINECOUNTING ROD TENS DIGIT ONECOUNTING ROD TENS DIGIT TWOCOUNTING" +
" ROD TENS DIGIT THREECOUNTING ROD TENS DIGIT FOURCOUNTING ROD TENS DIGIT" +
" FIVECOUNTING ROD TENS DIGIT SIXCOUNTING ROD TENS DIGIT SEVENCOUNTING RO" +
"D TENS DIGIT EIGHTCOUNTING ROD TENS DIGIT NINEIDEOGRAPHIC TALLY MARK ONE" +
"IDEOGRAPHIC TALLY MARK TWOIDEOGRAPHIC TALLY MARK THREEIDEOGRAPHIC TALLY " +
"MARK FOURIDEOGRAPHIC TALLY MARK FIVETALLY MARK ONETALLY MARK FIVEMATHEMA" +
"TICAL BOLD CAPITAL AMATHEMATICAL BOLD CAPITAL BMATHEMATICAL BOLD CAPITAL" +
" CMATHEMATICAL BOLD CAPITAL DMATHEMATICAL BOLD CAPITAL EMATHEMATICAL BOL" +
"D CAPITAL FMATHEMATICAL BOLD CAPITAL GMATHEMATICAL BOLD CAPITAL HMATHEMA" +
"TICAL BOLD CAPITAL IMATHEMATICAL BOLD CAPITAL JMATHEMATICAL BOLD CAPITAL" +
" KMATHEMATICAL BOLD CAPITAL LMATHEMATICAL BOLD CAPITAL MMATHEMATICAL BOL" +
"D CAPITAL NMATHEMATICAL BOLD CAPITAL OMATHEMATICAL BOLD CAPITAL PMATHEMA" +
"TICAL BOLD CAPITAL QMATHEMATICAL BOLD CAPITAL RMATHEMATICAL BOLD CAPITAL" +
" SMATHEMATICAL BOLD CAPITAL TMATHEMATICAL BOLD CAPITAL UMATHEMATICAL BOL" +
"D CAPITAL VMATHEMATICAL BOLD CAPITAL WMATHEMATICAL BOLD CAPITAL XMATHEMA" +
"TICAL BOLD CAPITAL YMATHEMATICAL BOLD CAPITAL ZMATHEMATICAL BOLD SMALL A" +
"MATHEMATICAL BOLD SMALL BMATHEMATICAL BOLD SMALL CMATHEMATICAL BOLD SMAL" +
"L DMATHEMATICAL BOLD SMALL EMATHEMATICAL BOLD SMALL FMATHEMATICAL BOLD S" +
"MALL GMATHEMATICAL BOLD SMALL HMATHEMATICAL BOLD SMALL IMATHEMATICAL BOL" +
"D SMALL JMATHEMATICAL BOLD SMALL KMATHEMATICAL BOLD SMALL LMATHEMATICAL " +
"BOLD SMALL MMATHEMATICAL BOLD SMALL NMATHEMATICAL BOLD SMALL OMATHEMATIC" +
"AL BOLD SMALL PMATHEMATICAL BOLD SMALL QMATHEMATICAL BOLD SMALL RMATHEMA" +
"TICAL BOLD SMALL SMATHEMATICAL BOLD SMALL TMATHEMATICAL BOLD SMALL UMATH" +
"EMATICAL BOLD SMALL VMATHEMATICAL BOLD SMALL WMATHEMATICAL BOLD SMALL XM" +
"ATHEMATICAL BOLD SMALL YMATHEMATICAL BOLD SMALL ZMATHEMATICAL ITALIC CAP" +
"ITAL AMATHEMATICAL ITALIC CAPITAL BMATHEMATICAL ITALIC CAPITAL CMATHEMAT" +
"ICAL ITALIC CAPITAL DMATHEMATICAL ITALIC CAPITAL EMATHEMATICAL ITALIC CA" +
"PITAL FMATHEMATICAL ITALIC CAPITAL GMATHEMATICAL ITALIC CAPITAL HMATHEMA" +
"TICAL ITALIC CAPITAL IMATHEMATICAL ITALIC CAPITAL JMATHEMATICAL ITALIC C" +
"APITAL KMATHEMATICAL ITALIC CAPITAL LMATHEMATICAL ITALIC CAPITAL MMATHEM" +
"ATICAL ITALIC CAPITAL NMATHEMATICAL ITALIC CAPITAL OMATHEMATICAL ITALIC " +
"CAPITAL PMATHEMATICAL ITALIC CAPITAL QMATHEMATICAL ITALIC CAPITAL RMATHE" +
"MATICAL ITALIC CAPITAL SMATHEMATICAL ITALIC CAPITAL TMATHEMATICAL ITALIC" +
" CAPITAL UMATHEMATICAL ITALIC CAPITAL VMATHEMATICAL ITALIC CAPITAL WMATH" +
"EMATICAL ITALIC CAPITAL XMATHEMATICAL ITALIC CAPITAL YMATHEMATICAL ITALI" +
"C CAPITAL ZMATHEMATICAL ITALIC SMALL AMATHEMATICAL ITALIC SMALL BMATHEMA" +
"TICAL ITALIC SMALL CMATHEMATICAL ITALIC SMALL DMATHEMATICAL ITALIC SMALL" +
" EMATHEMATICAL ITALIC SMALL FMATHEMATICAL ITALIC SMALL GMATHEMATICAL ITA" +
"LIC SMALL IMATHEMATICAL ITALIC SMALL JMATHEMATICAL ITALIC SMALL KMATHEMA") + ("" +
"TICAL ITALIC SMALL LMATHEMATICAL ITALIC SMALL MMATHEMATICAL ITALIC SMALL" +
" NMATHEMATICAL ITALIC SMALL OMATHEMATICAL ITALIC SMALL PMATHEMATICAL ITA" +
"LIC SMALL QMATHEMATICAL ITALIC SMALL RMATHEMATICAL ITALIC SMALL SMATHEMA" +
"TICAL ITALIC SMALL TMATHEMATICAL ITALIC SMALL UMATHEMATICAL ITALIC SMALL" +
" VMATHEMATICAL ITALIC SMALL WMATHEMATICAL ITALIC SMALL XMATHEMATICAL ITA" +
"LIC SMALL YMATHEMATICAL ITALIC SMALL ZMATHEMATICAL BOLD ITALIC CAPITAL A" +
"MATHEMATICAL BOLD ITALIC CAPITAL BMATHEMATICAL BOLD ITALIC CAPITAL CMATH" +
"EMATICAL BOLD ITALIC CAPITAL DMATHEMATICAL BOLD ITALIC CAPITAL EMATHEMAT" +
"ICAL BOLD ITALIC CAPITAL FMATHEMATICAL BOLD ITALIC CAPITAL GMATHEMATICAL" +
" BOLD ITALIC CAPITAL HMATHEMATICAL BOLD ITALIC CAPITAL IMATHEMATICAL BOL" +
"D ITALIC CAPITAL JMATHEMATICAL BOLD ITALIC CAPITAL KMATHEMATICAL BOLD IT" +
"ALIC CAPITAL LMATHEMATICAL BOLD ITALIC CAPITAL MMATHEMATICAL BOLD ITALIC" +
" CAPITAL NMATHEMATICAL BOLD ITALIC CAPITAL OMATHEMATICAL BOLD ITALIC CAP" +
"ITAL PMATHEMATICAL BOLD ITALIC CAPITAL QMATHEMATICAL BOLD ITALIC CAPITAL" +
" RMATHEMATICAL BOLD ITALIC CAPITAL SMATHEMATICAL BOLD ITALIC CAPITAL TMA" +
"THEMATICAL BOLD ITALIC CAPITAL UMATHEMATICAL BOLD ITALIC CAPITAL VMATHEM" +
"ATICAL BOLD ITALIC CAPITAL WMATHEMATICAL BOLD ITALIC CAPITAL XMATHEMATIC" +
"AL BOLD ITALIC CAPITAL YMATHEMATICAL BOLD ITALIC CAPITAL ZMATHEMATICAL B" +
"OLD ITALIC SMALL AMATHEMATICAL BOLD ITALIC SMALL BMATHEMATICAL BOLD ITAL" +
"IC SMALL CMATHEMATICAL BOLD ITALIC SMALL DMATHEMATICAL BOLD ITALIC SMALL" +
" EMATHEMATICAL BOLD ITALIC SMALL FMATHEMATICAL BOLD ITALIC SMALL GMATHEM" +
"ATICAL BOLD ITALIC SMALL HMATHEMATICAL BOLD ITALIC SMALL IMATHEMATICAL B" +
"OLD ITALIC SMALL JMATHEMATICAL BOLD ITALIC SMALL KMATHEMATICAL BOLD ITAL" +
"IC SMALL LMATHEMATICAL BOLD ITALIC SMALL MMATHEMATICAL BOLD ITALIC SMALL" +
" NMATHEMATICAL BOLD ITALIC SMALL OMATHEMATICAL BOLD ITALIC SMALL PMATHEM" +
"ATICAL BOLD ITALIC SMALL QMATHEMATICAL BOLD ITALIC SMALL RMATHEMATICAL B" +
"OLD ITALIC SMALL SMATHEMATICAL BOLD ITALIC SMALL TMATHEMATICAL BOLD ITAL" +
"IC SMALL UMATHEMATICAL BOLD ITALIC SMALL VMATHEMATICAL BOLD ITALIC SMALL" +
" WMATHEMATICAL BOLD ITALIC SMALL XMATHEMATICAL BOLD ITALIC SMALL YMATHEM" +
"ATICAL BOLD ITALIC SMALL ZMATHEMATICAL SCRIPT CAPITAL AMATHEMATICAL SCRI" +
"PT CAPITAL CMATHEMATICAL SCRIPT CAPITAL DMATHEMATICAL SCRIPT CAPITAL GMA" +
"THEMATICAL SCRIPT CAPITAL JMATHEMATICAL SCRIPT CAPITAL KMATHEMATICAL SCR" +
"IPT CAPITAL NMATHEMATICAL SCRIPT CAPITAL OMATHEMATICAL SCRIPT CAPITAL PM" +
"ATHEMATICAL SCRIPT CAPITAL QMATHEMATICAL SCRIPT CAPITAL SMATHEMATICAL SC" +
"RIPT CAPITAL TMATHEMATICAL SCRIPT CAPITAL UMATHEMATICAL SCRIPT CAPITAL V" +
"MATHEMATICAL SCRIPT CAPITAL WMATHEMATICAL SCRIPT CAPITAL XMATHEMATICAL S" +
"CRIPT CAPITAL YMATHEMATICAL SCRIPT CAPITAL ZMATHEMATICAL SCRIPT SMALL AM" +
"ATHEMATICAL SCRIPT SMALL BMATHEMATICAL SCRIPT SMALL CMATHEMATICAL SCRIPT" +
" SMALL DMATHEMATICAL SCRIPT SMALL FMATHEMATICAL SCRIPT SMALL HMATHEMATIC" +
"AL SCRIPT SMALL IMATHEMATICAL SCRIPT SMALL JMATHEMATICAL SCRIPT SMALL KM" +
"ATHEMATICAL SCRIPT SMALL LMATHEMATICAL SCRIPT SMALL MMATHEMATICAL SCRIPT" +
" SMALL NMATHEMATICAL SCRIPT SMALL PMATHEMATICAL SCRIPT SMALL QMATHEMATIC" +
"AL SCRIPT SMALL RMATHEMATICAL SCRIPT SMALL SMATHEMATICAL SCRIPT SMALL TM" +
"ATHEMATICAL SCRIPT SMALL UMATHEMATICAL SCRIPT SMALL VMATHEMATICAL SCRIPT" +
" SMALL WMATHEMATICAL SCRIPT SMALL XMATHEMATICAL SCRIPT SMALL YMATHEMATIC" +
"AL SCRIPT SMALL ZMATHEMATICAL BOLD SCRIPT CAPITAL AMATHEMATICAL BOLD SCR" +
"IPT CAPITAL BMATHEMATICAL BOLD SCRIPT CAPITAL CMATHEMATICAL BOLD SCRIPT " +
"CAPITAL DMATHEMATICAL BOLD SCRIPT CAPITAL EMATHEMATICAL BOLD SCRIPT CAPI" +
"TAL FMATHEMATICAL BOLD SCRIPT CAPITAL GMATHEMATICAL BOLD SCRIPT CAPITAL " +
"HMATHEMATICAL BOLD SCRIPT CAPITAL IMATHEMATICAL BOLD SCRIPT CAPITAL JMAT" +
"HEMATICAL BOLD SCRIPT CAPITAL KMATHEMATICAL BOLD SCRIPT CAPITAL LMATHEMA" +
"TICAL BOLD SCRIPT CAPITAL MMATHEMATICAL BOLD SCRIPT CAPITAL NMATHEMATICA" +
"L BOLD SCRIPT CAPITAL OMATHEMATICAL BOLD SCRIPT CAPITAL PMATHEMATICAL BO" +
"LD SCRIPT CAPITAL QMATHEMATICAL BOLD SCRIPT CAPITAL RMATHEMATICAL BOLD S" +
"CRIPT CAPITAL SMATHEMATICAL BOLD SCRIPT CAPITAL TMATHEMATICAL BOLD SCRIP" +
"T CAPITAL UMATHEMATICAL BOLD SCRIPT CAPITAL VMATHEMATICAL BOLD SCRIPT CA" +
"PITAL WMATHEMATICAL BOLD SCRIPT CAPITAL XMATHEMATICAL BOLD SCRIPT CAPITA" +
"L YMATHEMATICAL BOLD SCRIPT CAPITAL ZMATHEMATICAL BOLD SCRIPT SMALL AMAT" +
"HEMATICAL BOLD SCRIPT SMALL BMATHEMATICAL BOLD SCRIPT SMALL CMATHEMATICA" +
"L BOLD SCRIPT SMALL DMATHEMATICAL BOLD SCRIPT SMALL EMATHEMATICAL BOLD S" +
"CRIPT SMALL FMATHEMATICAL BOLD SCRIPT SMALL GMATHEMATICAL BOLD SCRIPT SM" +
"ALL HMATHEMATICAL BOLD SCRIPT SMALL IMATHEMATICAL BOLD SCRIPT SMALL JMAT" +
"HEMATICAL BOLD SCRIPT SMALL KMATHEMATICAL BOLD SCRIPT SMALL LMATHEMATICA" +
"L BOLD SCRIPT SMALL MMATHEMATICAL BOLD SCRIPT SMALL NMATHEMATICAL BOLD S") + ("" +
"CRIPT SMALL OMATHEMATICAL BOLD SCRIPT SMALL PMATHEMATICAL BOLD SCRIPT SM" +
"ALL QMATHEMATICAL BOLD SCRIPT SMALL RMATHEMATICAL BOLD SCRIPT SMALL SMAT" +
"HEMATICAL BOLD SCRIPT SMALL TMATHEMATICAL BOLD SCRIPT SMALL UMATHEMATICA" +
"L BOLD SCRIPT SMALL VMATHEMATICAL BOLD SCRIPT SMALL WMATHEMATICAL BOLD S" +
"CRIPT SMALL XMATHEMATICAL BOLD SCRIPT SMALL YMATHEMATICAL BOLD SCRIPT SM" +
"ALL ZMATHEMATICAL FRAKTUR CAPITAL AMATHEMATICAL FRAKTUR CAPITAL BMATHEMA" +
"TICAL FRAKTUR CAPITAL DMATHEMATICAL FRAKTUR CAPITAL EMATHEMATICAL FRAKTU" +
"R CAPITAL FMATHEMATICAL FRAKTUR CAPITAL GMATHEMATICAL FRAKTUR CAPITAL JM" +
"ATHEMATICAL FRAKTUR CAPITAL KMATHEMATICAL FRAKTUR CAPITAL LMATHEMATICAL " +
"FRAKTUR CAPITAL MMATHEMATICAL FRAKTUR CAPITAL NMATHEMATICAL FRAKTUR CAPI" +
"TAL OMATHEMATICAL FRAKTUR CAPITAL PMATHEMATICAL FRAKTUR CAPITAL QMATHEMA" +
"TICAL FRAKTUR CAPITAL SMATHEMATICAL FRAKTUR CAPITAL TMATHEMATICAL FRAKTU" +
"R CAPITAL UMATHEMATICAL FRAKTUR CAPITAL VMATHEMATICAL FRAKTUR CAPITAL WM" +
"ATHEMATICAL FRAKTUR CAPITAL XMATHEMATICAL FRAKTUR CAPITAL YMATHEMATICAL " +
"FRAKTUR SMALL AMATHEMATICAL FRAKTUR SMALL BMATHEMATICAL FRAKTUR SMALL CM" +
"ATHEMATICAL FRAKTUR SMALL DMATHEMATICAL FRAKTUR SMALL EMATHEMATICAL FRAK" +
"TUR SMALL FMATHEMATICAL FRAKTUR SMALL GMATHEMATICAL FRAKTUR SMALL HMATHE" +
"MATICAL FRAKTUR SMALL IMATHEMATICAL FRAKTUR SMALL JMATHEMATICAL FRAKTUR " +
"SMALL KMATHEMATICAL FRAKTUR SMALL LMATHEMATICAL FRAKTUR SMALL MMATHEMATI" +
"CAL FRAKTUR SMALL NMATHEMATICAL FRAKTUR SMALL OMATHEMATICAL FRAKTUR SMAL" +
"L PMATHEMATICAL FRAKTUR SMALL QMATHEMATICAL FRAKTUR SMALL RMATHEMATICAL " +
"FRAKTUR SMALL SMATHEMATICAL FRAKTUR SMALL TMATHEMATICAL FRAKTUR SMALL UM" +
"ATHEMATICAL FRAKTUR SMALL VMATHEMATICAL FRAKTUR SMALL WMATHEMATICAL FRAK" +
"TUR SMALL XMATHEMATICAL FRAKTUR SMALL YMATHEMATICAL FRAKTUR SMALL ZMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL AMATHEMATICAL DOUBLE-STRUCK CAPITAL BMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL DMATHEMATICAL DOUBLE-STRUCK CAPITAL EMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL FMATHEMATICAL DOUBLE-STRUCK CAPITAL GMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL IMATHEMATICAL DOUBLE-STRUCK CAPITAL JMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL KMATHEMATICAL DOUBLE-STRUCK CAPITAL LMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL MMATHEMATICAL DOUBLE-STRUCK CAPITAL OMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL SMATHEMATICAL DOUBLE-STRUCK CAPITAL TMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL UMATHEMATICAL DOUBLE-STRUCK CAPITAL VMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL WMATHEMATICAL DOUBLE-STRUCK CAPITAL XMATHE" +
"MATICAL DOUBLE-STRUCK CAPITAL YMATHEMATICAL DOUBLE-STRUCK SMALL AMATHEMA" +
"TICAL DOUBLE-STRUCK SMALL BMATHEMATICAL DOUBLE-STRUCK SMALL CMATHEMATICA" +
"L DOUBLE-STRUCK SMALL DMATHEMATICAL DOUBLE-STRUCK SMALL EMATHEMATICAL DO" +
"UBLE-STRUCK SMALL FMATHEMATICAL DOUBLE-STRUCK SMALL GMATHEMATICAL DOUBLE" +
"-STRUCK SMALL HMATHEMATICAL DOUBLE-STRUCK SMALL IMATHEMATICAL DOUBLE-STR" +
"UCK SMALL JMATHEMATICAL DOUBLE-STRUCK SMALL KMATHEMATICAL DOUBLE-STRUCK " +
"SMALL LMATHEMATICAL DOUBLE-STRUCK SMALL MMATHEMATICAL DOUBLE-STRUCK SMAL" +
"L NMATHEMATICAL DOUBLE-STRUCK SMALL OMATHEMATICAL DOUBLE-STRUCK SMALL PM" +
"ATHEMATICAL DOUBLE-STRUCK SMALL QMATHEMATICAL DOUBLE-STRUCK SMALL RMATHE" +
"MATICAL DOUBLE-STRUCK SMALL SMATHEMATICAL DOUBLE-STRUCK SMALL TMATHEMATI" +
"CAL DOUBLE-STRUCK SMALL UMATHEMATICAL DOUBLE-STRUCK SMALL VMATHEMATICAL " +
"DOUBLE-STRUCK SMALL WMATHEMATICAL DOUBLE-STRUCK SMALL XMATHEMATICAL DOUB" +
"LE-STRUCK SMALL YMATHEMATICAL DOUBLE-STRUCK SMALL ZMATHEMATICAL BOLD FRA" +
"KTUR CAPITAL AMATHEMATICAL BOLD FRAKTUR CAPITAL BMATHEMATICAL BOLD FRAKT" +
"UR CAPITAL CMATHEMATICAL BOLD FRAKTUR CAPITAL DMATHEMATICAL BOLD FRAKTUR" +
" CAPITAL EMATHEMATICAL BOLD FRAKTUR CAPITAL FMATHEMATICAL BOLD FRAKTUR C" +
"APITAL GMATHEMATICAL BOLD FRAKTUR CAPITAL HMATHEMATICAL BOLD FRAKTUR CAP" +
"ITAL IMATHEMATICAL BOLD FRAKTUR CAPITAL JMATHEMATICAL BOLD FRAKTUR CAPIT" +
"AL KMATHEMATICAL BOLD FRAKTUR CAPITAL LMATHEMATICAL BOLD FRAKTUR CAPITAL" +
" MMATHEMATICAL BOLD FRAKTUR CAPITAL NMATHEMATICAL BOLD FRAKTUR CAPITAL O" +
"MATHEMATICAL BOLD FRAKTUR CAPITAL PMATHEMATICAL BOLD FRAKTUR CAPITAL QMA" +
"THEMATICAL BOLD FRAKTUR CAPITAL RMATHEMATICAL BOLD FRAKTUR CAPITAL SMATH" +
"EMATICAL BOLD FRAKTUR CAPITAL TMATHEMATICAL BOLD FRAKTUR CAPITAL UMATHEM" +
"ATICAL BOLD FRAKTUR CAPITAL VMATHEMATICAL BOLD FRAKTUR CAPITAL WMATHEMAT" +
"ICAL BOLD FRAKTUR CAPITAL XMATHEMATICAL BOLD FRAKTUR CAPITAL YMATHEMATIC" +
"AL BOLD FRAKTUR CAPITAL ZMATHEMATICAL BOLD FRAKTUR SMALL AMATHEMATICAL B" +
"OLD FRAKTUR SMALL BMATHEMATICAL BOLD FRAKTUR SMALL CMATHEMATICAL BOLD FR" +
"AKTUR SMALL DMATHEMATICAL BOLD FRAKTUR SMALL EMATHEMATICAL BOLD FRAKTUR " +
"SMALL FMATHEMATICAL BOLD FRAKTUR SMALL GMATHEMATICAL BOLD FRAKTUR SMALL " +
"HMATHEMATICAL BOLD FRAKTUR SMALL IMATHEMATICAL BOLD FRAKTUR SMALL JMATHE" +
"MATICAL BOLD FRAKTUR SMALL KMATHEMATICAL BOLD FRAKTUR SMALL LMATHEMATICA") + ("" +
"L BOLD FRAKTUR SMALL MMATHEMATICAL BOLD FRAKTUR SMALL NMATHEMATICAL BOLD" +
" FRAKTUR SMALL OMATHEMATICAL BOLD FRAKTUR SMALL PMATHEMATICAL BOLD FRAKT" +
"UR SMALL QMATHEMATICAL BOLD FRAKTUR SMALL RMATHEMATICAL BOLD FRAKTUR SMA" +
"LL SMATHEMATICAL BOLD FRAKTUR SMALL TMATHEMATICAL BOLD FRAKTUR SMALL UMA" +
"THEMATICAL BOLD FRAKTUR SMALL VMATHEMATICAL BOLD FRAKTUR SMALL WMATHEMAT" +
"ICAL BOLD FRAKTUR SMALL XMATHEMATICAL BOLD FRAKTUR SMALL YMATHEMATICAL B" +
"OLD FRAKTUR SMALL ZMATHEMATICAL SANS-SERIF CAPITAL AMATHEMATICAL SANS-SE" +
"RIF CAPITAL BMATHEMATICAL SANS-SERIF CAPITAL CMATHEMATICAL SANS-SERIF CA" +
"PITAL DMATHEMATICAL SANS-SERIF CAPITAL EMATHEMATICAL SANS-SERIF CAPITAL " +
"FMATHEMATICAL SANS-SERIF CAPITAL GMATHEMATICAL SANS-SERIF CAPITAL HMATHE" +
"MATICAL SANS-SERIF CAPITAL IMATHEMATICAL SANS-SERIF CAPITAL JMATHEMATICA" +
"L SANS-SERIF CAPITAL KMATHEMATICAL SANS-SERIF CAPITAL LMATHEMATICAL SANS" +
"-SERIF CAPITAL MMATHEMATICAL SANS-SERIF CAPITAL NMATHEMATICAL SANS-SERIF" +
" CAPITAL OMATHEMATICAL SANS-SERIF CAPITAL PMATHEMATICAL SANS-SERIF CAPIT" +
"AL QMATHEMATICAL SANS-SERIF CAPITAL RMATHEMATICAL SANS-SERIF CAPITAL SMA" +
"THEMATICAL SANS-SERIF CAPITAL TMATHEMATICAL SANS-SERIF CAPITAL UMATHEMAT" +
"ICAL SANS-SERIF CAPITAL VMATHEMATICAL SANS-SERIF CAPITAL WMATHEMATICAL S" +
"ANS-SERIF CAPITAL XMATHEMATICAL SANS-SERIF CAPITAL YMATHEMATICAL SANS-SE" +
"RIF CAPITAL ZMATHEMATICAL SANS-SERIF SMALL AMATHEMATICAL SANS-SERIF SMAL" +
"L BMATHEMATICAL SANS-SERIF SMALL CMATHEMATICAL SANS-SERIF SMALL DMATHEMA" +
"TICAL SANS-SERIF SMALL EMATHEMATICAL SANS-SERIF SMALL FMATHEMATICAL SANS" +
"-SERIF SMALL GMATHEMATICAL SANS-SERIF SMALL HMATHEMATICAL SANS-SERIF SMA" +
"LL IMATHEMATICAL SANS-SERIF SMALL JMATHEMATICAL SANS-SERIF SMALL KMATHEM" +
"ATICAL SANS-SERIF SMALL LMATHEMATICAL SANS-SERIF SMALL MMATHEMATICAL SAN" +
"S-SERIF SMALL NMATHEMATICAL SANS-SERIF SMALL OMATHEMATICAL SANS-SERIF SM" +
"ALL PMATHEMATICAL SANS-SERIF SMALL QMATHEMATICAL SANS-SERIF SMALL RMATHE" +
"MATICAL SANS-SERIF SMALL SMATHEMATICAL SANS-SERIF SMALL TMATHEMATICAL SA" +
"NS-SERIF SMALL UMATHEMATICAL SANS-SERIF SMALL VMATHEMATICAL SANS-SERIF S" +
"MALL WMATHEMATICAL SANS-SERIF SMALL XMATHEMATICAL SANS-SERIF SMALL YMATH" +
"EMATICAL SANS-SERIF SMALL ZMATHEMATICAL SANS-SERIF BOLD CAPITAL AMATHEMA" +
"TICAL SANS-SERIF BOLD CAPITAL BMATHEMATICAL SANS-SERIF BOLD CAPITAL CMAT" +
"HEMATICAL SANS-SERIF BOLD CAPITAL DMATHEMATICAL SANS-SERIF BOLD CAPITAL " +
"EMATHEMATICAL SANS-SERIF BOLD CAPITAL FMATHEMATICAL SANS-SERIF BOLD CAPI" +
"TAL GMATHEMATICAL SANS-SERIF BOLD CAPITAL HMATHEMATICAL SANS-SERIF BOLD " +
"CAPITAL IMATHEMATICAL SANS-SERIF BOLD CAPITAL JMATHEMATICAL SANS-SERIF B" +
"OLD CAPITAL KMATHEMATICAL SANS-SERIF BOLD CAPITAL LMATHEMATICAL SANS-SER" +
"IF BOLD CAPITAL MMATHEMATICAL SANS-SERIF BOLD CAPITAL NMATHEMATICAL SANS" +
"-SERIF BOLD CAPITAL OMATHEMATICAL SANS-SERIF BOLD CAPITAL PMATHEMATICAL " +
"SANS-SERIF BOLD CAPITAL QMATHEMATICAL SANS-SERIF BOLD CAPITAL RMATHEMATI" +
"CAL SANS-SERIF BOLD CAPITAL SMATHEMATICAL SANS-SERIF BOLD CAPITAL TMATHE" +
"MATICAL SANS-SERIF BOLD CAPITAL UMATHEMATICAL SANS-SERIF BOLD CAPITAL VM" +
"ATHEMATICAL SANS-SERIF BOLD CAPITAL WMATHEMATICAL SANS-SERIF BOLD CAPITA" +
"L XMATHEMATICAL SANS-SERIF BOLD CAPITAL YMATHEMATICAL SANS-SERIF BOLD CA" +
"PITAL 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 ITALIC CAPITAL AMATHEMATICAL SANS-SERIF I" +
"TALIC CAPITAL BMATHEMATICAL SANS-SERIF ITALIC CAPITAL CMATHEMATICAL SANS" +
"-SERIF ITALIC CAPITAL DMATHEMATICAL SANS-SERIF ITALIC CAPITAL EMATHEMATI" +
"CAL SANS-SERIF ITALIC CAPITAL FMATHEMATICAL SANS-SERIF ITALIC CAPITAL GM" +
"ATHEMATICAL SANS-SERIF ITALIC CAPITAL HMATHEMATICAL SANS-SERIF ITALIC CA" +
"PITAL IMATHEMATICAL SANS-SERIF ITALIC CAPITAL JMATHEMATICAL SANS-SERIF I" +
"TALIC CAPITAL KMATHEMATICAL SANS-SERIF ITALIC CAPITAL LMATHEMATICAL SANS" +
"-SERIF ITALIC CAPITAL MMATHEMATICAL SANS-SERIF ITALIC CAPITAL NMATHEMATI") + ("" +
"CAL SANS-SERIF ITALIC CAPITAL OMATHEMATICAL SANS-SERIF ITALIC CAPITAL PM" +
"ATHEMATICAL SANS-SERIF ITALIC CAPITAL QMATHEMATICAL SANS-SERIF ITALIC CA" +
"PITAL RMATHEMATICAL SANS-SERIF ITALIC CAPITAL SMATHEMATICAL SANS-SERIF I" +
"TALIC CAPITAL TMATHEMATICAL SANS-SERIF ITALIC CAPITAL UMATHEMATICAL SANS" +
"-SERIF ITALIC CAPITAL VMATHEMATICAL SANS-SERIF ITALIC CAPITAL WMATHEMATI" +
"CAL SANS-SERIF ITALIC CAPITAL XMATHEMATICAL SANS-SERIF ITALIC CAPITAL YM" +
"ATHEMATICAL SANS-SERIF ITALIC CAPITAL ZMATHEMATICAL SANS-SERIF ITALIC SM" +
"ALL AMATHEMATICAL SANS-SERIF ITALIC SMALL BMATHEMATICAL SANS-SERIF ITALI" +
"C SMALL CMATHEMATICAL SANS-SERIF ITALIC SMALL DMATHEMATICAL SANS-SERIF I" +
"TALIC SMALL EMATHEMATICAL SANS-SERIF ITALIC SMALL FMATHEMATICAL SANS-SER" +
"IF ITALIC SMALL GMATHEMATICAL SANS-SERIF ITALIC SMALL HMATHEMATICAL SANS" +
"-SERIF ITALIC SMALL IMATHEMATICAL SANS-SERIF ITALIC SMALL JMATHEMATICAL " +
"SANS-SERIF ITALIC SMALL KMATHEMATICAL SANS-SERIF ITALIC SMALL LMATHEMATI" +
"CAL SANS-SERIF ITALIC SMALL MMATHEMATICAL SANS-SERIF ITALIC SMALL NMATHE" +
"MATICAL SANS-SERIF ITALIC SMALL OMATHEMATICAL SANS-SERIF ITALIC SMALL PM" +
"ATHEMATICAL SANS-SERIF ITALIC SMALL QMATHEMATICAL SANS-SERIF ITALIC SMAL" +
"L RMATHEMATICAL SANS-SERIF ITALIC SMALL SMATHEMATICAL SANS-SERIF ITALIC " +
"SMALL TMATHEMATICAL SANS-SERIF ITALIC SMALL UMATHEMATICAL SANS-SERIF ITA" +
"LIC SMALL VMATHEMATICAL SANS-SERIF ITALIC SMALL WMATHEMATICAL SANS-SERIF" +
" ITALIC SMALL XMATHEMATICAL SANS-SERIF ITALIC SMALL YMATHEMATICAL SANS-S" +
"ERIF ITALIC SMALL ZMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL AMATHEMAT" +
"ICAL SANS-SERIF BOLD ITALIC CAPITAL BMATHEMATICAL SANS-SERIF BOLD ITALIC" +
" CAPITAL CMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DMATHEMATICAL SANS" +
"-SERIF BOLD ITALIC CAPITAL EMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL " +
"FMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GMATHEMATICAL SANS-SERIF BO" +
"LD ITALIC CAPITAL HMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IMATHEMAT" +
"ICAL SANS-SERIF BOLD ITALIC CAPITAL JMATHEMATICAL SANS-SERIF BOLD ITALIC" +
" CAPITAL KMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LMATHEMATICAL SANS" +
"-SERIF BOLD ITALIC CAPITAL MMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL " +
"NMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMATHEMATICAL SANS-SERIF BO" +
"LD ITALIC CAPITAL PMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL QMATHEMAT" +
"ICAL SANS-SERIF BOLD ITALIC CAPITAL RMATHEMATICAL SANS-SERIF BOLD ITALIC" +
" CAPITAL SMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TMATHEMATICAL SANS" +
"-SERIF BOLD ITALIC CAPITAL UMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL " +
"VMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL WMATHEMATICAL SANS-SERIF BO" +
"LD ITALIC CAPITAL XMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL YMATHEMAT" +
"ICAL SANS-SERIF BOLD ITALIC CAPITAL ZMATHEMATICAL SANS-SERIF BOLD ITALIC" +
" SMALL AMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BMATHEMATICAL SANS-SER" +
"IF BOLD ITALIC SMALL CMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DMATHEMA" +
"TICAL SANS-SERIF BOLD ITALIC SMALL EMATHEMATICAL SANS-SERIF BOLD ITALIC " +
"SMALL FMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GMATHEMATICAL SANS-SERI" +
"F BOLD ITALIC SMALL HMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IMATHEMAT" +
"ICAL SANS-SERIF BOLD ITALIC SMALL JMATHEMATICAL SANS-SERIF BOLD ITALIC S" +
"MALL KMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LMATHEMATICAL SANS-SERIF" +
" BOLD ITALIC SMALL MMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NMATHEMATI" +
"CAL SANS-SERIF BOLD ITALIC SMALL OMATHEMATICAL SANS-SERIF BOLD ITALIC SM" +
"ALL PMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL QMATHEMATICAL SANS-SERIF " +
"BOLD ITALIC SMALL RMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SMATHEMATIC" +
"AL SANS-SERIF BOLD ITALIC SMALL TMATHEMATICAL SANS-SERIF BOLD ITALIC SMA" +
"LL UMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL VMATHEMATICAL SANS-SERIF B" +
"OLD ITALIC SMALL WMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XMATHEMATICA" +
"L SANS-SERIF BOLD ITALIC SMALL YMATHEMATICAL SANS-SERIF BOLD ITALIC SMAL" +
"L ZMATHEMATICAL MONOSPACE CAPITAL AMATHEMATICAL MONOSPACE CAPITAL BMATHE" +
"MATICAL MONOSPACE CAPITAL CMATHEMATICAL MONOSPACE CAPITAL DMATHEMATICAL " +
"MONOSPACE CAPITAL EMATHEMATICAL MONOSPACE CAPITAL FMATHEMATICAL MONOSPAC" +
"E CAPITAL GMATHEMATICAL MONOSPACE CAPITAL HMATHEMATICAL MONOSPACE CAPITA" +
"L IMATHEMATICAL MONOSPACE CAPITAL JMATHEMATICAL MONOSPACE CAPITAL KMATHE" +
"MATICAL MONOSPACE CAPITAL LMATHEMATICAL MONOSPACE CAPITAL MMATHEMATICAL " +
"MONOSPACE CAPITAL NMATHEMATICAL MONOSPACE CAPITAL OMATHEMATICAL MONOSPAC" +
"E CAPITAL PMATHEMATICAL MONOSPACE CAPITAL QMATHEMATICAL MONOSPACE CAPITA" +
"L RMATHEMATICAL MONOSPACE CAPITAL SMATHEMATICAL MONOSPACE CAPITAL TMATHE" +
"MATICAL MONOSPACE CAPITAL UMATHEMATICAL MONOSPACE CAPITAL VMATHEMATICAL " +
"MONOSPACE CAPITAL WMATHEMATICAL MONOSPACE CAPITAL XMATHEMATICAL MONOSPAC" +
"E CAPITAL YMATHEMATICAL MONOSPACE CAPITAL ZMATHEMATICAL MONOSPACE SMALL ") + ("" +
"AMATHEMATICAL MONOSPACE SMALL BMATHEMATICAL MONOSPACE SMALL CMATHEMATICA" +
"L MONOSPACE SMALL DMATHEMATICAL MONOSPACE SMALL EMATHEMATICAL MONOSPACE " +
"SMALL FMATHEMATICAL MONOSPACE SMALL GMATHEMATICAL MONOSPACE SMALL HMATHE" +
"MATICAL MONOSPACE SMALL IMATHEMATICAL MONOSPACE SMALL JMATHEMATICAL MONO" +
"SPACE SMALL KMATHEMATICAL MONOSPACE SMALL LMATHEMATICAL MONOSPACE SMALL " +
"MMATHEMATICAL MONOSPACE SMALL NMATHEMATICAL MONOSPACE SMALL OMATHEMATICA" +
"L MONOSPACE SMALL PMATHEMATICAL MONOSPACE SMALL QMATHEMATICAL MONOSPACE " +
"SMALL RMATHEMATICAL MONOSPACE SMALL SMATHEMATICAL MONOSPACE SMALL TMATHE" +
"MATICAL MONOSPACE SMALL UMATHEMATICAL MONOSPACE SMALL VMATHEMATICAL MONO" +
"SPACE SMALL WMATHEMATICAL MONOSPACE SMALL XMATHEMATICAL MONOSPACE SMALL " +
"YMATHEMATICAL MONOSPACE SMALL ZMATHEMATICAL ITALIC SMALL DOTLESS IMATHEM" +
"ATICAL ITALIC SMALL DOTLESS JMATHEMATICAL BOLD CAPITAL ALPHAMATHEMATICAL" +
" BOLD CAPITAL BETAMATHEMATICAL BOLD CAPITAL GAMMAMATHEMATICAL BOLD CAPIT" +
"AL DELTAMATHEMATICAL BOLD CAPITAL EPSILONMATHEMATICAL BOLD CAPITAL ZETAM" +
"ATHEMATICAL BOLD CAPITAL ETAMATHEMATICAL BOLD CAPITAL THETAMATHEMATICAL " +
"BOLD CAPITAL IOTAMATHEMATICAL BOLD CAPITAL KAPPAMATHEMATICAL BOLD CAPITA" +
"L LAMDAMATHEMATICAL BOLD CAPITAL MUMATHEMATICAL BOLD CAPITAL NUMATHEMATI" +
"CAL BOLD CAPITAL XIMATHEMATICAL BOLD CAPITAL OMICRONMATHEMATICAL BOLD CA" +
"PITAL PIMATHEMATICAL BOLD CAPITAL RHOMATHEMATICAL BOLD CAPITAL THETA SYM" +
"BOLMATHEMATICAL BOLD CAPITAL SIGMAMATHEMATICAL BOLD CAPITAL TAUMATHEMATI" +
"CAL BOLD CAPITAL UPSILONMATHEMATICAL BOLD CAPITAL PHIMATHEMATICAL BOLD C" +
"APITAL CHIMATHEMATICAL BOLD CAPITAL PSIMATHEMATICAL BOLD CAPITAL OMEGAMA" +
"THEMATICAL BOLD NABLAMATHEMATICAL BOLD SMALL ALPHAMATHEMATICAL BOLD SMAL" +
"L BETAMATHEMATICAL BOLD SMALL GAMMAMATHEMATICAL BOLD SMALL DELTAMATHEMAT" +
"ICAL BOLD SMALL EPSILONMATHEMATICAL BOLD SMALL ZETAMATHEMATICAL BOLD SMA" +
"LL ETAMATHEMATICAL BOLD SMALL THETAMATHEMATICAL BOLD SMALL IOTAMATHEMATI" +
"CAL BOLD SMALL KAPPAMATHEMATICAL BOLD SMALL LAMDAMATHEMATICAL BOLD SMALL" +
" MUMATHEMATICAL BOLD SMALL NUMATHEMATICAL BOLD SMALL XIMATHEMATICAL BOLD" +
" SMALL OMICRONMATHEMATICAL BOLD SMALL PIMATHEMATICAL BOLD SMALL RHOMATHE" +
"MATICAL BOLD SMALL FINAL SIGMAMATHEMATICAL BOLD SMALL SIGMAMATHEMATICAL " +
"BOLD SMALL TAUMATHEMATICAL BOLD SMALL UPSILONMATHEMATICAL BOLD SMALL PHI" +
"MATHEMATICAL BOLD SMALL CHIMATHEMATICAL BOLD SMALL PSIMATHEMATICAL BOLD " +
"SMALL OMEGAMATHEMATICAL BOLD PARTIAL DIFFERENTIALMATHEMATICAL BOLD EPSIL" +
"ON SYMBOLMATHEMATICAL BOLD THETA SYMBOLMATHEMATICAL BOLD KAPPA SYMBOLMAT" +
"HEMATICAL BOLD PHI SYMBOLMATHEMATICAL BOLD RHO SYMBOLMATHEMATICAL BOLD P" +
"I SYMBOLMATHEMATICAL ITALIC CAPITAL ALPHAMATHEMATICAL ITALIC CAPITAL BET" +
"AMATHEMATICAL ITALIC CAPITAL GAMMAMATHEMATICAL ITALIC CAPITAL DELTAMATHE" +
"MATICAL ITALIC CAPITAL EPSILONMATHEMATICAL ITALIC CAPITAL ZETAMATHEMATIC" +
"AL ITALIC CAPITAL ETAMATHEMATICAL ITALIC CAPITAL THETAMATHEMATICAL ITALI" +
"C CAPITAL IOTAMATHEMATICAL ITALIC CAPITAL KAPPAMATHEMATICAL ITALIC CAPIT" +
"AL LAMDAMATHEMATICAL ITALIC CAPITAL MUMATHEMATICAL ITALIC CAPITAL NUMATH" +
"EMATICAL ITALIC CAPITAL XIMATHEMATICAL ITALIC CAPITAL OMICRONMATHEMATICA" +
"L ITALIC CAPITAL PIMATHEMATICAL ITALIC CAPITAL RHOMATHEMATICAL ITALIC CA" +
"PITAL THETA SYMBOLMATHEMATICAL ITALIC CAPITAL SIGMAMATHEMATICAL ITALIC C" +
"APITAL TAUMATHEMATICAL ITALIC CAPITAL UPSILONMATHEMATICAL ITALIC CAPITAL" +
" PHIMATHEMATICAL ITALIC CAPITAL CHIMATHEMATICAL ITALIC CAPITAL PSIMATHEM" +
"ATICAL ITALIC CAPITAL OMEGAMATHEMATICAL ITALIC NABLAMATHEMATICAL ITALIC " +
"SMALL ALPHAMATHEMATICAL ITALIC SMALL BETAMATHEMATICAL ITALIC SMALL GAMMA" +
"MATHEMATICAL ITALIC SMALL DELTAMATHEMATICAL ITALIC SMALL EPSILONMATHEMAT" +
"ICAL ITALIC SMALL ZETAMATHEMATICAL ITALIC SMALL ETAMATHEMATICAL ITALIC S" +
"MALL THETAMATHEMATICAL ITALIC SMALL IOTAMATHEMATICAL ITALIC SMALL KAPPAM" +
"ATHEMATICAL ITALIC SMALL LAMDAMATHEMATICAL ITALIC SMALL MUMATHEMATICAL I" +
"TALIC SMALL NUMATHEMATICAL ITALIC SMALL XIMATHEMATICAL ITALIC SMALL OMIC" +
"RONMATHEMATICAL ITALIC SMALL PIMATHEMATICAL ITALIC SMALL RHOMATHEMATICAL" +
" ITALIC SMALL FINAL SIGMAMATHEMATICAL ITALIC SMALL SIGMAMATHEMATICAL ITA" +
"LIC SMALL TAUMATHEMATICAL ITALIC SMALL UPSILONMATHEMATICAL ITALIC SMALL " +
"PHIMATHEMATICAL ITALIC SMALL CHIMATHEMATICAL ITALIC SMALL PSIMATHEMATICA" +
"L ITALIC SMALL OMEGAMATHEMATICAL ITALIC PARTIAL DIFFERENTIALMATHEMATICAL" +
" ITALIC EPSILON SYMBOLMATHEMATICAL ITALIC THETA SYMBOLMATHEMATICAL ITALI" +
"C KAPPA SYMBOLMATHEMATICAL ITALIC PHI SYMBOLMATHEMATICAL ITALIC RHO SYMB" +
"OLMATHEMATICAL ITALIC PI SYMBOLMATHEMATICAL BOLD ITALIC CAPITAL ALPHAMAT" +
"HEMATICAL BOLD ITALIC CAPITAL BETAMATHEMATICAL BOLD ITALIC CAPITAL GAMMA" +
"MATHEMATICAL BOLD ITALIC CAPITAL DELTAMATHEMATICAL BOLD ITALIC CAPITAL E" +
"PSILONMATHEMATICAL BOLD ITALIC CAPITAL ZETAMATHEMATICAL BOLD ITALIC CAPI") + ("" +
"TAL ETAMATHEMATICAL BOLD ITALIC CAPITAL THETAMATHEMATICAL BOLD ITALIC CA" +
"PITAL IOTAMATHEMATICAL BOLD ITALIC CAPITAL KAPPAMATHEMATICAL BOLD ITALIC" +
" CAPITAL LAMDAMATHEMATICAL BOLD ITALIC CAPITAL MUMATHEMATICAL BOLD ITALI" +
"C CAPITAL NUMATHEMATICAL BOLD ITALIC CAPITAL XIMATHEMATICAL BOLD ITALIC " +
"CAPITAL OMICRONMATHEMATICAL BOLD ITALIC CAPITAL PIMATHEMATICAL BOLD ITAL" +
"IC CAPITAL RHOMATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOLMATHEMATICAL " +
"BOLD ITALIC CAPITAL SIGMAMATHEMATICAL BOLD ITALIC CAPITAL TAUMATHEMATICA" +
"L BOLD ITALIC CAPITAL UPSILONMATHEMATICAL BOLD ITALIC CAPITAL PHIMATHEMA" +
"TICAL BOLD ITALIC CAPITAL CHIMATHEMATICAL BOLD ITALIC CAPITAL PSIMATHEMA" +
"TICAL BOLD ITALIC CAPITAL OMEGAMATHEMATICAL BOLD ITALIC NABLAMATHEMATICA" +
"L BOLD ITALIC SMALL ALPHAMATHEMATICAL BOLD ITALIC SMALL BETAMATHEMATICAL" +
" BOLD ITALIC SMALL GAMMAMATHEMATICAL BOLD ITALIC SMALL DELTAMATHEMATICAL" +
" BOLD ITALIC SMALL EPSILONMATHEMATICAL BOLD ITALIC SMALL ZETAMATHEMATICA" +
"L BOLD ITALIC SMALL ETAMATHEMATICAL BOLD ITALIC SMALL THETAMATHEMATICAL " +
"BOLD ITALIC SMALL IOTAMATHEMATICAL BOLD ITALIC SMALL KAPPAMATHEMATICAL B" +
"OLD ITALIC SMALL LAMDAMATHEMATICAL BOLD ITALIC SMALL MUMATHEMATICAL BOLD" +
" ITALIC SMALL NUMATHEMATICAL BOLD ITALIC SMALL XIMATHEMATICAL BOLD ITALI" +
"C SMALL OMICRONMATHEMATICAL BOLD ITALIC SMALL PIMATHEMATICAL BOLD ITALIC" +
" SMALL RHOMATHEMATICAL BOLD ITALIC SMALL FINAL SIGMAMATHEMATICAL BOLD IT" +
"ALIC SMALL SIGMAMATHEMATICAL BOLD ITALIC SMALL TAUMATHEMATICAL BOLD ITAL" +
"IC SMALL UPSILONMATHEMATICAL BOLD ITALIC SMALL PHIMATHEMATICAL BOLD ITAL" +
"IC SMALL CHIMATHEMATICAL BOLD ITALIC SMALL PSIMATHEMATICAL BOLD ITALIC S" +
"MALL OMEGAMATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIALMATHEMATICAL BOLD" +
" ITALIC EPSILON SYMBOLMATHEMATICAL BOLD ITALIC THETA SYMBOLMATHEMATICAL " +
"BOLD ITALIC KAPPA SYMBOLMATHEMATICAL BOLD ITALIC PHI SYMBOLMATHEMATICAL " +
"BOLD ITALIC RHO SYMBOLMATHEMATICAL BOLD ITALIC PI SYMBOLMATHEMATICAL SAN" +
"S-SERIF BOLD CAPITAL ALPHAMATHEMATICAL SANS-SERIF BOLD CAPITAL BETAMATHE" +
"MATICAL SANS-SERIF BOLD CAPITAL GAMMAMATHEMATICAL SANS-SERIF BOLD CAPITA" +
"L DELTAMATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILONMATHEMATICAL SANS-SER" +
"IF BOLD CAPITAL ZETAMATHEMATICAL SANS-SERIF BOLD CAPITAL ETAMATHEMATICAL" +
" SANS-SERIF BOLD CAPITAL THETAMATHEMATICAL SANS-SERIF BOLD CAPITAL IOTAM" +
"ATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPAMATHEMATICAL SANS-SERIF BOLD CA" +
"PITAL LAMDAMATHEMATICAL SANS-SERIF BOLD CAPITAL MUMATHEMATICAL SANS-SERI" +
"F BOLD CAPITAL NUMATHEMATICAL SANS-SERIF BOLD CAPITAL XIMATHEMATICAL SAN" +
"S-SERIF BOLD CAPITAL OMICRONMATHEMATICAL SANS-SERIF BOLD CAPITAL PIMATHE" +
"MATICAL SANS-SERIF BOLD CAPITAL RHOMATHEMATICAL SANS-SERIF BOLD CAPITAL " +
"THETA SYMBOLMATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMAMATHEMATICAL SANS-" +
"SERIF BOLD CAPITAL TAUMATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILONMATHEM" +
"ATICAL SANS-SERIF BOLD CAPITAL PHIMATHEMATICAL SANS-SERIF BOLD CAPITAL C" +
"HIMATHEMATICAL SANS-SERIF BOLD CAPITAL PSIMATHEMATICAL SANS-SERIF BOLD C" +
"APITAL OMEGAMATHEMATICAL SANS-SERIF BOLD NABLAMATHEMATICAL SANS-SERIF BO" +
"LD SMALL ALPHAMATHEMATICAL SANS-SERIF BOLD SMALL BETAMATHEMATICAL SANS-S" +
"ERIF BOLD SMALL GAMMAMATHEMATICAL SANS-SERIF BOLD SMALL DELTAMATHEMATICA" +
"L SANS-SERIF BOLD SMALL EPSILONMATHEMATICAL SANS-SERIF BOLD SMALL ZETAMA" +
"THEMATICAL SANS-SERIF BOLD SMALL ETAMATHEMATICAL SANS-SERIF BOLD SMALL T" +
"HETAMATHEMATICAL SANS-SERIF BOLD SMALL IOTAMATHEMATICAL SANS-SERIF BOLD " +
"SMALL KAPPAMATHEMATICAL SANS-SERIF BOLD SMALL LAMDAMATHEMATICAL SANS-SER" +
"IF BOLD SMALL MUMATHEMATICAL SANS-SERIF BOLD SMALL NUMATHEMATICAL SANS-S" +
"ERIF BOLD SMALL XIMATHEMATICAL SANS-SERIF BOLD SMALL OMICRONMATHEMATICAL" +
" SANS-SERIF BOLD SMALL PIMATHEMATICAL SANS-SERIF BOLD SMALL RHOMATHEMATI" +
"CAL SANS-SERIF BOLD SMALL FINAL SIGMAMATHEMATICAL SANS-SERIF BOLD SMALL " +
"SIGMAMATHEMATICAL SANS-SERIF BOLD SMALL TAUMATHEMATICAL SANS-SERIF BOLD " +
"SMALL UPSILONMATHEMATICAL SANS-SERIF BOLD SMALL PHIMATHEMATICAL SANS-SER" +
"IF BOLD SMALL CHIMATHEMATICAL SANS-SERIF BOLD SMALL PSIMATHEMATICAL SANS" +
"-SERIF BOLD SMALL OMEGAMATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL" +
"MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOLMATHEMATICAL SANS-SERIF BOLD " +
"THETA SYMBOLMATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOLMATHEMATICAL SANS-S" +
"ERIF BOLD PHI SYMBOLMATHEMATICAL SANS-SERIF BOLD RHO SYMBOLMATHEMATICAL " +
"SANS-SERIF BOLD PI SYMBOLMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALP" +
"HAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETAMATHEMATICAL SANS-SERI" +
"F BOLD ITALIC CAPITAL GAMMAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D" +
"ELTAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILONMATHEMATICAL SANS" +
"-SERIF BOLD ITALIC CAPITAL ZETAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPIT" +
"AL ETAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETAMATHEMATICAL SANS") + ("" +
"-SERIF BOLD ITALIC CAPITAL IOTAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPIT" +
"AL KAPPAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDAMATHEMATICAL SA" +
"NS-SERIF BOLD ITALIC CAPITAL MUMATHEMATICAL SANS-SERIF BOLD ITALIC CAPIT" +
"AL NUMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XIMATHEMATICAL SANS-SER" +
"IF BOLD ITALIC CAPITAL OMICRONMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITA" +
"L PIMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHOMATHEMATICAL SANS-SER" +
"IF BOLD ITALIC CAPITAL THETA SYMBOLMATHEMATICAL SANS-SERIF BOLD ITALIC C" +
"APITAL SIGMAMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAUMATHEMATICAL " +
"SANS-SERIF BOLD ITALIC CAPITAL UPSILONMATHEMATICAL SANS-SERIF BOLD ITALI" +
"C CAPITAL PHIMATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHIMATHEMATICAL" +
" SANS-SERIF BOLD ITALIC CAPITAL PSIMATHEMATICAL SANS-SERIF BOLD ITALIC C" +
"APITAL OMEGAMATHEMATICAL SANS-SERIF BOLD ITALIC NABLAMATHEMATICAL SANS-S" +
"ERIF BOLD ITALIC SMALL ALPHAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BE" +
"TAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMAMATHEMATICAL SANS-SERIF" +
" BOLD ITALIC SMALL DELTAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILO" +
"NMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETAMATHEMATICAL SANS-SERIF B" +
"OLD ITALIC SMALL ETAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETAMATHE" +
"MATICAL SANS-SERIF BOLD ITALIC SMALL IOTAMATHEMATICAL SANS-SERIF BOLD IT" +
"ALIC SMALL KAPPAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDAMATHEMATI" +
"CAL SANS-SERIF BOLD ITALIC SMALL MUMATHEMATICAL SANS-SERIF BOLD ITALIC S" +
"MALL NUMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XIMATHEMATICAL SANS-SER" +
"IF BOLD ITALIC SMALL OMICRONMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI" +
"MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHOMATHEMATICAL SANS-SERIF BOL" +
"D ITALIC SMALL FINAL SIGMAMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGM" +
"AMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAUMATHEMATICAL SANS-SERIF BO" +
"LD ITALIC SMALL UPSILONMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHIMATH" +
"EMATICAL SANS-SERIF BOLD ITALIC SMALL CHIMATHEMATICAL SANS-SERIF BOLD IT" +
"ALIC SMALL PSIMATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGAMATHEMATICA" +
"L SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIALMATHEMATICAL SANS-SERIF BOL" +
"D ITALIC EPSILON SYMBOLMATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOLM" +
"ATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOLMATHEMATICAL SANS-SERIF B" +
"OLD ITALIC PHI SYMBOLMATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOLMATHE" +
"MATICAL SANS-SERIF BOLD ITALIC PI SYMBOLMATHEMATICAL BOLD CAPITAL DIGAMM" +
"AMATHEMATICAL BOLD SMALL DIGAMMAMATHEMATICAL BOLD DIGIT ZEROMATHEMATICAL" +
" BOLD DIGIT ONEMATHEMATICAL BOLD DIGIT TWOMATHEMATICAL BOLD DIGIT THREEM" +
"ATHEMATICAL BOLD DIGIT FOURMATHEMATICAL BOLD DIGIT FIVEMATHEMATICAL BOLD" +
" DIGIT SIXMATHEMATICAL BOLD DIGIT SEVENMATHEMATICAL BOLD DIGIT EIGHTMATH" +
"EMATICAL BOLD DIGIT NINEMATHEMATICAL DOUBLE-STRUCK DIGIT ZEROMATHEMATICA" +
"L DOUBLE-STRUCK DIGIT ONEMATHEMATICAL DOUBLE-STRUCK DIGIT TWOMATHEMATICA" +
"L DOUBLE-STRUCK DIGIT THREEMATHEMATICAL DOUBLE-STRUCK DIGIT FOURMATHEMAT" +
"ICAL DOUBLE-STRUCK DIGIT FIVEMATHEMATICAL DOUBLE-STRUCK DIGIT SIXMATHEMA" +
"TICAL DOUBLE-STRUCK DIGIT SEVENMATHEMATICAL DOUBLE-STRUCK DIGIT EIGHTMAT" +
"HEMATICAL DOUBLE-STRUCK DIGIT NINEMATHEMATICAL SANS-SERIF DIGIT ZEROMATH" +
"EMATICAL SANS-SERIF DIGIT ONEMATHEMATICAL SANS-SERIF DIGIT TWOMATHEMATIC" +
"AL SANS-SERIF DIGIT THREEMATHEMATICAL SANS-SERIF DIGIT FOURMATHEMATICAL " +
"SANS-SERIF DIGIT FIVEMATHEMATICAL SANS-SERIF DIGIT SIXMATHEMATICAL SANS-" +
"SERIF DIGIT SEVENMATHEMATICAL SANS-SERIF DIGIT EIGHTMATHEMATICAL SANS-SE" +
"RIF DIGIT NINEMATHEMATICAL SANS-SERIF BOLD DIGIT ZEROMATHEMATICAL SANS-S" +
"ERIF BOLD DIGIT ONEMATHEMATICAL SANS-SERIF BOLD DIGIT TWOMATHEMATICAL SA" +
"NS-SERIF BOLD DIGIT THREEMATHEMATICAL SANS-SERIF BOLD DIGIT FOURMATHEMAT" +
"ICAL SANS-SERIF BOLD DIGIT FIVEMATHEMATICAL SANS-SERIF BOLD DIGIT SIXMAT" +
"HEMATICAL SANS-SERIF BOLD DIGIT SEVENMATHEMATICAL SANS-SERIF BOLD DIGIT " +
"EIGHTMATHEMATICAL SANS-SERIF BOLD DIGIT NINEMATHEMATICAL MONOSPACE DIGIT" +
" ZEROMATHEMATICAL MONOSPACE DIGIT ONEMATHEMATICAL MONOSPACE DIGIT TWOMAT" +
"HEMATICAL MONOSPACE DIGIT THREEMATHEMATICAL MONOSPACE DIGIT FOURMATHEMAT" +
"ICAL MONOSPACE DIGIT FIVEMATHEMATICAL MONOSPACE DIGIT SIXMATHEMATICAL MO" +
"NOSPACE DIGIT SEVENMATHEMATICAL MONOSPACE DIGIT EIGHTMATHEMATICAL MONOSP" +
"ACE DIGIT NINESIGNWRITING HAND-FIST INDEXSIGNWRITING HAND-CIRCLE INDEXSI" +
"GNWRITING HAND-CUP INDEXSIGNWRITING HAND-OVAL INDEXSIGNWRITING HAND-HING" +
"E INDEXSIGNWRITING HAND-ANGLE INDEXSIGNWRITING HAND-FIST INDEX BENTSIGNW" +
"RITING HAND-CIRCLE INDEX BENTSIGNWRITING HAND-FIST THUMB UNDER INDEX BEN" +
"TSIGNWRITING HAND-FIST INDEX RAISED KNUCKLESIGNWRITING HAND-FIST INDEX C" +
"UPPEDSIGNWRITING HAND-FIST INDEX HINGEDSIGNWRITING HAND-FIST INDEX HINGE" +
"D LOWSIGNWRITING HAND-CIRCLE INDEX HINGESIGNWRITING HAND-FIST INDEX MIDD") + ("" +
"LESIGNWRITING HAND-CIRCLE INDEX MIDDLESIGNWRITING HAND-FIST INDEX MIDDLE" +
" BENTSIGNWRITING HAND-FIST INDEX MIDDLE RAISED KNUCKLESSIGNWRITING HAND-" +
"FIST INDEX MIDDLE HINGEDSIGNWRITING HAND-FIST INDEX UP MIDDLE HINGEDSIGN" +
"WRITING HAND-FIST INDEX HINGED MIDDLE UPSIGNWRITING HAND-FIST INDEX MIDD" +
"LE CONJOINEDSIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED INDEX BENTSIGNW" +
"RITING HAND-FIST INDEX MIDDLE CONJOINED MIDDLE BENTSIGNWRITING HAND-FIST" +
" INDEX MIDDLE CONJOINED CUPPEDSIGNWRITING HAND-FIST INDEX MIDDLE CONJOIN" +
"ED HINGEDSIGNWRITING HAND-FIST INDEX MIDDLE CROSSEDSIGNWRITING HAND-CIRC" +
"LE INDEX MIDDLE CROSSEDSIGNWRITING HAND-FIST MIDDLE BENT OVER INDEXSIGNW" +
"RITING HAND-FIST INDEX BENT OVER MIDDLESIGNWRITING HAND-FIST INDEX MIDDL" +
"E THUMBSIGNWRITING HAND-CIRCLE INDEX MIDDLE THUMBSIGNWRITING HAND-FIST I" +
"NDEX MIDDLE STRAIGHT THUMB BENTSIGNWRITING HAND-FIST INDEX MIDDLE BENT T" +
"HUMB STRAIGHTSIGNWRITING HAND-FIST INDEX MIDDLE THUMB BENTSIGNWRITING HA" +
"ND-FIST INDEX MIDDLE HINGED SPREAD THUMB SIDESIGNWRITING HAND-FIST INDEX" +
" UP MIDDLE HINGED THUMB SIDESIGNWRITING HAND-FIST INDEX UP MIDDLE HINGED" +
" THUMB CONJOINEDSIGNWRITING HAND-FIST INDEX HINGED MIDDLE UP THUMB SIDES" +
"IGNWRITING HAND-FIST INDEX MIDDLE UP SPREAD THUMB FORWARDSIGNWRITING HAN" +
"D-FIST INDEX MIDDLE THUMB CUPPEDSIGNWRITING HAND-FIST INDEX MIDDLE THUMB" +
" CIRCLEDSIGNWRITING HAND-FIST INDEX MIDDLE THUMB HOOKEDSIGNWRITING HAND-" +
"FIST INDEX MIDDLE THUMB HINGEDSIGNWRITING HAND-FIST THUMB BETWEEN INDEX " +
"MIDDLE STRAIGHTSIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDESI" +
"GNWRITING HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE CONJOINEDSIGNWRITI" +
"NG HAND-FIST INDEX MIDDLE CONJOINED THUMB SIDE BENTSIGNWRITING HAND-FIST" +
" MIDDLE THUMB HOOKED INDEX UPSIGNWRITING HAND-FIST INDEX THUMB HOOKED MI" +
"DDLE UPSIGNWRITING HAND-FIST INDEX MIDDLE CONJOINED HINGED THUMB SIDESIG" +
"NWRITING HAND-FIST INDEX MIDDLE CROSSED THUMB SIDESIGNWRITING HAND-FIST " +
"INDEX MIDDLE CONJOINED THUMB FORWARDSIGNWRITING HAND-FIST INDEX MIDDLE C" +
"ONJOINED CUPPED THUMB FORWARDSIGNWRITING HAND-FIST MIDDLE THUMB CUPPED I" +
"NDEX UPSIGNWRITING HAND-FIST INDEX THUMB CUPPED MIDDLE UPSIGNWRITING HAN" +
"D-FIST MIDDLE THUMB CIRCLED INDEX UPSIGNWRITING HAND-FIST MIDDLE THUMB C" +
"IRCLED INDEX HINGEDSIGNWRITING HAND-FIST INDEX THUMB ANGLED OUT MIDDLE U" +
"PSIGNWRITING HAND-FIST INDEX THUMB ANGLED IN MIDDLE UPSIGNWRITING HAND-F" +
"IST INDEX THUMB CIRCLED MIDDLE UPSIGNWRITING HAND-FIST INDEX MIDDLE THUM" +
"B CONJOINED HINGEDSIGNWRITING HAND-FIST INDEX MIDDLE THUMB ANGLED OUTSIG" +
"NWRITING HAND-FIST INDEX MIDDLE THUMB ANGLEDSIGNWRITING HAND-FIST MIDDLE" +
" THUMB ANGLED OUT INDEX UPSIGNWRITING HAND-FIST MIDDLE THUMB ANGLED OUT " +
"INDEX CROSSEDSIGNWRITING HAND-FIST MIDDLE THUMB ANGLED INDEX UPSIGNWRITI" +
"NG HAND-FIST INDEX THUMB HOOKED MIDDLE HINGEDSIGNWRITING HAND-FLAT FOUR " +
"FINGERSSIGNWRITING HAND-FLAT FOUR FINGERS BENTSIGNWRITING HAND-FLAT FOUR" +
" FINGERS HINGEDSIGNWRITING HAND-FLAT FOUR FINGERS CONJOINEDSIGNWRITING H" +
"AND-FLAT FOUR FINGERS CONJOINED SPLITSIGNWRITING HAND-CLAW FOUR FINGERS " +
"CONJOINEDSIGNWRITING HAND-FIST FOUR FINGERS CONJOINED BENTSIGNWRITING HA" +
"ND-HINGE FOUR FINGERS CONJOINEDSIGNWRITING HAND-FLAT FIVE FINGERS SPREAD" +
"SIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREADSIGNWRITING HAND-FLAT FIVE" +
" FINGERS SPREAD FOUR BENTSIGNWRITING HAND-FLAT HEEL FIVE FINGERS SPREAD " +
"FOUR BENTSIGNWRITING HAND-FLAT FIVE FINGERS SPREAD BENTSIGNWRITING HAND-" +
"FLAT HEEL FIVE FINGERS SPREAD BENTSIGNWRITING HAND-FLAT FIVE FINGERS SPR" +
"EAD THUMB FORWARDSIGNWRITING HAND-CUP FIVE FINGERS SPREADSIGNWRITING HAN" +
"D-CUP FIVE FINGERS SPREAD OPENSIGNWRITING HAND-HINGE FIVE FINGERS SPREAD" +
" OPENSIGNWRITING HAND-OVAL FIVE FINGERS SPREADSIGNWRITING HAND-FLAT FIVE" +
" FINGERS SPREAD HINGEDSIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED T" +
"HUMB SIDESIGNWRITING HAND-FLAT FIVE FINGERS SPREAD HINGED NO THUMBSIGNWR" +
"ITING HAND-FLATSIGNWRITING HAND-FLAT BETWEEN PALM FACINGSSIGNWRITING HAN" +
"D-FLAT HEELSIGNWRITING HAND-FLAT THUMB SIDESIGNWRITING HAND-FLAT HEEL TH" +
"UMB SIDESIGNWRITING HAND-FLAT THUMB BENTSIGNWRITING HAND-FLAT THUMB FORW" +
"ARDSIGNWRITING HAND-FLAT SPLIT INDEX THUMB SIDESIGNWRITING HAND-FLAT SPL" +
"IT CENTRESIGNWRITING HAND-FLAT SPLIT CENTRE THUMB SIDESIGNWRITING HAND-F" +
"LAT SPLIT CENTRE THUMB SIDE BENTSIGNWRITING HAND-FLAT SPLIT LITTLESIGNWR" +
"ITING HAND-CLAWSIGNWRITING HAND-CLAW THUMB SIDESIGNWRITING HAND-CLAW NO " +
"THUMBSIGNWRITING HAND-CLAW THUMB FORWARDSIGNWRITING HAND-HOOK CURLICUESI" +
"GNWRITING HAND-HOOKSIGNWRITING HAND-CUP OPENSIGNWRITING HAND-CUPSIGNWRIT" +
"ING HAND-CUP OPEN THUMB SIDESIGNWRITING HAND-CUP THUMB SIDESIGNWRITING H" +
"AND-CUP OPEN NO THUMBSIGNWRITING HAND-CUP NO THUMBSIGNWRITING HAND-CUP O" +
"PEN THUMB FORWARDSIGNWRITING HAND-CUP THUMB FORWARDSIGNWRITING HAND-CURL") + ("" +
"ICUE OPENSIGNWRITING HAND-CURLICUESIGNWRITING HAND-CIRCLESIGNWRITING HAN" +
"D-OVALSIGNWRITING HAND-OVAL THUMB SIDESIGNWRITING HAND-OVAL NO THUMBSIGN" +
"WRITING HAND-OVAL THUMB FORWARDSIGNWRITING HAND-HINGE OPENSIGNWRITING HA" +
"ND-HINGE OPEN THUMB FORWARDSIGNWRITING HAND-HINGESIGNWRITING HAND-HINGE " +
"SMALLSIGNWRITING HAND-HINGE OPEN THUMB SIDESIGNWRITING HAND-HINGE THUMB " +
"SIDESIGNWRITING HAND-HINGE OPEN NO THUMBSIGNWRITING HAND-HINGE NO THUMBS" +
"IGNWRITING HAND-HINGE THUMB SIDE TOUCHING INDEXSIGNWRITING HAND-HINGE TH" +
"UMB BETWEEN MIDDLE RINGSIGNWRITING HAND-ANGLESIGNWRITING HAND-FIST INDEX" +
" MIDDLE RINGSIGNWRITING HAND-CIRCLE INDEX MIDDLE RINGSIGNWRITING HAND-HI" +
"NGE INDEX MIDDLE RINGSIGNWRITING HAND-ANGLE INDEX MIDDLE RINGSIGNWRITING" +
" HAND-HINGE LITTLESIGNWRITING HAND-FIST INDEX MIDDLE RING BENTSIGNWRITIN" +
"G HAND-FIST INDEX MIDDLE RING CONJOINEDSIGNWRITING HAND-HINGE INDEX MIDD" +
"LE RING CONJOINEDSIGNWRITING HAND-FIST LITTLE DOWNSIGNWRITING HAND-FIST " +
"LITTLE DOWN RIPPLE STRAIGHTSIGNWRITING HAND-FIST LITTLE DOWN RIPPLE CURV" +
"EDSIGNWRITING HAND-FIST LITTLE DOWN OTHERS CIRCLEDSIGNWRITING HAND-FIST " +
"LITTLE UPSIGNWRITING HAND-FIST THUMB UNDER LITTLE UPSIGNWRITING HAND-CIR" +
"CLE LITTLE UPSIGNWRITING HAND-OVAL LITTLE UPSIGNWRITING HAND-ANGLE LITTL" +
"E UPSIGNWRITING HAND-FIST LITTLE RAISED KNUCKLESIGNWRITING HAND-FIST LIT" +
"TLE BENTSIGNWRITING HAND-FIST LITTLE TOUCHES THUMBSIGNWRITING HAND-FIST " +
"LITTLE THUMBSIGNWRITING HAND-HINGE LITTLE THUMBSIGNWRITING HAND-FIST LIT" +
"TLE INDEX THUMBSIGNWRITING HAND-HINGE LITTLE INDEX THUMBSIGNWRITING HAND" +
"-ANGLE LITTLE INDEX THUMB INDEX THUMB OUTSIGNWRITING HAND-ANGLE LITTLE I" +
"NDEX THUMB INDEX THUMBSIGNWRITING HAND-FIST LITTLE INDEXSIGNWRITING HAND" +
"-CIRCLE LITTLE INDEXSIGNWRITING HAND-HINGE LITTLE INDEXSIGNWRITING HAND-" +
"ANGLE LITTLE INDEXSIGNWRITING HAND-FIST INDEX MIDDLE LITTLESIGNWRITING H" +
"AND-CIRCLE INDEX MIDDLE LITTLESIGNWRITING HAND-HINGE INDEX MIDDLE LITTLE" +
"SIGNWRITING HAND-HINGE RINGSIGNWRITING HAND-ANGLE INDEX MIDDLE LITTLESIG" +
"NWRITING HAND-FIST INDEX MIDDLE CROSS LITTLESIGNWRITING HAND-CIRCLE INDE" +
"X MIDDLE CROSS LITTLESIGNWRITING HAND-FIST RING DOWNSIGNWRITING HAND-HIN" +
"GE RING DOWN INDEX THUMB HOOK MIDDLESIGNWRITING HAND-ANGLE RING DOWN MID" +
"DLE THUMB INDEX CROSSSIGNWRITING HAND-FIST RING UPSIGNWRITING HAND-FIST " +
"RING RAISED KNUCKLESIGNWRITING HAND-FIST RING LITTLESIGNWRITING HAND-CIR" +
"CLE RING LITTLESIGNWRITING HAND-OVAL RING LITTLESIGNWRITING HAND-ANGLE R" +
"ING LITTLESIGNWRITING HAND-FIST RING MIDDLESIGNWRITING HAND-FIST RING MI" +
"DDLE CONJOINEDSIGNWRITING HAND-FIST RING MIDDLE RAISED KNUCKLESSIGNWRITI" +
"NG HAND-FIST RING INDEXSIGNWRITING HAND-FIST RING THUMBSIGNWRITING HAND-" +
"HOOK RING THUMBSIGNWRITING HAND-FIST INDEX RING LITTLESIGNWRITING HAND-C" +
"IRCLE INDEX RING LITTLESIGNWRITING HAND-CURLICUE INDEX RING LITTLE ONSIG" +
"NWRITING HAND-HOOK INDEX RING LITTLE OUTSIGNWRITING HAND-HOOK INDEX RING" +
" LITTLE INSIGNWRITING HAND-HOOK INDEX RING LITTLE UNDERSIGNWRITING HAND-" +
"CUP INDEX RING LITTLESIGNWRITING HAND-HINGE INDEX RING LITTLESIGNWRITING" +
" HAND-ANGLE INDEX RING LITTLE OUTSIGNWRITING HAND-ANGLE INDEX RING LITTL" +
"ESIGNWRITING HAND-FIST MIDDLE DOWNSIGNWRITING HAND-HINGE MIDDLESIGNWRITI" +
"NG HAND-FIST MIDDLE UPSIGNWRITING HAND-CIRCLE MIDDLE UPSIGNWRITING HAND-" +
"FIST MIDDLE RAISED KNUCKLESIGNWRITING HAND-FIST MIDDLE UP THUMB SIDESIGN" +
"WRITING HAND-HOOK MIDDLE THUMBSIGNWRITING HAND-FIST MIDDLE THUMB LITTLES" +
"IGNWRITING HAND-FIST MIDDLE LITTLESIGNWRITING HAND-FIST MIDDLE RING LITT" +
"LESIGNWRITING HAND-CIRCLE MIDDLE RING LITTLESIGNWRITING HAND-CURLICUE MI" +
"DDLE RING LITTLE ONSIGNWRITING HAND-CUP MIDDLE RING LITTLESIGNWRITING HA" +
"ND-HINGE MIDDLE RING LITTLESIGNWRITING HAND-ANGLE MIDDLE RING LITTLE OUT" +
"SIGNWRITING HAND-ANGLE MIDDLE RING LITTLE INSIGNWRITING HAND-ANGLE MIDDL" +
"E RING LITTLESIGNWRITING HAND-CIRCLE MIDDLE RING LITTLE BENTSIGNWRITING " +
"HAND-CLAW MIDDLE RING LITTLE CONJOINEDSIGNWRITING HAND-CLAW MIDDLE RING " +
"LITTLE CONJOINED SIDESIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED " +
"OUTSIGNWRITING HAND-HOOK MIDDLE RING LITTLE CONJOINED INSIGNWRITING HAND" +
"-HOOK MIDDLE RING LITTLE CONJOINEDSIGNWRITING HAND-HINGE INDEX HINGEDSIG" +
"NWRITING HAND-FIST INDEX THUMB SIDESIGNWRITING HAND-HINGE INDEX THUMB SI" +
"DESIGNWRITING HAND-FIST INDEX THUMB SIDE THUMB DIAGONALSIGNWRITING HAND-" +
"FIST INDEX THUMB SIDE THUMB CONJOINEDSIGNWRITING HAND-FIST INDEX THUMB S" +
"IDE THUMB BENTSIGNWRITING HAND-FIST INDEX THUMB SIDE INDEX BENTSIGNWRITI" +
"NG HAND-FIST INDEX THUMB SIDE BOTH BENTSIGNWRITING HAND-FIST INDEX THUMB" +
" SIDE INDEX HINGESIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX STRAIGH" +
"TSIGNWRITING HAND-FIST INDEX THUMB FORWARD INDEX BENTSIGNWRITING HAND-FI" +
"ST INDEX THUMB HOOKSIGNWRITING HAND-FIST INDEX THUMB CURLICUESIGNWRITING") + ("" +
" HAND-FIST INDEX THUMB CURVE THUMB INSIDESIGNWRITING HAND-CLAW INDEX THU" +
"MB CURVE THUMB INSIDESIGNWRITING HAND-FIST INDEX THUMB CURVE THUMB UNDER" +
"SIGNWRITING HAND-FIST INDEX THUMB CIRCLESIGNWRITING HAND-CUP INDEX THUMB" +
"SIGNWRITING HAND-CUP INDEX THUMB OPENSIGNWRITING HAND-HINGE INDEX THUMB " +
"OPENSIGNWRITING HAND-HINGE INDEX THUMB LARGESIGNWRITING HAND-HINGE INDEX" +
" THUMBSIGNWRITING HAND-HINGE INDEX THUMB SMALLSIGNWRITING HAND-ANGLE IND" +
"EX THUMB OUTSIGNWRITING HAND-ANGLE INDEX THUMB INSIGNWRITING HAND-ANGLE " +
"INDEX THUMBSIGNWRITING HAND-FIST THUMBSIGNWRITING HAND-FIST THUMB HEELSI" +
"GNWRITING HAND-FIST THUMB SIDE DIAGONALSIGNWRITING HAND-FIST THUMB SIDE " +
"CONJOINEDSIGNWRITING HAND-FIST THUMB SIDE BENTSIGNWRITING HAND-FIST THUM" +
"B FORWARDSIGNWRITING HAND-FIST THUMB BETWEEN INDEX MIDDLESIGNWRITING HAN" +
"D-FIST THUMB BETWEEN MIDDLE RINGSIGNWRITING HAND-FIST THUMB BETWEEN RING" +
" LITTLESIGNWRITING HAND-FIST THUMB UNDER TWO FINGERSSIGNWRITING HAND-FIS" +
"T THUMB OVER TWO FINGERSSIGNWRITING HAND-FIST THUMB UNDER THREE FINGERSS" +
"IGNWRITING HAND-FIST THUMB UNDER FOUR FINGERSSIGNWRITING HAND-FIST THUMB" +
" OVER FOUR RAISED KNUCKLESSIGNWRITING HAND-FISTSIGNWRITING HAND-FIST HEE" +
"LSIGNWRITING TOUCH SINGLESIGNWRITING TOUCH MULTIPLESIGNWRITING TOUCH BET" +
"WEENSIGNWRITING GRASP SINGLESIGNWRITING GRASP MULTIPLESIGNWRITING GRASP " +
"BETWEENSIGNWRITING STRIKE SINGLESIGNWRITING STRIKE MULTIPLESIGNWRITING S" +
"TRIKE BETWEENSIGNWRITING BRUSH SINGLESIGNWRITING BRUSH MULTIPLESIGNWRITI" +
"NG BRUSH BETWEENSIGNWRITING RUB SINGLESIGNWRITING RUB MULTIPLESIGNWRITIN" +
"G RUB BETWEENSIGNWRITING SURFACE SYMBOLSSIGNWRITING SURFACE BETWEENSIGNW" +
"RITING SQUEEZE LARGE SINGLESIGNWRITING SQUEEZE SMALL SINGLESIGNWRITING S" +
"QUEEZE LARGE MULTIPLESIGNWRITING SQUEEZE SMALL MULTIPLESIGNWRITING SQUEE" +
"ZE SEQUENTIALSIGNWRITING FLICK LARGE SINGLESIGNWRITING FLICK SMALL SINGL" +
"ESIGNWRITING FLICK LARGE MULTIPLESIGNWRITING FLICK SMALL MULTIPLESIGNWRI" +
"TING FLICK SEQUENTIALSIGNWRITING SQUEEZE FLICK ALTERNATINGSIGNWRITING MO" +
"VEMENT-HINGE UP DOWN LARGESIGNWRITING MOVEMENT-HINGE UP DOWN SMALLSIGNWR" +
"ITING MOVEMENT-HINGE UP SEQUENTIALSIGNWRITING MOVEMENT-HINGE DOWN SEQUEN" +
"TIALSIGNWRITING MOVEMENT-HINGE UP DOWN ALTERNATING LARGESIGNWRITING MOVE" +
"MENT-HINGE UP DOWN ALTERNATING SMALLSIGNWRITING MOVEMENT-HINGE SIDE TO S" +
"IDE SCISSORSSIGNWRITING MOVEMENT-WALLPLANE FINGER CONTACTSIGNWRITING MOV" +
"EMENT-FLOORPLANE FINGER CONTACTSIGNWRITING MOVEMENT-WALLPLANE SINGLE STR" +
"AIGHT SMALLSIGNWRITING MOVEMENT-WALLPLANE SINGLE STRAIGHT MEDIUMSIGNWRIT" +
"ING MOVEMENT-WALLPLANE SINGLE STRAIGHT LARGESIGNWRITING MOVEMENT-WALLPLA" +
"NE SINGLE STRAIGHT LARGESTSIGNWRITING MOVEMENT-WALLPLANE SINGLE WRIST FL" +
"EXSIGNWRITING MOVEMENT-WALLPLANE DOUBLE STRAIGHTSIGNWRITING MOVEMENT-WAL" +
"LPLANE DOUBLE WRIST FLEXSIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATIN" +
"GSIGNWRITING MOVEMENT-WALLPLANE DOUBLE ALTERNATING WRIST FLEXSIGNWRITING" +
" MOVEMENT-WALLPLANE CROSSSIGNWRITING MOVEMENT-WALLPLANE TRIPLE STRAIGHT " +
"MOVEMENTSIGNWRITING MOVEMENT-WALLPLANE TRIPLE WRIST FLEXSIGNWRITING MOVE" +
"MENT-WALLPLANE TRIPLE ALTERNATINGSIGNWRITING MOVEMENT-WALLPLANE TRIPLE A" +
"LTERNATING WRIST FLEXSIGNWRITING MOVEMENT-WALLPLANE BEND SMALLSIGNWRITIN" +
"G MOVEMENT-WALLPLANE BEND MEDIUMSIGNWRITING MOVEMENT-WALLPLANE BEND LARG" +
"ESIGNWRITING MOVEMENT-WALLPLANE CORNER SMALLSIGNWRITING MOVEMENT-WALLPLA" +
"NE CORNER MEDIUMSIGNWRITING MOVEMENT-WALLPLANE CORNER LARGESIGNWRITING M" +
"OVEMENT-WALLPLANE CORNER ROTATIONSIGNWRITING MOVEMENT-WALLPLANE CHECK SM" +
"ALLSIGNWRITING MOVEMENT-WALLPLANE CHECK MEDIUMSIGNWRITING MOVEMENT-WALLP" +
"LANE CHECK LARGESIGNWRITING MOVEMENT-WALLPLANE BOX SMALLSIGNWRITING MOVE" +
"MENT-WALLPLANE BOX MEDIUMSIGNWRITING MOVEMENT-WALLPLANE BOX LARGESIGNWRI" +
"TING MOVEMENT-WALLPLANE ZIGZAG SMALLSIGNWRITING MOVEMENT-WALLPLANE ZIGZA" +
"G MEDIUMSIGNWRITING MOVEMENT-WALLPLANE ZIGZAG LARGESIGNWRITING MOVEMENT-" +
"WALLPLANE PEAKS SMALLSIGNWRITING MOVEMENT-WALLPLANE PEAKS MEDIUMSIGNWRIT" +
"ING MOVEMENT-WALLPLANE PEAKS LARGESIGNWRITING TRAVEL-WALLPLANE ROTATION-" +
"WALLPLANE SINGLESIGNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE DOUBLESI" +
"GNWRITING TRAVEL-WALLPLANE ROTATION-WALLPLANE ALTERNATINGSIGNWRITING TRA" +
"VEL-WALLPLANE ROTATION-FLOORPLANE SINGLESIGNWRITING TRAVEL-WALLPLANE ROT" +
"ATION-FLOORPLANE DOUBLESIGNWRITING TRAVEL-WALLPLANE ROTATION-FLOORPLANE " +
"ALTERNATINGSIGNWRITING TRAVEL-WALLPLANE SHAKINGSIGNWRITING TRAVEL-WALLPL" +
"ANE ARM SPIRAL SINGLESIGNWRITING TRAVEL-WALLPLANE ARM SPIRAL DOUBLESIGNW" +
"RITING TRAVEL-WALLPLANE ARM SPIRAL TRIPLESIGNWRITING MOVEMENT-DIAGONAL A" +
"WAY SMALLSIGNWRITING MOVEMENT-DIAGONAL AWAY MEDIUMSIGNWRITING MOVEMENT-D" +
"IAGONAL AWAY LARGESIGNWRITING MOVEMENT-DIAGONAL AWAY LARGESTSIGNWRITING " +
"MOVEMENT-DIAGONAL TOWARDS SMALLSIGNWRITING MOVEMENT-DIAGONAL TOWARDS MED") + ("" +
"IUMSIGNWRITING MOVEMENT-DIAGONAL TOWARDS LARGESIGNWRITING MOVEMENT-DIAGO" +
"NAL TOWARDS LARGESTSIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY SMALLSIGNW" +
"RITING MOVEMENT-DIAGONAL BETWEEN AWAY MEDIUMSIGNWRITING MOVEMENT-DIAGONA" +
"L BETWEEN AWAY LARGESIGNWRITING MOVEMENT-DIAGONAL BETWEEN AWAY LARGESTSI" +
"GNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS SMALLSIGNWRITING MOVEMENT-DI" +
"AGONAL BETWEEN TOWARDS MEDIUMSIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWAR" +
"DS LARGESIGNWRITING MOVEMENT-DIAGONAL BETWEEN TOWARDS LARGESTSIGNWRITING" +
" MOVEMENT-FLOORPLANE SINGLE STRAIGHT SMALLSIGNWRITING MOVEMENT-FLOORPLAN" +
"E SINGLE STRAIGHT MEDIUMSIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT " +
"LARGESIGNWRITING MOVEMENT-FLOORPLANE SINGLE STRAIGHT LARGESTSIGNWRITING " +
"MOVEMENT-FLOORPLANE SINGLE WRIST FLEXSIGNWRITING MOVEMENT-FLOORPLANE DOU" +
"BLE STRAIGHTSIGNWRITING MOVEMENT-FLOORPLANE DOUBLE WRIST FLEXSIGNWRITING" +
" MOVEMENT-FLOORPLANE DOUBLE ALTERNATINGSIGNWRITING MOVEMENT-FLOORPLANE D" +
"OUBLE ALTERNATING WRIST FLEXSIGNWRITING MOVEMENT-FLOORPLANE CROSSSIGNWRI" +
"TING MOVEMENT-FLOORPLANE TRIPLE STRAIGHT MOVEMENTSIGNWRITING MOVEMENT-FL" +
"OORPLANE TRIPLE WRIST FLEXSIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNA" +
"TING MOVEMENTSIGNWRITING MOVEMENT-FLOORPLANE TRIPLE ALTERNATING WRIST FL" +
"EXSIGNWRITING MOVEMENT-FLOORPLANE BENDSIGNWRITING MOVEMENT-FLOORPLANE CO" +
"RNER SMALLSIGNWRITING MOVEMENT-FLOORPLANE CORNER MEDIUMSIGNWRITING MOVEM" +
"ENT-FLOORPLANE CORNER LARGESIGNWRITING MOVEMENT-FLOORPLANE CHECKSIGNWRIT" +
"ING MOVEMENT-FLOORPLANE BOX SMALLSIGNWRITING MOVEMENT-FLOORPLANE BOX MED" +
"IUMSIGNWRITING MOVEMENT-FLOORPLANE BOX LARGESIGNWRITING MOVEMENT-FLOORPL" +
"ANE ZIGZAG SMALLSIGNWRITING MOVEMENT-FLOORPLANE ZIGZAG MEDIUMSIGNWRITING" +
" MOVEMENT-FLOORPLANE ZIGZAG LARGESIGNWRITING MOVEMENT-FLOORPLANE PEAKS S" +
"MALLSIGNWRITING MOVEMENT-FLOORPLANE PEAKS MEDIUMSIGNWRITING MOVEMENT-FLO" +
"ORPLANE PEAKS LARGESIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE SIN" +
"GLESIGNWRITING TRAVEL-FLOORPLANE ROTATION-FLOORPLANE DOUBLESIGNWRITING T" +
"RAVEL-FLOORPLANE ROTATION-FLOORPLANE ALTERNATINGSIGNWRITING TRAVEL-FLOOR" +
"PLANE ROTATION-WALLPLANE SINGLESIGNWRITING TRAVEL-FLOORPLANE ROTATION-WA" +
"LLPLANE DOUBLESIGNWRITING TRAVEL-FLOORPLANE ROTATION-WALLPLANE ALTERNATI" +
"NGSIGNWRITING TRAVEL-FLOORPLANE SHAKINGSIGNWRITING MOVEMENT-WALLPLANE CU" +
"RVE QUARTER SMALLSIGNWRITING MOVEMENT-WALLPLANE CURVE QUARTER MEDIUMSIGN" +
"WRITING MOVEMENT-WALLPLANE CURVE QUARTER LARGESIGNWRITING MOVEMENT-WALLP" +
"LANE CURVE QUARTER LARGESTSIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRC" +
"LE SMALLSIGNWRITING MOVEMENT-WALLPLANE CURVE HALF-CIRCLE MEDIUMSIGNWRITI" +
"NG MOVEMENT-WALLPLANE CURVE HALF-CIRCLE LARGESIGNWRITING MOVEMENT-WALLPL" +
"ANE CURVE HALF-CIRCLE LARGESTSIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-" +
"QUARTER CIRCLE SMALLSIGNWRITING MOVEMENT-WALLPLANE CURVE THREE-QUARTER C" +
"IRCLE MEDIUMSIGNWRITING MOVEMENT-WALLPLANE HUMP SMALLSIGNWRITING MOVEMEN" +
"T-WALLPLANE HUMP MEDIUMSIGNWRITING MOVEMENT-WALLPLANE HUMP LARGESIGNWRIT" +
"ING MOVEMENT-WALLPLANE LOOP SMALLSIGNWRITING MOVEMENT-WALLPLANE LOOP MED" +
"IUMSIGNWRITING MOVEMENT-WALLPLANE LOOP LARGESIGNWRITING MOVEMENT-WALLPLA" +
"NE LOOP SMALL DOUBLESIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE SMA" +
"LLSIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE DOUBLE MEDIUMSIGNWRITING MOV" +
"EMENT-WALLPLANE WAVE CURVE DOUBLE LARGESIGNWRITING MOVEMENT-WALLPLANE WA" +
"VE CURVE TRIPLE SMALLSIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE ME" +
"DIUMSIGNWRITING MOVEMENT-WALLPLANE WAVE CURVE TRIPLE LARGESIGNWRITING MO" +
"VEMENT-WALLPLANE CURVE THEN STRAIGHTSIGNWRITING MOVEMENT-WALLPLANE CURVE" +
"D CROSS SMALLSIGNWRITING MOVEMENT-WALLPLANE CURVED CROSS MEDIUMSIGNWRITI" +
"NG ROTATION-WALLPLANE SINGLESIGNWRITING ROTATION-WALLPLANE DOUBLESIGNWRI" +
"TING ROTATION-WALLPLANE ALTERNATESIGNWRITING MOVEMENT-WALLPLANE SHAKINGS" +
"IGNWRITING MOVEMENT-WALLPLANE CURVE HITTING FRONT WALLSIGNWRITING MOVEME" +
"NT-WALLPLANE HUMP HITTING FRONT WALLSIGNWRITING MOVEMENT-WALLPLANE LOOP " +
"HITTING FRONT WALLSIGNWRITING MOVEMENT-WALLPLANE WAVE HITTING FRONT WALL" +
"SIGNWRITING ROTATION-WALLPLANE SINGLE HITTING FRONT WALLSIGNWRITING ROTA" +
"TION-WALLPLANE DOUBLE HITTING FRONT WALLSIGNWRITING ROTATION-WALLPLANE A" +
"LTERNATING HITTING FRONT WALLSIGNWRITING MOVEMENT-WALLPLANE CURVE HITTIN" +
"G CHESTSIGNWRITING MOVEMENT-WALLPLANE HUMP HITTING CHESTSIGNWRITING MOVE" +
"MENT-WALLPLANE LOOP HITTING CHESTSIGNWRITING MOVEMENT-WALLPLANE WAVE HIT" +
"TING CHESTSIGNWRITING ROTATION-WALLPLANE SINGLE HITTING CHESTSIGNWRITING" +
" ROTATION-WALLPLANE DOUBLE HITTING CHESTSIGNWRITING ROTATION-WALLPLANE A" +
"LTERNATING HITTING CHESTSIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PAT" +
"H SMALLSIGNWRITING MOVEMENT-WALLPLANE WAVE DIAGONAL PATH MEDIUMSIGNWRITI" +
"NG MOVEMENT-WALLPLANE WAVE DIAGONAL PATH LARGESIGNWRITING MOVEMENT-FLOOR") + ("" +
"PLANE CURVE HITTING CEILING SMALLSIGNWRITING MOVEMENT-FLOORPLANE CURVE H" +
"ITTING CEILING LARGESIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING" +
" SMALL DOUBLESIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE " +
"DOUBLESIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING SMALL TRIPLES" +
"IGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING CEILING LARGE TRIPLESIGNWRIT" +
"ING MOVEMENT-FLOORPLANE LOOP HITTING CEILING SMALL SINGLESIGNWRITING MOV" +
"EMENT-FLOORPLANE LOOP HITTING CEILING LARGE SINGLESIGNWRITING MOVEMENT-F" +
"LOORPLANE LOOP HITTING CEILING SMALL DOUBLESIGNWRITING MOVEMENT-FLOORPLA" +
"NE LOOP HITTING CEILING LARGE DOUBLESIGNWRITING MOVEMENT-FLOORPLANE WAVE" +
" HITTING CEILING SMALLSIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING CEILI" +
"NG LARGESIGNWRITING ROTATION-FLOORPLANE SINGLE HITTING CEILINGSIGNWRITIN" +
"G ROTATION-FLOORPLANE DOUBLE HITTING CEILINGSIGNWRITING ROTATION-FLOORPL" +
"ANE ALTERNATING HITTING CEILINGSIGNWRITING MOVEMENT-FLOORPLANE CURVE HIT" +
"TING FLOOR SMALLSIGNWRITING MOVEMENT-FLOORPLANE CURVE HITTING FLOOR LARG" +
"ESIGNWRITING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR SMALL DOUBLESIGNWRIT" +
"ING MOVEMENT-FLOORPLANE HUMP HITTING FLOOR LARGE DOUBLESIGNWRITING MOVEM" +
"ENT-FLOORPLANE HUMP HITTING FLOOR TRIPLE SMALL TRIPLESIGNWRITING MOVEMEN" +
"T-FLOORPLANE HUMP HITTING FLOOR TRIPLE LARGE TRIPLESIGNWRITING MOVEMENT-" +
"FLOORPLANE LOOP HITTING FLOOR SMALL SINGLESIGNWRITING MOVEMENT-FLOORPLAN" +
"E LOOP HITTING FLOOR LARGE SINGLESIGNWRITING MOVEMENT-FLOORPLANE LOOP HI" +
"TTING FLOOR SMALL DOUBLESIGNWRITING MOVEMENT-FLOORPLANE LOOP HITTING FLO" +
"OR LARGE DOUBLESIGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR SMALLS" +
"IGNWRITING MOVEMENT-FLOORPLANE WAVE HITTING FLOOR LARGESIGNWRITING ROTAT" +
"ION-FLOORPLANE SINGLE HITTING FLOORSIGNWRITING ROTATION-FLOORPLANE DOUBL" +
"E HITTING FLOORSIGNWRITING ROTATION-FLOORPLANE ALTERNATING HITTING FLOOR" +
"SIGNWRITING MOVEMENT-FLOORPLANE CURVE SMALLSIGNWRITING MOVEMENT-FLOORPLA" +
"NE CURVE MEDIUMSIGNWRITING MOVEMENT-FLOORPLANE CURVE LARGESIGNWRITING MO" +
"VEMENT-FLOORPLANE CURVE LARGESTSIGNWRITING MOVEMENT-FLOORPLANE CURVE COM" +
"BINEDSIGNWRITING MOVEMENT-FLOORPLANE HUMP SMALLSIGNWRITING MOVEMENT-FLOO" +
"RPLANE LOOP SMALLSIGNWRITING MOVEMENT-FLOORPLANE WAVE SNAKESIGNWRITING M" +
"OVEMENT-FLOORPLANE WAVE SMALLSIGNWRITING MOVEMENT-FLOORPLANE WAVE LARGES" +
"IGNWRITING ROTATION-FLOORPLANE SINGLESIGNWRITING ROTATION-FLOORPLANE DOU" +
"BLESIGNWRITING ROTATION-FLOORPLANE ALTERNATINGSIGNWRITING MOVEMENT-FLOOR" +
"PLANE SHAKING PARALLELSIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE SMALL SI" +
"NGLESIGNWRITING MOVEMENT-WALLPLANE ARM CIRCLE MEDIUM SINGLESIGNWRITING M" +
"OVEMENT-WALLPLANE ARM CIRCLE SMALL DOUBLESIGNWRITING MOVEMENT-WALLPLANE " +
"ARM CIRCLE MEDIUM DOUBLESIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTI" +
"NG WALL SMALL SINGLESIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING W" +
"ALL MEDIUM SINGLESIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL" +
" LARGE SINGLESIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL SMA" +
"LL DOUBLESIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL MEDIUM " +
"DOUBLESIGNWRITING MOVEMENT-FLOORPLANE ARM CIRCLE HITTING WALL LARGE DOUB" +
"LESIGNWRITING MOVEMENT-WALLPLANE WRIST CIRCLE FRONT SINGLESIGNWRITING MO" +
"VEMENT-WALLPLANE WRIST CIRCLE FRONT DOUBLESIGNWRITING MOVEMENT-FLOORPLAN" +
"E WRIST CIRCLE HITTING WALL SINGLESIGNWRITING MOVEMENT-FLOORPLANE WRIST " +
"CIRCLE HITTING WALL DOUBLESIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES " +
"SINGLESIGNWRITING MOVEMENT-WALLPLANE FINGER CIRCLES DOUBLESIGNWRITING MO" +
"VEMENT-FLOORPLANE FINGER CIRCLES HITTING WALL SINGLESIGNWRITING MOVEMENT" +
"-FLOORPLANE FINGER CIRCLES HITTING WALL DOUBLESIGNWRITING DYNAMIC ARROWH" +
"EAD SMALLSIGNWRITING DYNAMIC ARROWHEAD LARGESIGNWRITING DYNAMIC FASTSIGN" +
"WRITING DYNAMIC SLOWSIGNWRITING DYNAMIC TENSESIGNWRITING DYNAMIC RELAXED" +
"SIGNWRITING DYNAMIC SIMULTANEOUSSIGNWRITING DYNAMIC SIMULTANEOUS ALTERNA" +
"TINGSIGNWRITING DYNAMIC EVERY OTHER TIMESIGNWRITING DYNAMIC GRADUALSIGNW" +
"RITING HEADSIGNWRITING HEAD RIMSIGNWRITING HEAD MOVEMENT-WALLPLANE STRAI" +
"GHTSIGNWRITING HEAD MOVEMENT-WALLPLANE TILTSIGNWRITING HEAD MOVEMENT-FLO" +
"ORPLANE STRAIGHTSIGNWRITING HEAD MOVEMENT-WALLPLANE CURVESIGNWRITING HEA" +
"D MOVEMENT-FLOORPLANE CURVESIGNWRITING HEAD MOVEMENT CIRCLESIGNWRITING F" +
"ACE DIRECTION POSITION NOSE FORWARD TILTINGSIGNWRITING FACE DIRECTION PO" +
"SITION NOSE UP OR DOWNSIGNWRITING FACE DIRECTION POSITION NOSE UP OR DOW" +
"N TILTINGSIGNWRITING EYEBROWS STRAIGHT UPSIGNWRITING EYEBROWS STRAIGHT N" +
"EUTRALSIGNWRITING EYEBROWS STRAIGHT DOWNSIGNWRITING DREAMY EYEBROWS NEUT" +
"RAL DOWNSIGNWRITING DREAMY EYEBROWS DOWN NEUTRALSIGNWRITING DREAMY EYEBR" +
"OWS UP NEUTRALSIGNWRITING DREAMY EYEBROWS NEUTRAL UPSIGNWRITING FOREHEAD" +
" NEUTRALSIGNWRITING FOREHEAD CONTACTSIGNWRITING FOREHEAD WRINKLEDSIGNWRI") + ("" +
"TING EYES OPENSIGNWRITING EYES SQUEEZEDSIGNWRITING EYES CLOSEDSIGNWRITIN" +
"G EYE BLINK SINGLESIGNWRITING EYE BLINK MULTIPLESIGNWRITING EYES HALF OP" +
"ENSIGNWRITING EYES WIDE OPENSIGNWRITING EYES HALF CLOSEDSIGNWRITING EYES" +
" WIDENING MOVEMENTSIGNWRITING EYE WINKSIGNWRITING EYELASHES UPSIGNWRITIN" +
"G EYELASHES DOWNSIGNWRITING EYELASHES FLUTTERINGSIGNWRITING EYEGAZE-WALL" +
"PLANE STRAIGHTSIGNWRITING EYEGAZE-WALLPLANE STRAIGHT DOUBLESIGNWRITING E" +
"YEGAZE-WALLPLANE STRAIGHT ALTERNATINGSIGNWRITING EYEGAZE-FLOORPLANE STRA" +
"IGHTSIGNWRITING EYEGAZE-FLOORPLANE STRAIGHT DOUBLESIGNWRITING EYEGAZE-FL" +
"OORPLANE STRAIGHT ALTERNATINGSIGNWRITING EYEGAZE-WALLPLANE CURVEDSIGNWRI" +
"TING EYEGAZE-FLOORPLANE CURVEDSIGNWRITING EYEGAZE-WALLPLANE CIRCLINGSIGN" +
"WRITING CHEEKS PUFFEDSIGNWRITING CHEEKS NEUTRALSIGNWRITING CHEEKS SUCKED" +
"SIGNWRITING TENSE CHEEKS HIGHSIGNWRITING TENSE CHEEKS MIDDLESIGNWRITING " +
"TENSE CHEEKS LOWSIGNWRITING EARSSIGNWRITING NOSE NEUTRALSIGNWRITING NOSE" +
" CONTACTSIGNWRITING NOSE WRINKLESSIGNWRITING NOSE WIGGLESSIGNWRITING AIR" +
" BLOWING OUTSIGNWRITING AIR SUCKING INSIGNWRITING AIR BLOW SMALL ROTATIO" +
"NSSIGNWRITING AIR SUCK SMALL ROTATIONSSIGNWRITING BREATH INHALESIGNWRITI" +
"NG BREATH EXHALESIGNWRITING MOUTH CLOSED NEUTRALSIGNWRITING MOUTH CLOSED" +
" FORWARDSIGNWRITING MOUTH CLOSED CONTACTSIGNWRITING MOUTH SMILESIGNWRITI" +
"NG MOUTH SMILE WRINKLEDSIGNWRITING MOUTH SMILE OPENSIGNWRITING MOUTH FRO" +
"WNSIGNWRITING MOUTH FROWN WRINKLEDSIGNWRITING MOUTH FROWN OPENSIGNWRITIN" +
"G MOUTH OPEN CIRCLESIGNWRITING MOUTH OPEN FORWARDSIGNWRITING MOUTH OPEN " +
"WRINKLEDSIGNWRITING MOUTH OPEN OVALSIGNWRITING MOUTH OPEN OVAL WRINKLEDS" +
"IGNWRITING MOUTH OPEN OVAL YAWNSIGNWRITING MOUTH OPEN RECTANGLESIGNWRITI" +
"NG MOUTH OPEN RECTANGLE WRINKLEDSIGNWRITING MOUTH OPEN RECTANGLE YAWNSIG" +
"NWRITING MOUTH KISSSIGNWRITING MOUTH KISS FORWARDSIGNWRITING MOUTH KISS " +
"WRINKLEDSIGNWRITING MOUTH TENSESIGNWRITING MOUTH TENSE FORWARDSIGNWRITIN" +
"G MOUTH TENSE SUCKEDSIGNWRITING LIPS PRESSED TOGETHERSIGNWRITING LIP LOW" +
"ER OVER UPPERSIGNWRITING LIP UPPER OVER LOWERSIGNWRITING MOUTH CORNERSSI" +
"GNWRITING MOUTH WRINKLES SINGLESIGNWRITING MOUTH WRINKLES DOUBLESIGNWRIT" +
"ING TONGUE STICKING OUT FARSIGNWRITING TONGUE LICKING LIPSSIGNWRITING TO" +
"NGUE TIP BETWEEN LIPSSIGNWRITING TONGUE TIP TOUCHING INSIDE MOUTHSIGNWRI" +
"TING TONGUE INSIDE MOUTH RELAXEDSIGNWRITING TONGUE MOVES AGAINST CHEEKSI" +
"GNWRITING TONGUE CENTRE STICKING OUTSIGNWRITING TONGUE CENTRE INSIDE MOU" +
"THSIGNWRITING TEETHSIGNWRITING TEETH MOVEMENTSIGNWRITING TEETH ON TONGUE" +
"SIGNWRITING TEETH ON TONGUE MOVEMENTSIGNWRITING TEETH ON LIPSSIGNWRITING" +
" TEETH ON LIPS MOVEMENTSIGNWRITING TEETH BITE LIPSSIGNWRITING MOVEMENT-W" +
"ALLPLANE JAWSIGNWRITING MOVEMENT-FLOORPLANE JAWSIGNWRITING NECKSIGNWRITI" +
"NG HAIRSIGNWRITING EXCITEMENTSIGNWRITING SHOULDER HIP SPINESIGNWRITING S" +
"HOULDER HIP POSITIONSSIGNWRITING WALLPLANE SHOULDER HIP MOVESIGNWRITING " +
"FLOORPLANE SHOULDER HIP MOVESIGNWRITING SHOULDER TILTING FROM WAISTSIGNW" +
"RITING TORSO-WALLPLANE STRAIGHT STRETCHSIGNWRITING TORSO-WALLPLANE CURVE" +
"D BENDSIGNWRITING TORSO-FLOORPLANE TWISTINGSIGNWRITING UPPER BODY TILTIN" +
"G FROM HIP JOINTSSIGNWRITING LIMB COMBINATIONSIGNWRITING LIMB LENGTH-1SI" +
"GNWRITING LIMB LENGTH-2SIGNWRITING LIMB LENGTH-3SIGNWRITING LIMB LENGTH-" +
"4SIGNWRITING LIMB LENGTH-5SIGNWRITING LIMB LENGTH-6SIGNWRITING LIMB LENG" +
"TH-7SIGNWRITING FINGERSIGNWRITING LOCATION-WALLPLANE SPACESIGNWRITING LO" +
"CATION-FLOORPLANE SPACESIGNWRITING LOCATION HEIGHTSIGNWRITING LOCATION W" +
"IDTHSIGNWRITING LOCATION DEPTHSIGNWRITING LOCATION HEAD NECKSIGNWRITING " +
"LOCATION TORSOSIGNWRITING LOCATION LIMBS DIGITSSIGNWRITING COMMASIGNWRIT" +
"ING FULL STOPSIGNWRITING SEMICOLONSIGNWRITING COLONSIGNWRITING PARENTHES" +
"ISSIGNWRITING FILL MODIFIER-2SIGNWRITING FILL MODIFIER-3SIGNWRITING FILL" +
" MODIFIER-4SIGNWRITING FILL MODIFIER-5SIGNWRITING FILL MODIFIER-6SIGNWRI" +
"TING ROTATION MODIFIER-2SIGNWRITING ROTATION MODIFIER-3SIGNWRITING ROTAT" +
"ION MODIFIER-4SIGNWRITING ROTATION MODIFIER-5SIGNWRITING ROTATION MODIFI" +
"ER-6SIGNWRITING ROTATION MODIFIER-7SIGNWRITING ROTATION MODIFIER-8SIGNWR" +
"ITING ROTATION MODIFIER-9SIGNWRITING ROTATION MODIFIER-10SIGNWRITING ROT" +
"ATION MODIFIER-11SIGNWRITING ROTATION MODIFIER-12SIGNWRITING ROTATION MO" +
"DIFIER-13SIGNWRITING ROTATION MODIFIER-14SIGNWRITING ROTATION MODIFIER-1" +
"5SIGNWRITING ROTATION MODIFIER-16LATIN SMALL LETTER FENG DIGRAPH WITH TR" +
"ILLLATIN SMALL LETTER REVERSED SCRIPT GLATIN LETTER SMALL CAPITAL TURNED" +
" GLATIN SMALL LETTER REVERSED KLATIN LETTER SMALL CAPITAL L WITH BELTLAT" +
"IN SMALL LETTER LEZH WITH RETROFLEX HOOKLATIN SMALL LETTER TURNED Y WITH" +
" BELTLATIN SMALL LETTER REVERSED ENGLATIN SMALL LETTER TURNED R WITH LON" +
"G LEG AND RETROFLEX HOOKLATIN SMALL LETTER T WITH HOOK AND RETROFLEX HOO") + ("" +
"KLATIN LETTER RETROFLEX CLICK WITH RETROFLEX HOOKLATIN SMALL LETTER ESH " +
"WITH DOUBLE BARLATIN SMALL LETTER ESH WITH DOUBLE BAR AND CURLLATIN SMAL" +
"L LETTER TURNED T WITH CURLLATIN LETTER INVERTED GLOTTAL STOP WITH CURLL" +
"ATIN LETTER STRETCHED C WITH CURLLATIN LETTER SMALL CAPITAL TURNED KLATI" +
"N SMALL LETTER L WITH FISHHOOKLATIN SMALL LETTER DEZH DIGRAPH WITH PALAT" +
"AL HOOKLATIN SMALL LETTER L WITH BELT AND PALATAL HOOKLATIN SMALL LETTER" +
" ENG WITH PALATAL HOOKLATIN SMALL LETTER TURNED R WITH PALATAL HOOKLATIN" +
" SMALL LETTER R WITH FISHHOOK AND PALATAL HOOKLATIN SMALL LETTER TESH DI" +
"GRAPH WITH PALATAL HOOKLATIN SMALL LETTER EZH WITH PALATAL HOOKLATIN SMA" +
"LL LETTER DEZH DIGRAPH WITH RETROFLEX HOOKLATIN SMALL LETTER I WITH STRO" +
"KE AND RETROFLEX HOOKLATIN SMALL LETTER O WITH RETROFLEX HOOKLATIN SMALL" +
" LETTER TESH DIGRAPH WITH RETROFLEX HOOKLATIN SMALL LETTER C WITH RETROF" +
"LEX HOOKLATIN SMALL LETTER S WITH CURLLATIN SMALL LETTER D WITH MID-HEIG" +
"HT LEFT HOOKLATIN SMALL LETTER L WITH MID-HEIGHT LEFT HOOKLATIN SMALL LE" +
"TTER N WITH MID-HEIGHT LEFT HOOKLATIN SMALL LETTER R WITH MID-HEIGHT LEF" +
"T HOOKLATIN SMALL LETTER S WITH MID-HEIGHT LEFT HOOKLATIN SMALL LETTER T" +
" WITH MID-HEIGHT LEFT HOOKCOMBINING GLAGOLITIC LETTER AZUCOMBINING GLAGO" +
"LITIC LETTER BUKYCOMBINING GLAGOLITIC LETTER VEDECOMBINING GLAGOLITIC LE" +
"TTER GLAGOLICOMBINING GLAGOLITIC LETTER DOBROCOMBINING GLAGOLITIC LETTER" +
" YESTUCOMBINING GLAGOLITIC LETTER ZHIVETECOMBINING GLAGOLITIC LETTER ZEM" +
"LJACOMBINING GLAGOLITIC LETTER IZHECOMBINING GLAGOLITIC LETTER INITIAL I" +
"ZHECOMBINING GLAGOLITIC LETTER ICOMBINING GLAGOLITIC LETTER DJERVICOMBIN" +
"ING GLAGOLITIC LETTER KAKOCOMBINING GLAGOLITIC LETTER LJUDIJECOMBINING G" +
"LAGOLITIC LETTER MYSLITECOMBINING GLAGOLITIC LETTER NASHICOMBINING GLAGO" +
"LITIC LETTER ONUCOMBINING GLAGOLITIC LETTER POKOJICOMBINING GLAGOLITIC L" +
"ETTER RITSICOMBINING GLAGOLITIC LETTER SLOVOCOMBINING GLAGOLITIC LETTER " +
"TVRIDOCOMBINING GLAGOLITIC LETTER UKUCOMBINING GLAGOLITIC LETTER FRITUCO" +
"MBINING GLAGOLITIC LETTER HERUCOMBINING GLAGOLITIC LETTER SHTACOMBINING " +
"GLAGOLITIC LETTER TSICOMBINING GLAGOLITIC LETTER CHRIVICOMBINING GLAGOLI" +
"TIC LETTER SHACOMBINING GLAGOLITIC LETTER YERUCOMBINING GLAGOLITIC LETTE" +
"R YERICOMBINING GLAGOLITIC LETTER YATICOMBINING GLAGOLITIC LETTER YUCOMB" +
"INING GLAGOLITIC LETTER SMALL YUSCOMBINING GLAGOLITIC LETTER YOCOMBINING" +
" GLAGOLITIC LETTER IOTATED SMALL YUSCOMBINING GLAGOLITIC LETTER BIG YUSC" +
"OMBINING GLAGOLITIC LETTER IOTATED BIG YUSCOMBINING GLAGOLITIC LETTER FI" +
"TAMODIFIER LETTER CYRILLIC SMALL AMODIFIER LETTER CYRILLIC SMALL BEMODIF" +
"IER LETTER CYRILLIC SMALL VEMODIFIER LETTER CYRILLIC SMALL GHEMODIFIER L" +
"ETTER CYRILLIC SMALL DEMODIFIER LETTER CYRILLIC SMALL IEMODIFIER LETTER " +
"CYRILLIC SMALL ZHEMODIFIER LETTER CYRILLIC SMALL ZEMODIFIER LETTER CYRIL" +
"LIC SMALL IMODIFIER LETTER CYRILLIC SMALL KAMODIFIER LETTER CYRILLIC SMA" +
"LL ELMODIFIER LETTER CYRILLIC SMALL EMMODIFIER LETTER CYRILLIC SMALL OMO" +
"DIFIER LETTER CYRILLIC SMALL PEMODIFIER LETTER CYRILLIC SMALL ERMODIFIER" +
" LETTER CYRILLIC SMALL ESMODIFIER LETTER CYRILLIC SMALL TEMODIFIER LETTE" +
"R CYRILLIC SMALL UMODIFIER LETTER CYRILLIC SMALL EFMODIFIER LETTER CYRIL" +
"LIC SMALL HAMODIFIER LETTER CYRILLIC SMALL TSEMODIFIER LETTER CYRILLIC S" +
"MALL CHEMODIFIER LETTER CYRILLIC SMALL SHAMODIFIER LETTER CYRILLIC SMALL" +
" YERUMODIFIER LETTER CYRILLIC SMALL EMODIFIER LETTER CYRILLIC SMALL YUMO" +
"DIFIER LETTER CYRILLIC SMALL DZZEMODIFIER LETTER CYRILLIC SMALL SCHWAMOD" +
"IFIER LETTER CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN IMODIFIER LETTER CYRI" +
"LLIC SMALL JEMODIFIER LETTER CYRILLIC SMALL BARRED OMODIFIER LETTER CYRI" +
"LLIC SMALL STRAIGHT UMODIFIER LETTER CYRILLIC SMALL PALOCHKACYRILLIC SUB" +
"SCRIPT SMALL LETTER ACYRILLIC SUBSCRIPT SMALL LETTER BECYRILLIC SUBSCRIP" +
"T SMALL LETTER VECYRILLIC SUBSCRIPT SMALL LETTER GHECYRILLIC SUBSCRIPT S" +
"MALL LETTER DECYRILLIC SUBSCRIPT SMALL LETTER IECYRILLIC SUBSCRIPT SMALL" +
" LETTER ZHECYRILLIC SUBSCRIPT SMALL LETTER ZECYRILLIC SUBSCRIPT SMALL LE" +
"TTER ICYRILLIC SUBSCRIPT SMALL LETTER KACYRILLIC SUBSCRIPT SMALL LETTER " +
"ELCYRILLIC SUBSCRIPT SMALL LETTER OCYRILLIC SUBSCRIPT SMALL LETTER PECYR" +
"ILLIC SUBSCRIPT SMALL LETTER ESCYRILLIC SUBSCRIPT SMALL LETTER UCYRILLIC" +
" SUBSCRIPT SMALL LETTER EFCYRILLIC SUBSCRIPT SMALL LETTER HACYRILLIC SUB" +
"SCRIPT SMALL LETTER TSECYRILLIC SUBSCRIPT SMALL LETTER CHECYRILLIC SUBSC" +
"RIPT SMALL LETTER SHACYRILLIC SUBSCRIPT SMALL LETTER HARD SIGNCYRILLIC S" +
"UBSCRIPT SMALL LETTER YERUCYRILLIC SUBSCRIPT SMALL LETTER GHE WITH UPTUR" +
"NCYRILLIC SUBSCRIPT SMALL LETTER BYELORUSSIAN-UKRAINIAN ICYRILLIC SUBSCR" +
"IPT SMALL LETTER DZECYRILLIC SUBSCRIPT SMALL LETTER DZHEMODIFIER LETTER " +
"CYRILLIC SMALL ES WITH DESCENDERMODIFIER LETTER CYRILLIC SMALL YERU WITH") + ("" +
" BACK YERMODIFIER LETTER CYRILLIC SMALL STRAIGHT U WITH STROKECOMBINING " +
"CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN INYIAKENG PUACHUE HMONG LET" +
"TER MANYIAKENG PUACHUE HMONG LETTER TSANYIAKENG PUACHUE HMONG LETTER NTA" +
"NYIAKENG PUACHUE HMONG LETTER TANYIAKENG PUACHUE HMONG LETTER HANYIAKENG" +
" PUACHUE HMONG LETTER NANYIAKENG PUACHUE HMONG LETTER XANYIAKENG PUACHUE" +
" HMONG LETTER NKANYIAKENG PUACHUE HMONG LETTER CANYIAKENG PUACHUE HMONG " +
"LETTER LANYIAKENG PUACHUE HMONG LETTER SANYIAKENG PUACHUE HMONG LETTER Z" +
"ANYIAKENG PUACHUE HMONG LETTER NCANYIAKENG PUACHUE HMONG LETTER NTSANYIA" +
"KENG PUACHUE HMONG LETTER KANYIAKENG PUACHUE HMONG LETTER DANYIAKENG PUA" +
"CHUE HMONG LETTER NYANYIAKENG PUACHUE HMONG LETTER NRANYIAKENG PUACHUE H" +
"MONG LETTER VANYIAKENG PUACHUE HMONG LETTER NTXANYIAKENG PUACHUE HMONG L" +
"ETTER TXANYIAKENG PUACHUE HMONG LETTER FANYIAKENG PUACHUE HMONG LETTER R" +
"ANYIAKENG PUACHUE HMONG LETTER QANYIAKENG PUACHUE HMONG LETTER YANYIAKEN" +
"G PUACHUE HMONG LETTER NQANYIAKENG PUACHUE HMONG LETTER PANYIAKENG PUACH" +
"UE HMONG LETTER XYANYIAKENG PUACHUE HMONG LETTER NPANYIAKENG PUACHUE HMO" +
"NG LETTER DLANYIAKENG PUACHUE HMONG LETTER NPLANYIAKENG PUACHUE HMONG LE" +
"TTER HAHNYIAKENG PUACHUE HMONG LETTER MLANYIAKENG PUACHUE HMONG LETTER P" +
"LANYIAKENG PUACHUE HMONG LETTER GANYIAKENG PUACHUE HMONG LETTER RRANYIAK" +
"ENG PUACHUE HMONG LETTER ANYIAKENG PUACHUE HMONG LETTER AANYIAKENG PUACH" +
"UE HMONG LETTER INYIAKENG PUACHUE HMONG LETTER UNYIAKENG PUACHUE HMONG L" +
"ETTER ONYIAKENG PUACHUE HMONG LETTER OONYIAKENG PUACHUE HMONG LETTER ENY" +
"IAKENG PUACHUE HMONG LETTER EENYIAKENG PUACHUE HMONG LETTER WNYIAKENG PU" +
"ACHUE HMONG TONE-BNYIAKENG PUACHUE HMONG TONE-MNYIAKENG PUACHUE HMONG TO" +
"NE-JNYIAKENG PUACHUE HMONG TONE-VNYIAKENG PUACHUE HMONG TONE-SNYIAKENG P" +
"UACHUE HMONG TONE-GNYIAKENG PUACHUE HMONG TONE-DNYIAKENG PUACHUE HMONG S" +
"IGN FOR PERSONNYIAKENG PUACHUE HMONG SIGN FOR THINGNYIAKENG PUACHUE HMON" +
"G SIGN FOR LOCATIONNYIAKENG PUACHUE HMONG SIGN FOR ANIMALNYIAKENG PUACHU" +
"E HMONG SIGN FOR INVERTEBRATENYIAKENG PUACHUE HMONG SIGN XW XWNYIAKENG P" +
"UACHUE HMONG SYLLABLE LENGTHENERNYIAKENG PUACHUE HMONG DIGIT ZERONYIAKEN" +
"G PUACHUE HMONG DIGIT ONENYIAKENG PUACHUE HMONG DIGIT TWONYIAKENG PUACHU" +
"E HMONG DIGIT THREENYIAKENG PUACHUE HMONG DIGIT FOURNYIAKENG PUACHUE HMO" +
"NG DIGIT FIVENYIAKENG PUACHUE HMONG DIGIT SIXNYIAKENG PUACHUE HMONG DIGI" +
"T SEVENNYIAKENG PUACHUE HMONG DIGIT EIGHTNYIAKENG PUACHUE HMONG DIGIT NI" +
"NENYIAKENG PUACHUE HMONG LOGOGRAM NYAJNYIAKENG PUACHUE HMONG CIRCLED CAT" +
"OTO LETTER PATOTO LETTER BATOTO LETTER TATOTO LETTER DATOTO LETTER KATOT" +
"O LETTER GATOTO LETTER MATOTO LETTER NATOTO LETTER NGATOTO LETTER SATOTO" +
" LETTER CHATOTO LETTER YATOTO LETTER WATOTO LETTER JATOTO LETTER HATOTO " +
"LETTER RATOTO LETTER LATOTO LETTER ITOTO LETTER BREATHY ITOTO LETTER IUT" +
"OTO LETTER BREATHY IUTOTO LETTER UTOTO LETTER ETOTO LETTER BREATHY ETOTO" +
" LETTER EOTOTO LETTER BREATHY EOTOTO LETTER OTOTO LETTER AETOTO LETTER B" +
"REATHY AETOTO LETTER ATOTO SIGN RISING TONEWANCHO LETTER AAWANCHO LETTER" +
" AWANCHO LETTER BAWANCHO LETTER CAWANCHO LETTER DAWANCHO LETTER GAWANCHO" +
" LETTER YAWANCHO LETTER PHAWANCHO LETTER LAWANCHO LETTER NAWANCHO LETTER" +
" PAWANCHO LETTER TAWANCHO LETTER THAWANCHO LETTER FAWANCHO LETTER SAWANC" +
"HO LETTER SHAWANCHO LETTER JAWANCHO LETTER ZAWANCHO LETTER WAWANCHO LETT" +
"ER VAWANCHO LETTER KAWANCHO LETTER OWANCHO LETTER AUWANCHO LETTER RAWANC" +
"HO LETTER MAWANCHO LETTER KHAWANCHO LETTER HAWANCHO LETTER EWANCHO LETTE" +
"R IWANCHO LETTER NGAWANCHO LETTER UWANCHO LETTER LLHAWANCHO LETTER TSAWA" +
"NCHO LETTER TRAWANCHO LETTER ONGWANCHO LETTER AANGWANCHO LETTER ANGWANCH" +
"O LETTER INGWANCHO LETTER ONWANCHO LETTER ENWANCHO LETTER AANWANCHO LETT" +
"ER NYAWANCHO LETTER UENWANCHO LETTER YIHWANCHO TONE TUPWANCHO TONE TUPNI" +
"WANCHO TONE KOIWANCHO TONE KOINIWANCHO DIGIT ZEROWANCHO DIGIT ONEWANCHO " +
"DIGIT TWOWANCHO DIGIT THREEWANCHO DIGIT FOURWANCHO DIGIT FIVEWANCHO DIGI" +
"T SIXWANCHO DIGIT SEVENWANCHO DIGIT EIGHTWANCHO DIGIT NINEWANCHO NGUN SI" +
"GNNAG MUNDARI LETTER ONAG MUNDARI LETTER OPNAG MUNDARI LETTER OLNAG MUND" +
"ARI LETTER OYNAG MUNDARI LETTER ONGNAG MUNDARI LETTER ANAG MUNDARI LETTE" +
"R AJNAG MUNDARI LETTER ABNAG MUNDARI LETTER ANYNAG MUNDARI LETTER AHNAG " +
"MUNDARI LETTER INAG MUNDARI LETTER ISNAG MUNDARI LETTER IDDNAG MUNDARI L" +
"ETTER ITNAG MUNDARI LETTER IHNAG MUNDARI LETTER UNAG MUNDARI LETTER UCNA" +
"G MUNDARI LETTER UDNAG MUNDARI LETTER UKNAG MUNDARI LETTER URNAG MUNDARI" +
" LETTER ENAG MUNDARI LETTER ENNNAG MUNDARI LETTER EGNAG MUNDARI LETTER E" +
"MNAG MUNDARI LETTER ENNAG MUNDARI LETTER ETTNAG MUNDARI LETTER ELLNAG MU" +
"NDARI SIGN OJODNAG MUNDARI SIGN MUHORNAG MUNDARI SIGN TOYORNAG MUNDARI S" +
"IGN IKIRNAG MUNDARI SIGN SUTUHNAG MUNDARI DIGIT ZERONAG MUNDARI DIGIT ON") + ("" +
"ENAG MUNDARI DIGIT TWONAG MUNDARI DIGIT THREENAG MUNDARI DIGIT FOURNAG M" +
"UNDARI DIGIT FIVENAG MUNDARI DIGIT SIXNAG MUNDARI DIGIT SEVENNAG MUNDARI" +
" DIGIT EIGHTNAG MUNDARI DIGIT NINEOL ONAL LETTER OOL ONAL LETTER OMOL ON" +
"AL LETTER ONGOL ONAL LETTER ORROL ONAL LETTER OOOL ONAL LETTER OYOL ONAL" +
" LETTER AOL ONAL LETTER ADOL ONAL LETTER ABOL ONAL LETTER AHOL ONAL LETT" +
"ER ALOL ONAL LETTER AWOL ONAL LETTER IOL ONAL LETTER ITOL ONAL LETTER IP" +
"OL ONAL LETTER ITTOL ONAL LETTER IDOL ONAL LETTER INOL ONAL LETTER UOL O" +
"NAL LETTER UKOL ONAL LETTER UDDOL ONAL LETTER UJOL ONAL LETTER UNYOL ONA" +
"L LETTER UROL ONAL LETTER EOL ONAL LETTER ESOL ONAL LETTER EHOL ONAL LET" +
"TER ECOL ONAL LETTER ENNOL ONAL LETTER EGOL ONAL SIGN MUOL ONAL SIGN IKI" +
"ROL ONAL SIGN HODDONDOL ONAL DIGIT ZEROOL ONAL DIGIT ONEOL ONAL DIGIT TW" +
"OOL ONAL DIGIT THREEOL ONAL DIGIT FOUROL ONAL DIGIT FIVEOL ONAL DIGIT SI" +
"XOL ONAL DIGIT SEVENOL ONAL DIGIT EIGHTOL ONAL DIGIT NINEOL ONAL ABBREVI" +
"ATION SIGNTAI YO LETTER LOW KOTAI YO LETTER HIGH KOTAI YO LETTER LOW KHO" +
"TAI YO LETTER HIGH KHOTAI YO LETTER GOTAI YO LETTER NGOTAI YO LETTER COT" +
"AI YO LETTER LOW XOTAI YO LETTER HIGH XOTAI YO LETTER LOW NYOTAI YO LETT" +
"ER HIGH NYOTAI YO LETTER DOTAI YO LETTER LOW TOTAI YO LETTER HIGH TOTAI " +
"YO LETTER THOTAI YO LETTER NOTAI YO LETTER BOTAI YO LETTER LOW POTAI YO " +
"LETTER HIGH POTAI YO LETTER PHOTAI YO LETTER LOW FOTAI YO LETTER HIGH FO" +
"TAI YO LETTER MOTAI YO LETTER YOTAI YO LETTER LOTAI YO LETTER VOTAI YO L" +
"ETTER LOW HOTAI YO LETTER HIGH HOTAI YO LETTER QOTAI YO LETTER LOW KVOTA" +
"I YO LETTER HIGH KVOTAI YO LETTER AATAI YO LETTER ITAI YO LETTER UETAI Y" +
"O SIGN UETAI YO LETTER UTAI YO LETTER AETAI YO SIGN AUTAI YO LETTER OTAI" +
" YO LETTER ETAI YO LETTER IATAI YO LETTER UEATAI YO LETTER UATAI YO LETT" +
"ER OOTAI YO LETTER AUETAI YO SIGN AYTAI YO SIGN ANGTAI YO LETTER ANTAI Y" +
"O LETTER AMTAI YO LETTER AKTAI YO LETTER ATTAI YO LETTER APTAI YO SIGN O" +
"MTAI YO SYMBOL MUEANGTAI YO XAM LAIETHIOPIC SYLLABLE HHYAETHIOPIC SYLLAB" +
"LE HHYUETHIOPIC SYLLABLE HHYIETHIOPIC SYLLABLE HHYAAETHIOPIC SYLLABLE HH" +
"YEEETHIOPIC SYLLABLE HHYEETHIOPIC SYLLABLE HHYOETHIOPIC SYLLABLE GURAGE " +
"HHWAETHIOPIC SYLLABLE HHWIETHIOPIC SYLLABLE HHWEEETHIOPIC SYLLABLE HHWEE" +
"THIOPIC SYLLABLE GURAGE MWIETHIOPIC SYLLABLE GURAGE MWEEETHIOPIC SYLLABL" +
"E GURAGE QWIETHIOPIC SYLLABLE GURAGE QWEEETHIOPIC SYLLABLE GURAGE QWEETH" +
"IOPIC SYLLABLE GURAGE BWIETHIOPIC SYLLABLE GURAGE BWEEETHIOPIC SYLLABLE " +
"GURAGE KWIETHIOPIC SYLLABLE GURAGE KWEEETHIOPIC SYLLABLE GURAGE KWEETHIO" +
"PIC SYLLABLE GURAGE GWIETHIOPIC SYLLABLE GURAGE GWEEETHIOPIC SYLLABLE GU" +
"RAGE GWEETHIOPIC SYLLABLE GURAGE FWIETHIOPIC SYLLABLE GURAGE FWEEETHIOPI" +
"C SYLLABLE GURAGE PWIETHIOPIC SYLLABLE GURAGE PWEEMENDE KIKAKUI SYLLABLE" +
" M001 KIMENDE KIKAKUI SYLLABLE M002 KAMENDE KIKAKUI SYLLABLE M003 KUMEND" +
"E KIKAKUI SYLLABLE M065 KEEMENDE KIKAKUI SYLLABLE M095 KEMENDE KIKAKUI S" +
"YLLABLE M076 KOOMENDE KIKAKUI SYLLABLE M048 KOMENDE KIKAKUI SYLLABLE M17" +
"9 KUAMENDE KIKAKUI SYLLABLE M004 WIMENDE KIKAKUI SYLLABLE M005 WAMENDE K" +
"IKAKUI SYLLABLE M006 WUMENDE KIKAKUI SYLLABLE M126 WEEMENDE KIKAKUI SYLL" +
"ABLE M118 WEMENDE KIKAKUI SYLLABLE M114 WOOMENDE KIKAKUI SYLLABLE M045 W" +
"OMENDE KIKAKUI SYLLABLE M194 WUIMENDE KIKAKUI SYLLABLE M143 WEIMENDE KIK" +
"AKUI SYLLABLE M061 WVIMENDE KIKAKUI SYLLABLE M049 WVAMENDE KIKAKUI SYLLA" +
"BLE M139 WVEMENDE KIKAKUI SYLLABLE M007 MINMENDE KIKAKUI SYLLABLE M008 M" +
"ANMENDE KIKAKUI SYLLABLE M009 MUNMENDE KIKAKUI SYLLABLE M059 MENMENDE KI" +
"KAKUI SYLLABLE M094 MONMENDE KIKAKUI SYLLABLE M154 MUANMENDE KIKAKUI SYL" +
"LABLE M189 MUENMENDE KIKAKUI SYLLABLE M010 BIMENDE KIKAKUI SYLLABLE M011" +
" BAMENDE KIKAKUI SYLLABLE M012 BUMENDE KIKAKUI SYLLABLE M150 BEEMENDE KI" +
"KAKUI SYLLABLE M097 BEMENDE KIKAKUI SYLLABLE M103 BOOMENDE KIKAKUI SYLLA" +
"BLE M138 BOMENDE KIKAKUI SYLLABLE M013 IMENDE KIKAKUI SYLLABLE M014 AMEN" +
"DE KIKAKUI SYLLABLE M015 UMENDE KIKAKUI SYLLABLE M163 EEMENDE KIKAKUI SY" +
"LLABLE M100 EMENDE KIKAKUI SYLLABLE M165 OOMENDE KIKAKUI SYLLABLE M147 O" +
"MENDE KIKAKUI SYLLABLE M137 EIMENDE KIKAKUI SYLLABLE M131 INMENDE KIKAKU" +
"I SYLLABLE M135 INMENDE KIKAKUI SYLLABLE M195 ANMENDE KIKAKUI SYLLABLE M" +
"178 ENMENDE KIKAKUI SYLLABLE M019 SIMENDE KIKAKUI SYLLABLE M020 SAMENDE " +
"KIKAKUI SYLLABLE M021 SUMENDE KIKAKUI SYLLABLE M162 SEEMENDE KIKAKUI SYL" +
"LABLE M116 SEMENDE KIKAKUI SYLLABLE M136 SOOMENDE KIKAKUI SYLLABLE M079 " +
"SOMENDE KIKAKUI SYLLABLE M196 SIAMENDE KIKAKUI SYLLABLE M025 LIMENDE KIK" +
"AKUI SYLLABLE M026 LAMENDE KIKAKUI SYLLABLE M027 LUMENDE KIKAKUI SYLLABL" +
"E M084 LEEMENDE KIKAKUI SYLLABLE M073 LEMENDE KIKAKUI SYLLABLE M054 LOOM" +
"ENDE KIKAKUI SYLLABLE M153 LOMENDE KIKAKUI SYLLABLE M110 LONG LEMENDE KI" +
"KAKUI SYLLABLE M016 DIMENDE KIKAKUI SYLLABLE M017 DAMENDE KIKAKUI SYLLAB") + ("" +
"LE M018 DUMENDE KIKAKUI SYLLABLE M089 DEEMENDE KIKAKUI SYLLABLE M180 DOO" +
"MENDE KIKAKUI SYLLABLE M181 DOMENDE KIKAKUI SYLLABLE M022 TIMENDE KIKAKU" +
"I SYLLABLE M023 TAMENDE KIKAKUI SYLLABLE M024 TUMENDE KIKAKUI SYLLABLE M" +
"091 TEEMENDE KIKAKUI SYLLABLE M055 TEMENDE KIKAKUI SYLLABLE M104 TOOMEND" +
"E KIKAKUI SYLLABLE M069 TOMENDE KIKAKUI SYLLABLE M028 JIMENDE KIKAKUI SY" +
"LLABLE M029 JAMENDE KIKAKUI SYLLABLE M030 JUMENDE KIKAKUI SYLLABLE M157 " +
"JEEMENDE KIKAKUI SYLLABLE M113 JEMENDE KIKAKUI SYLLABLE M160 JOOMENDE KI" +
"KAKUI SYLLABLE M063 JOMENDE KIKAKUI SYLLABLE M175 LONG JOMENDE KIKAKUI S" +
"YLLABLE M031 YIMENDE KIKAKUI SYLLABLE M032 YAMENDE KIKAKUI SYLLABLE M033" +
" YUMENDE KIKAKUI SYLLABLE M109 YEEMENDE KIKAKUI SYLLABLE M080 YEMENDE KI" +
"KAKUI SYLLABLE M141 YOOMENDE KIKAKUI SYLLABLE M121 YOMENDE KIKAKUI SYLLA" +
"BLE M034 FIMENDE KIKAKUI SYLLABLE M035 FAMENDE KIKAKUI SYLLABLE M036 FUM" +
"ENDE KIKAKUI SYLLABLE M078 FEEMENDE KIKAKUI SYLLABLE M075 FEMENDE KIKAKU" +
"I SYLLABLE M133 FOOMENDE KIKAKUI SYLLABLE M088 FOMENDE KIKAKUI SYLLABLE " +
"M197 FUAMENDE KIKAKUI SYLLABLE M101 FANMENDE KIKAKUI SYLLABLE M037 NINME" +
"NDE KIKAKUI SYLLABLE M038 NANMENDE KIKAKUI SYLLABLE M039 NUNMENDE KIKAKU" +
"I SYLLABLE M117 NENMENDE KIKAKUI SYLLABLE M169 NONMENDE KIKAKUI SYLLABLE" +
" M176 HIMENDE KIKAKUI SYLLABLE M041 HAMENDE KIKAKUI SYLLABLE M186 HUMEND" +
"E KIKAKUI SYLLABLE M040 HEEMENDE KIKAKUI SYLLABLE M096 HEMENDE KIKAKUI S" +
"YLLABLE M042 HOOMENDE KIKAKUI SYLLABLE M140 HOMENDE KIKAKUI SYLLABLE M08" +
"3 HEEIMENDE KIKAKUI SYLLABLE M128 HOOUMENDE KIKAKUI SYLLABLE M053 HINMEN" +
"DE KIKAKUI SYLLABLE M130 HANMENDE KIKAKUI SYLLABLE M087 HUNMENDE KIKAKUI" +
" SYLLABLE M052 HENMENDE KIKAKUI SYLLABLE M193 HONMENDE KIKAKUI SYLLABLE " +
"M046 HUANMENDE KIKAKUI SYLLABLE M090 NGGIMENDE KIKAKUI SYLLABLE M043 NGG" +
"AMENDE KIKAKUI SYLLABLE M082 NGGUMENDE KIKAKUI SYLLABLE M115 NGGEEMENDE " +
"KIKAKUI SYLLABLE M146 NGGEMENDE KIKAKUI SYLLABLE M156 NGGOOMENDE KIKAKUI" +
" SYLLABLE M120 NGGOMENDE KIKAKUI SYLLABLE M159 NGGAAMENDE KIKAKUI SYLLAB" +
"LE M127 NGGUAMENDE KIKAKUI SYLLABLE M086 LONG NGGEMENDE KIKAKUI SYLLABLE" +
" M106 LONG NGGOOMENDE KIKAKUI SYLLABLE M183 LONG NGGOMENDE KIKAKUI SYLLA" +
"BLE M155 GIMENDE KIKAKUI SYLLABLE M111 GAMENDE KIKAKUI SYLLABLE M168 GUM" +
"ENDE KIKAKUI SYLLABLE M190 GEEMENDE KIKAKUI SYLLABLE M166 GUEIMENDE KIKA" +
"KUI SYLLABLE M167 GUANMENDE KIKAKUI SYLLABLE M184 NGENMENDE KIKAKUI SYLL" +
"ABLE M057 NGONMENDE KIKAKUI SYLLABLE M177 NGUANMENDE KIKAKUI SYLLABLE M0" +
"68 PIMENDE KIKAKUI SYLLABLE M099 PAMENDE KIKAKUI SYLLABLE M050 PUMENDE K" +
"IKAKUI SYLLABLE M081 PEEMENDE KIKAKUI SYLLABLE M051 PEMENDE KIKAKUI SYLL" +
"ABLE M102 POOMENDE KIKAKUI SYLLABLE M066 POMENDE KIKAKUI SYLLABLE M145 M" +
"BIMENDE KIKAKUI SYLLABLE M062 MBAMENDE KIKAKUI SYLLABLE M122 MBUMENDE KI" +
"KAKUI SYLLABLE M047 MBEEMENDE KIKAKUI SYLLABLE M188 MBEEMENDE KIKAKUI SY" +
"LLABLE M072 MBEMENDE KIKAKUI SYLLABLE M172 MBOOMENDE KIKAKUI SYLLABLE M1" +
"74 MBOMENDE KIKAKUI SYLLABLE M187 MBUUMENDE KIKAKUI SYLLABLE M161 LONG M" +
"BEMENDE KIKAKUI SYLLABLE M105 LONG MBOOMENDE KIKAKUI SYLLABLE M142 LONG " +
"MBOMENDE KIKAKUI SYLLABLE M132 KPIMENDE KIKAKUI SYLLABLE M092 KPAMENDE K" +
"IKAKUI SYLLABLE M074 KPUMENDE KIKAKUI SYLLABLE M044 KPEEMENDE KIKAKUI SY" +
"LLABLE M108 KPEMENDE KIKAKUI SYLLABLE M112 KPOOMENDE KIKAKUI SYLLABLE M1" +
"58 KPOMENDE KIKAKUI SYLLABLE M124 GBIMENDE KIKAKUI SYLLABLE M056 GBAMEND" +
"E KIKAKUI SYLLABLE M148 GBUMENDE KIKAKUI SYLLABLE M093 GBEEMENDE KIKAKUI" +
" SYLLABLE M107 GBEMENDE KIKAKUI SYLLABLE M071 GBOOMENDE KIKAKUI SYLLABLE" +
" M070 GBOMENDE KIKAKUI SYLLABLE M171 RAMENDE KIKAKUI SYLLABLE M123 NDIME" +
"NDE KIKAKUI SYLLABLE M129 NDAMENDE KIKAKUI SYLLABLE M125 NDUMENDE KIKAKU" +
"I SYLLABLE M191 NDEEMENDE KIKAKUI SYLLABLE M119 NDEMENDE KIKAKUI SYLLABL" +
"E M067 NDOOMENDE KIKAKUI SYLLABLE M064 NDOMENDE KIKAKUI SYLLABLE M152 NJ" +
"AMENDE KIKAKUI SYLLABLE M192 NJUMENDE KIKAKUI SYLLABLE M149 NJEEMENDE KI" +
"KAKUI SYLLABLE M134 NJOOMENDE KIKAKUI SYLLABLE M182 VIMENDE KIKAKUI SYLL" +
"ABLE M185 VAMENDE KIKAKUI SYLLABLE M151 VUMENDE KIKAKUI SYLLABLE M173 VE" +
"EMENDE KIKAKUI SYLLABLE M085 VEMENDE KIKAKUI SYLLABLE M144 VOOMENDE KIKA" +
"KUI SYLLABLE M077 VOMENDE KIKAKUI SYLLABLE M164 NYINMENDE KIKAKUI SYLLAB" +
"LE M058 NYANMENDE KIKAKUI SYLLABLE M170 NYUNMENDE KIKAKUI SYLLABLE M098 " +
"NYENMENDE KIKAKUI SYLLABLE M060 NYONMENDE KIKAKUI DIGIT ONEMENDE KIKAKUI" +
" DIGIT TWOMENDE KIKAKUI DIGIT THREEMENDE KIKAKUI DIGIT FOURMENDE KIKAKUI" +
" DIGIT FIVEMENDE KIKAKUI DIGIT SIXMENDE KIKAKUI DIGIT SEVENMENDE KIKAKUI" +
" DIGIT EIGHTMENDE KIKAKUI DIGIT NINEMENDE KIKAKUI COMBINING NUMBER TEENS" +
"MENDE KIKAKUI COMBINING NUMBER TENSMENDE KIKAKUI COMBINING NUMBER HUNDRE" +
"DSMENDE KIKAKUI COMBINING NUMBER THOUSANDSMENDE KIKAKUI COMBINING NUMBER" +
" TEN THOUSANDSMENDE KIKAKUI COMBINING NUMBER HUNDRED THOUSANDSMENDE KIKA") + ("" +
"KUI COMBINING NUMBER MILLIONSADLAM CAPITAL LETTER ALIFADLAM CAPITAL LETT" +
"ER DAALIADLAM CAPITAL LETTER LAAMADLAM CAPITAL LETTER MIIMADLAM CAPITAL " +
"LETTER BAADLAM CAPITAL LETTER SINNYIIYHEADLAM CAPITAL LETTER PEADLAM CAP" +
"ITAL LETTER BHEADLAM CAPITAL LETTER RAADLAM CAPITAL LETTER EADLAM CAPITA" +
"L LETTER FAADLAM CAPITAL LETTER IADLAM CAPITAL LETTER OADLAM CAPITAL LET" +
"TER DHAADLAM CAPITAL LETTER YHEADLAM CAPITAL LETTER WAWADLAM CAPITAL LET" +
"TER NUNADLAM CAPITAL LETTER KAFADLAM CAPITAL LETTER YAADLAM CAPITAL LETT" +
"ER UADLAM CAPITAL LETTER JIIMADLAM CAPITAL LETTER CHIADLAM CAPITAL LETTE" +
"R HAADLAM CAPITAL LETTER QAAFADLAM CAPITAL LETTER GAADLAM CAPITAL LETTER" +
" NYAADLAM CAPITAL LETTER TUADLAM CAPITAL LETTER NHAADLAM CAPITAL LETTER " +
"VAADLAM CAPITAL LETTER KHAADLAM CAPITAL LETTER GBEADLAM CAPITAL LETTER Z" +
"ALADLAM CAPITAL LETTER KPOADLAM CAPITAL LETTER SHAADLAM SMALL LETTER ALI" +
"FADLAM SMALL LETTER DAALIADLAM SMALL LETTER LAAMADLAM SMALL LETTER MIIMA" +
"DLAM SMALL LETTER BAADLAM SMALL LETTER SINNYIIYHEADLAM SMALL LETTER PEAD" +
"LAM SMALL LETTER BHEADLAM SMALL LETTER RAADLAM SMALL LETTER EADLAM SMALL" +
" LETTER FAADLAM SMALL LETTER IADLAM SMALL LETTER OADLAM SMALL LETTER DHA" +
"ADLAM SMALL LETTER YHEADLAM SMALL LETTER WAWADLAM SMALL LETTER NUNADLAM " +
"SMALL LETTER KAFADLAM SMALL LETTER YAADLAM SMALL LETTER UADLAM SMALL LET" +
"TER JIIMADLAM SMALL LETTER CHIADLAM SMALL LETTER HAADLAM SMALL LETTER QA" +
"AFADLAM SMALL LETTER GAADLAM SMALL LETTER NYAADLAM SMALL LETTER TUADLAM " +
"SMALL LETTER NHAADLAM SMALL LETTER VAADLAM SMALL LETTER KHAADLAM SMALL L" +
"ETTER GBEADLAM SMALL LETTER ZALADLAM SMALL LETTER KPOADLAM SMALL LETTER " +
"SHAADLAM ALIF LENGTHENERADLAM VOWEL LENGTHENERADLAM GEMINATION MARKADLAM" +
" HAMZAADLAM CONSONANT MODIFIERADLAM GEMINATE CONSONANT MODIFIERADLAM NUK" +
"TAADLAM NASALIZATION MARKADLAM DIGIT ZEROADLAM DIGIT ONEADLAM DIGIT TWOA" +
"DLAM DIGIT THREEADLAM DIGIT FOURADLAM DIGIT FIVEADLAM DIGIT SIXADLAM DIG" +
"IT SEVENADLAM DIGIT EIGHTADLAM DIGIT NINEADLAM INITIAL EXCLAMATION MARKA" +
"DLAM INITIAL QUESTION MARKINDIC SIYAQ NUMBER ONEINDIC SIYAQ NUMBER TWOIN" +
"DIC SIYAQ NUMBER THREEINDIC SIYAQ NUMBER FOURINDIC SIYAQ NUMBER FIVEINDI" +
"C SIYAQ NUMBER SIXINDIC SIYAQ NUMBER SEVENINDIC SIYAQ NUMBER EIGHTINDIC " +
"SIYAQ NUMBER NINEINDIC SIYAQ NUMBER TENINDIC SIYAQ NUMBER TWENTYINDIC SI" +
"YAQ NUMBER THIRTYINDIC SIYAQ NUMBER FORTYINDIC SIYAQ NUMBER FIFTYINDIC S" +
"IYAQ NUMBER SIXTYINDIC SIYAQ NUMBER SEVENTYINDIC SIYAQ NUMBER EIGHTYINDI" +
"C SIYAQ NUMBER NINETYINDIC SIYAQ NUMBER ONE HUNDREDINDIC SIYAQ NUMBER TW" +
"O HUNDREDINDIC SIYAQ NUMBER THREE HUNDREDINDIC SIYAQ NUMBER FOUR HUNDRED" +
"INDIC SIYAQ NUMBER FIVE HUNDREDINDIC SIYAQ NUMBER SIX HUNDREDINDIC SIYAQ" +
" NUMBER SEVEN HUNDREDINDIC SIYAQ NUMBER EIGHT HUNDREDINDIC SIYAQ NUMBER " +
"NINE HUNDREDINDIC SIYAQ NUMBER ONE THOUSANDINDIC SIYAQ NUMBER TWO THOUSA" +
"NDINDIC SIYAQ NUMBER THREE THOUSANDINDIC SIYAQ NUMBER FOUR THOUSANDINDIC" +
" SIYAQ NUMBER FIVE THOUSANDINDIC SIYAQ NUMBER SIX THOUSANDINDIC SIYAQ NU" +
"MBER SEVEN THOUSANDINDIC SIYAQ NUMBER EIGHT THOUSANDINDIC SIYAQ NUMBER N" +
"INE THOUSANDINDIC SIYAQ NUMBER TEN THOUSANDINDIC SIYAQ NUMBER TWENTY THO" +
"USANDINDIC SIYAQ NUMBER THIRTY THOUSANDINDIC SIYAQ NUMBER FORTY THOUSAND" +
"INDIC SIYAQ NUMBER FIFTY THOUSANDINDIC SIYAQ NUMBER SIXTY THOUSANDINDIC " +
"SIYAQ NUMBER SEVENTY THOUSANDINDIC SIYAQ NUMBER EIGHTY THOUSANDINDIC SIY" +
"AQ NUMBER NINETY THOUSANDINDIC SIYAQ NUMBER LAKHINDIC SIYAQ NUMBER LAKHA" +
"NINDIC SIYAQ LAKH MARKINDIC SIYAQ NUMBER KARORINDIC SIYAQ NUMBER KARORAN" +
"INDIC SIYAQ NUMBER PREFIXED ONEINDIC SIYAQ NUMBER PREFIXED TWOINDIC SIYA" +
"Q NUMBER PREFIXED THREEINDIC SIYAQ NUMBER PREFIXED FOURINDIC SIYAQ NUMBE" +
"R PREFIXED FIVEINDIC SIYAQ NUMBER PREFIXED SIXINDIC SIYAQ NUMBER PREFIXE" +
"D SEVENINDIC SIYAQ NUMBER PREFIXED EIGHTINDIC SIYAQ NUMBER PREFIXED NINE" +
"INDIC SIYAQ PLACEHOLDERINDIC SIYAQ FRACTION ONE QUARTERINDIC SIYAQ FRACT" +
"ION ONE HALFINDIC SIYAQ FRACTION THREE QUARTERSINDIC SIYAQ RUPEE MARKIND" +
"IC SIYAQ NUMBER ALTERNATE ONEINDIC SIYAQ NUMBER ALTERNATE TWOINDIC SIYAQ" +
" NUMBER ALTERNATE TEN THOUSANDINDIC SIYAQ ALTERNATE LAKH MARKOTTOMAN SIY" +
"AQ NUMBER ONEOTTOMAN SIYAQ NUMBER TWOOTTOMAN SIYAQ NUMBER THREEOTTOMAN S" +
"IYAQ NUMBER FOUROTTOMAN SIYAQ NUMBER FIVEOTTOMAN SIYAQ NUMBER SIXOTTOMAN" +
" SIYAQ NUMBER SEVENOTTOMAN SIYAQ NUMBER EIGHTOTTOMAN SIYAQ NUMBER NINEOT" +
"TOMAN SIYAQ NUMBER TENOTTOMAN SIYAQ NUMBER TWENTYOTTOMAN SIYAQ NUMBER TH" +
"IRTYOTTOMAN SIYAQ NUMBER FORTYOTTOMAN SIYAQ NUMBER FIFTYOTTOMAN SIYAQ NU" +
"MBER SIXTYOTTOMAN SIYAQ NUMBER SEVENTYOTTOMAN SIYAQ NUMBER EIGHTYOTTOMAN" +
" SIYAQ NUMBER NINETYOTTOMAN SIYAQ NUMBER ONE HUNDREDOTTOMAN SIYAQ NUMBER" +
" TWO HUNDREDOTTOMAN SIYAQ NUMBER THREE HUNDREDOTTOMAN SIYAQ NUMBER FOUR " +
"HUNDREDOTTOMAN SIYAQ NUMBER FIVE HUNDREDOTTOMAN SIYAQ NUMBER SIX HUNDRED") + ("" +
"OTTOMAN SIYAQ NUMBER SEVEN HUNDREDOTTOMAN SIYAQ NUMBER EIGHT HUNDREDOTTO" +
"MAN SIYAQ NUMBER NINE HUNDREDOTTOMAN SIYAQ NUMBER ONE THOUSANDOTTOMAN SI" +
"YAQ NUMBER TWO THOUSANDOTTOMAN SIYAQ NUMBER THREE THOUSANDOTTOMAN SIYAQ " +
"NUMBER FOUR THOUSANDOTTOMAN SIYAQ NUMBER FIVE THOUSANDOTTOMAN SIYAQ NUMB" +
"ER SIX THOUSANDOTTOMAN SIYAQ NUMBER SEVEN THOUSANDOTTOMAN SIYAQ NUMBER E" +
"IGHT THOUSANDOTTOMAN SIYAQ NUMBER NINE THOUSANDOTTOMAN SIYAQ NUMBER TEN " +
"THOUSANDOTTOMAN SIYAQ NUMBER TWENTY THOUSANDOTTOMAN SIYAQ NUMBER THIRTY " +
"THOUSANDOTTOMAN SIYAQ NUMBER FORTY THOUSANDOTTOMAN SIYAQ NUMBER FIFTY TH" +
"OUSANDOTTOMAN SIYAQ NUMBER SIXTY THOUSANDOTTOMAN SIYAQ NUMBER SEVENTY TH" +
"OUSANDOTTOMAN SIYAQ NUMBER EIGHTY THOUSANDOTTOMAN SIYAQ NUMBER NINETY TH" +
"OUSANDOTTOMAN SIYAQ MARRATANOTTOMAN SIYAQ ALTERNATE NUMBER TWOOTTOMAN SI" +
"YAQ ALTERNATE NUMBER THREEOTTOMAN SIYAQ ALTERNATE NUMBER FOUROTTOMAN SIY" +
"AQ ALTERNATE NUMBER FIVEOTTOMAN SIYAQ ALTERNATE NUMBER SIXOTTOMAN SIYAQ " +
"ALTERNATE NUMBER SEVENOTTOMAN SIYAQ ALTERNATE NUMBER EIGHTOTTOMAN SIYAQ " +
"ALTERNATE NUMBER NINEOTTOMAN SIYAQ ALTERNATE NUMBER TENOTTOMAN SIYAQ ALT" +
"ERNATE NUMBER FOUR HUNDREDOTTOMAN SIYAQ ALTERNATE NUMBER SIX HUNDREDOTTO" +
"MAN SIYAQ ALTERNATE NUMBER TWO THOUSANDOTTOMAN SIYAQ ALTERNATE NUMBER TE" +
"N THOUSANDOTTOMAN SIYAQ FRACTION ONE HALFOTTOMAN SIYAQ FRACTION ONE SIXT" +
"HARABIC MATHEMATICAL ALEFARABIC MATHEMATICAL BEHARABIC MATHEMATICAL JEEM" +
"ARABIC MATHEMATICAL DALARABIC MATHEMATICAL WAWARABIC MATHEMATICAL ZAINAR" +
"ABIC MATHEMATICAL HAHARABIC MATHEMATICAL TAHARABIC MATHEMATICAL YEHARABI" +
"C MATHEMATICAL KAFARABIC MATHEMATICAL LAMARABIC MATHEMATICAL MEEMARABIC " +
"MATHEMATICAL NOONARABIC MATHEMATICAL SEENARABIC MATHEMATICAL AINARABIC M" +
"ATHEMATICAL FEHARABIC MATHEMATICAL SADARABIC MATHEMATICAL QAFARABIC MATH" +
"EMATICAL REHARABIC MATHEMATICAL SHEENARABIC MATHEMATICAL TEHARABIC MATHE" +
"MATICAL THEHARABIC MATHEMATICAL KHAHARABIC MATHEMATICAL THALARABIC MATHE" +
"MATICAL DADARABIC MATHEMATICAL ZAHARABIC MATHEMATICAL GHAINARABIC MATHEM" +
"ATICAL DOTLESS BEHARABIC MATHEMATICAL DOTLESS NOONARABIC MATHEMATICAL DO" +
"TLESS FEHARABIC MATHEMATICAL DOTLESS QAFARABIC MATHEMATICAL INITIAL BEHA" +
"RABIC MATHEMATICAL INITIAL JEEMARABIC MATHEMATICAL INITIAL HEHARABIC MAT" +
"HEMATICAL INITIAL HAHARABIC MATHEMATICAL INITIAL YEHARABIC MATHEMATICAL " +
"INITIAL KAFARABIC MATHEMATICAL INITIAL LAMARABIC MATHEMATICAL INITIAL ME" +
"EMARABIC MATHEMATICAL INITIAL NOONARABIC MATHEMATICAL INITIAL SEENARABIC" +
" MATHEMATICAL INITIAL AINARABIC MATHEMATICAL INITIAL FEHARABIC MATHEMATI" +
"CAL INITIAL SADARABIC MATHEMATICAL INITIAL QAFARABIC MATHEMATICAL INITIA" +
"L SHEENARABIC MATHEMATICAL INITIAL TEHARABIC MATHEMATICAL INITIAL THEHAR" +
"ABIC MATHEMATICAL INITIAL KHAHARABIC MATHEMATICAL INITIAL DADARABIC MATH" +
"EMATICAL INITIAL GHAINARABIC MATHEMATICAL TAILED JEEMARABIC MATHEMATICAL" +
" TAILED HAHARABIC MATHEMATICAL TAILED YEHARABIC MATHEMATICAL TAILED LAMA" +
"RABIC MATHEMATICAL TAILED NOONARABIC MATHEMATICAL TAILED SEENARABIC MATH" +
"EMATICAL TAILED AINARABIC MATHEMATICAL TAILED SADARABIC MATHEMATICAL TAI" +
"LED QAFARABIC MATHEMATICAL TAILED SHEENARABIC MATHEMATICAL TAILED KHAHAR" +
"ABIC MATHEMATICAL TAILED DADARABIC MATHEMATICAL TAILED GHAINARABIC MATHE" +
"MATICAL TAILED DOTLESS NOONARABIC MATHEMATICAL TAILED DOTLESS QAFARABIC " +
"MATHEMATICAL STRETCHED BEHARABIC MATHEMATICAL STRETCHED JEEMARABIC MATHE" +
"MATICAL STRETCHED HEHARABIC MATHEMATICAL STRETCHED HAHARABIC MATHEMATICA" +
"L STRETCHED TAHARABIC MATHEMATICAL STRETCHED YEHARABIC MATHEMATICAL STRE" +
"TCHED KAFARABIC MATHEMATICAL STRETCHED MEEMARABIC MATHEMATICAL STRETCHED" +
" NOONARABIC MATHEMATICAL STRETCHED SEENARABIC MATHEMATICAL STRETCHED AIN" +
"ARABIC MATHEMATICAL STRETCHED FEHARABIC MATHEMATICAL STRETCHED SADARABIC" +
" MATHEMATICAL STRETCHED QAFARABIC MATHEMATICAL STRETCHED SHEENARABIC MAT" +
"HEMATICAL STRETCHED TEHARABIC MATHEMATICAL STRETCHED THEHARABIC MATHEMAT" +
"ICAL STRETCHED KHAHARABIC MATHEMATICAL STRETCHED DADARABIC MATHEMATICAL " +
"STRETCHED ZAHARABIC MATHEMATICAL STRETCHED GHAINARABIC MATHEMATICAL STRE" +
"TCHED DOTLESS BEHARABIC MATHEMATICAL STRETCHED DOTLESS FEHARABIC MATHEMA" +
"TICAL LOOPED ALEFARABIC MATHEMATICAL LOOPED BEHARABIC MATHEMATICAL LOOPE" +
"D JEEMARABIC MATHEMATICAL LOOPED DALARABIC MATHEMATICAL LOOPED HEHARABIC" +
" MATHEMATICAL LOOPED WAWARABIC MATHEMATICAL LOOPED ZAINARABIC MATHEMATIC" +
"AL LOOPED HAHARABIC MATHEMATICAL LOOPED TAHARABIC MATHEMATICAL LOOPED YE" +
"HARABIC MATHEMATICAL LOOPED LAMARABIC MATHEMATICAL LOOPED MEEMARABIC MAT" +
"HEMATICAL LOOPED NOONARABIC MATHEMATICAL LOOPED SEENARABIC MATHEMATICAL " +
"LOOPED AINARABIC MATHEMATICAL LOOPED FEHARABIC MATHEMATICAL LOOPED SADAR" +
"ABIC MATHEMATICAL LOOPED QAFARABIC MATHEMATICAL LOOPED REHARABIC MATHEMA" +
"TICAL LOOPED SHEENARABIC MATHEMATICAL LOOPED TEHARABIC MATHEMATICAL LOOP") + ("" +
"ED THEHARABIC MATHEMATICAL LOOPED KHAHARABIC MATHEMATICAL LOOPED THALARA" +
"BIC MATHEMATICAL LOOPED DADARABIC MATHEMATICAL LOOPED ZAHARABIC MATHEMAT" +
"ICAL LOOPED GHAINARABIC MATHEMATICAL DOUBLE-STRUCK BEHARABIC MATHEMATICA" +
"L DOUBLE-STRUCK JEEMARABIC MATHEMATICAL DOUBLE-STRUCK DALARABIC MATHEMAT" +
"ICAL DOUBLE-STRUCK WAWARABIC MATHEMATICAL DOUBLE-STRUCK ZAINARABIC MATHE" +
"MATICAL DOUBLE-STRUCK HAHARABIC MATHEMATICAL DOUBLE-STRUCK TAHARABIC MAT" +
"HEMATICAL DOUBLE-STRUCK YEHARABIC MATHEMATICAL DOUBLE-STRUCK LAMARABIC M" +
"ATHEMATICAL DOUBLE-STRUCK MEEMARABIC MATHEMATICAL DOUBLE-STRUCK NOONARAB" +
"IC MATHEMATICAL DOUBLE-STRUCK SEENARABIC MATHEMATICAL DOUBLE-STRUCK AINA" +
"RABIC MATHEMATICAL DOUBLE-STRUCK FEHARABIC MATHEMATICAL DOUBLE-STRUCK SA" +
"DARABIC MATHEMATICAL DOUBLE-STRUCK QAFARABIC MATHEMATICAL DOUBLE-STRUCK " +
"REHARABIC MATHEMATICAL DOUBLE-STRUCK SHEENARABIC MATHEMATICAL DOUBLE-STR" +
"UCK TEHARABIC MATHEMATICAL DOUBLE-STRUCK THEHARABIC MATHEMATICAL DOUBLE-" +
"STRUCK KHAHARABIC MATHEMATICAL DOUBLE-STRUCK THALARABIC MATHEMATICAL DOU" +
"BLE-STRUCK DADARABIC MATHEMATICAL DOUBLE-STRUCK ZAHARABIC MATHEMATICAL D" +
"OUBLE-STRUCK GHAINARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEE" +
"LARABIC MATHEMATICAL OPERATOR HAH WITH DALMAHJONG TILE EAST WINDMAHJONG " +
"TILE SOUTH WINDMAHJONG TILE WEST WINDMAHJONG TILE NORTH WINDMAHJONG TILE" +
" RED DRAGONMAHJONG TILE GREEN DRAGONMAHJONG TILE WHITE DRAGONMAHJONG TIL" +
"E ONE OF CHARACTERSMAHJONG TILE TWO OF CHARACTERSMAHJONG TILE THREE OF C" +
"HARACTERSMAHJONG TILE FOUR OF CHARACTERSMAHJONG TILE FIVE OF CHARACTERSM" +
"AHJONG TILE SIX OF CHARACTERSMAHJONG TILE SEVEN OF CHARACTERSMAHJONG TIL" +
"E EIGHT OF CHARACTERSMAHJONG TILE NINE OF CHARACTERSMAHJONG TILE ONE OF " +
"BAMBOOSMAHJONG TILE TWO OF BAMBOOSMAHJONG TILE THREE OF BAMBOOSMAHJONG T" +
"ILE FOUR OF BAMBOOSMAHJONG TILE FIVE OF BAMBOOSMAHJONG TILE SIX OF BAMBO" +
"OSMAHJONG TILE SEVEN OF BAMBOOSMAHJONG TILE EIGHT OF BAMBOOSMAHJONG TILE" +
" NINE OF BAMBOOSMAHJONG TILE ONE OF CIRCLESMAHJONG TILE TWO OF CIRCLESMA" +
"HJONG TILE THREE OF CIRCLESMAHJONG TILE FOUR OF CIRCLESMAHJONG TILE FIVE" +
" OF CIRCLESMAHJONG TILE SIX OF CIRCLESMAHJONG TILE SEVEN OF CIRCLESMAHJO" +
"NG TILE EIGHT OF CIRCLESMAHJONG TILE NINE OF CIRCLESMAHJONG TILE PLUMMAH" +
"JONG TILE ORCHIDMAHJONG TILE BAMBOOMAHJONG TILE CHRYSANTHEMUMMAHJONG TIL" +
"E SPRINGMAHJONG TILE SUMMERMAHJONG TILE AUTUMNMAHJONG TILE WINTERMAHJONG" +
" TILE JOKERMAHJONG TILE BACKDOMINO TILE HORIZONTAL BACKDOMINO TILE HORIZ" +
"ONTAL-00-00DOMINO TILE HORIZONTAL-00-01DOMINO TILE HORIZONTAL-00-02DOMIN" +
"O TILE HORIZONTAL-00-03DOMINO TILE HORIZONTAL-00-04DOMINO TILE HORIZONTA" +
"L-00-05DOMINO TILE HORIZONTAL-00-06DOMINO TILE HORIZONTAL-01-00DOMINO TI" +
"LE HORIZONTAL-01-01DOMINO TILE HORIZONTAL-01-02DOMINO TILE HORIZONTAL-01" +
"-03DOMINO TILE HORIZONTAL-01-04DOMINO TILE HORIZONTAL-01-05DOMINO TILE H" +
"ORIZONTAL-01-06DOMINO TILE HORIZONTAL-02-00DOMINO TILE HORIZONTAL-02-01D" +
"OMINO TILE HORIZONTAL-02-02DOMINO TILE HORIZONTAL-02-03DOMINO TILE HORIZ" +
"ONTAL-02-04DOMINO TILE HORIZONTAL-02-05DOMINO TILE HORIZONTAL-02-06DOMIN" +
"O TILE HORIZONTAL-03-00DOMINO TILE HORIZONTAL-03-01DOMINO TILE HORIZONTA" +
"L-03-02DOMINO TILE HORIZONTAL-03-03DOMINO TILE HORIZONTAL-03-04DOMINO TI" +
"LE HORIZONTAL-03-05DOMINO TILE HORIZONTAL-03-06DOMINO TILE HORIZONTAL-04" +
"-00DOMINO TILE HORIZONTAL-04-01DOMINO TILE HORIZONTAL-04-02DOMINO TILE H" +
"ORIZONTAL-04-03DOMINO TILE HORIZONTAL-04-04DOMINO TILE HORIZONTAL-04-05D" +
"OMINO TILE HORIZONTAL-04-06DOMINO TILE HORIZONTAL-05-00DOMINO TILE HORIZ" +
"ONTAL-05-01DOMINO TILE HORIZONTAL-05-02DOMINO TILE HORIZONTAL-05-03DOMIN" +
"O TILE HORIZONTAL-05-04DOMINO TILE HORIZONTAL-05-05DOMINO TILE HORIZONTA" +
"L-05-06DOMINO TILE HORIZONTAL-06-00DOMINO TILE HORIZONTAL-06-01DOMINO TI" +
"LE HORIZONTAL-06-02DOMINO TILE HORIZONTAL-06-03DOMINO TILE HORIZONTAL-06" +
"-04DOMINO TILE HORIZONTAL-06-05DOMINO TILE HORIZONTAL-06-06DOMINO TILE V" +
"ERTICAL BACKDOMINO TILE VERTICAL-00-00DOMINO TILE VERTICAL-00-01DOMINO T" +
"ILE VERTICAL-00-02DOMINO TILE VERTICAL-00-03DOMINO TILE VERTICAL-00-04DO" +
"MINO TILE VERTICAL-00-05DOMINO TILE VERTICAL-00-06DOMINO TILE VERTICAL-0" +
"1-00DOMINO TILE VERTICAL-01-01DOMINO TILE VERTICAL-01-02DOMINO TILE VERT" +
"ICAL-01-03DOMINO TILE VERTICAL-01-04DOMINO TILE VERTICAL-01-05DOMINO TIL" +
"E VERTICAL-01-06DOMINO TILE VERTICAL-02-00DOMINO TILE VERTICAL-02-01DOMI" +
"NO TILE VERTICAL-02-02DOMINO TILE VERTICAL-02-03DOMINO TILE VERTICAL-02-" +
"04DOMINO TILE VERTICAL-02-05DOMINO TILE VERTICAL-02-06DOMINO TILE VERTIC" +
"AL-03-00DOMINO TILE VERTICAL-03-01DOMINO TILE VERTICAL-03-02DOMINO TILE " +
"VERTICAL-03-03DOMINO TILE VERTICAL-03-04DOMINO TILE VERTICAL-03-05DOMINO" +
" TILE VERTICAL-03-06DOMINO TILE VERTICAL-04-00DOMINO TILE VERTICAL-04-01" +
"DOMINO TILE VERTICAL-04-02DOMINO TILE VERTICAL-04-03DOMINO TILE VERTICAL") + ("" +
"-04-04DOMINO TILE VERTICAL-04-05DOMINO TILE VERTICAL-04-06DOMINO TILE VE" +
"RTICAL-05-00DOMINO TILE VERTICAL-05-01DOMINO TILE VERTICAL-05-02DOMINO T" +
"ILE VERTICAL-05-03DOMINO TILE VERTICAL-05-04DOMINO TILE VERTICAL-05-05DO" +
"MINO TILE VERTICAL-05-06DOMINO TILE VERTICAL-06-00DOMINO TILE VERTICAL-0" +
"6-01DOMINO TILE VERTICAL-06-02DOMINO TILE VERTICAL-06-03DOMINO TILE VERT" +
"ICAL-06-04DOMINO TILE VERTICAL-06-05DOMINO TILE VERTICAL-06-06PLAYING CA" +
"RD BACKPLAYING CARD ACE OF SPADESPLAYING CARD TWO OF SPADESPLAYING CARD " +
"THREE OF SPADESPLAYING CARD FOUR OF SPADESPLAYING CARD FIVE OF SPADESPLA" +
"YING CARD SIX OF SPADESPLAYING CARD SEVEN OF SPADESPLAYING CARD EIGHT OF" +
" SPADESPLAYING CARD NINE OF SPADESPLAYING CARD TEN OF SPADESPLAYING CARD" +
" JACK OF SPADESPLAYING CARD KNIGHT OF SPADESPLAYING CARD QUEEN OF SPADES" +
"PLAYING CARD KING OF SPADESPLAYING CARD ACE OF HEARTSPLAYING CARD TWO OF" +
" HEARTSPLAYING CARD THREE OF HEARTSPLAYING CARD FOUR OF HEARTSPLAYING CA" +
"RD FIVE OF HEARTSPLAYING CARD SIX OF HEARTSPLAYING CARD SEVEN OF HEARTSP" +
"LAYING CARD EIGHT OF HEARTSPLAYING CARD NINE OF HEARTSPLAYING CARD TEN O" +
"F HEARTSPLAYING CARD JACK OF HEARTSPLAYING CARD KNIGHT OF HEARTSPLAYING " +
"CARD QUEEN OF HEARTSPLAYING CARD KING OF HEARTSPLAYING CARD RED JOKERPLA" +
"YING CARD ACE OF DIAMONDSPLAYING CARD TWO OF DIAMONDSPLAYING CARD THREE " +
"OF DIAMONDSPLAYING CARD FOUR OF DIAMONDSPLAYING CARD FIVE OF DIAMONDSPLA" +
"YING CARD SIX OF DIAMONDSPLAYING CARD SEVEN OF DIAMONDSPLAYING CARD EIGH" +
"T OF DIAMONDSPLAYING CARD NINE OF DIAMONDSPLAYING CARD TEN OF DIAMONDSPL" +
"AYING CARD JACK OF DIAMONDSPLAYING CARD KNIGHT OF DIAMONDSPLAYING CARD Q" +
"UEEN OF DIAMONDSPLAYING CARD KING OF DIAMONDSPLAYING CARD BLACK JOKERPLA" +
"YING CARD ACE OF CLUBSPLAYING CARD TWO OF CLUBSPLAYING CARD THREE OF CLU" +
"BSPLAYING CARD FOUR OF CLUBSPLAYING CARD FIVE OF CLUBSPLAYING CARD SIX O" +
"F CLUBSPLAYING CARD SEVEN OF CLUBSPLAYING CARD EIGHT OF CLUBSPLAYING CAR" +
"D NINE OF CLUBSPLAYING CARD TEN OF CLUBSPLAYING CARD JACK OF CLUBSPLAYIN" +
"G CARD KNIGHT OF CLUBSPLAYING CARD QUEEN OF CLUBSPLAYING CARD KING OF CL" +
"UBSPLAYING CARD WHITE JOKERPLAYING CARD FOOLPLAYING CARD TRUMP-1PLAYING " +
"CARD TRUMP-2PLAYING CARD TRUMP-3PLAYING CARD TRUMP-4PLAYING CARD TRUMP-5" +
"PLAYING CARD TRUMP-6PLAYING CARD TRUMP-7PLAYING CARD TRUMP-8PLAYING CARD" +
" TRUMP-9PLAYING CARD TRUMP-10PLAYING CARD TRUMP-11PLAYING CARD TRUMP-12P" +
"LAYING CARD TRUMP-13PLAYING CARD TRUMP-14PLAYING CARD TRUMP-15PLAYING CA" +
"RD TRUMP-16PLAYING CARD TRUMP-17PLAYING CARD TRUMP-18PLAYING CARD TRUMP-" +
"19PLAYING CARD TRUMP-20PLAYING CARD TRUMP-21DIGIT ZERO FULL STOPDIGIT ZE" +
"RO COMMADIGIT ONE COMMADIGIT TWO COMMADIGIT THREE COMMADIGIT FOUR COMMAD" +
"IGIT FIVE COMMADIGIT SIX COMMADIGIT SEVEN COMMADIGIT EIGHT COMMADIGIT NI" +
"NE COMMADINGBAT CIRCLED SANS-SERIF DIGIT ZERODINGBAT NEGATIVE CIRCLED SA" +
"NS-SERIF DIGIT ZEROCIRCLED ZERO WITH SLASHCIRCLED ANTICLOCKWISE ARROWCIR" +
"CLED DOLLAR SIGN WITH OVERLAID BACKSLASHPARENTHESIZED LATIN CAPITAL LETT" +
"ER APARENTHESIZED LATIN CAPITAL LETTER BPARENTHESIZED LATIN CAPITAL LETT" +
"ER CPARENTHESIZED LATIN CAPITAL LETTER DPARENTHESIZED LATIN CAPITAL LETT" +
"ER EPARENTHESIZED LATIN CAPITAL LETTER FPARENTHESIZED LATIN CAPITAL LETT" +
"ER GPARENTHESIZED LATIN CAPITAL LETTER HPARENTHESIZED LATIN CAPITAL LETT" +
"ER IPARENTHESIZED LATIN CAPITAL LETTER JPARENTHESIZED LATIN CAPITAL LETT" +
"ER KPARENTHESIZED LATIN CAPITAL LETTER LPARENTHESIZED LATIN CAPITAL LETT" +
"ER MPARENTHESIZED LATIN CAPITAL LETTER NPARENTHESIZED LATIN CAPITAL LETT" +
"ER OPARENTHESIZED LATIN CAPITAL LETTER PPARENTHESIZED LATIN CAPITAL LETT" +
"ER QPARENTHESIZED LATIN CAPITAL LETTER RPARENTHESIZED LATIN CAPITAL LETT" +
"ER SPARENTHESIZED LATIN CAPITAL LETTER TPARENTHESIZED LATIN CAPITAL LETT" +
"ER UPARENTHESIZED LATIN CAPITAL LETTER VPARENTHESIZED LATIN CAPITAL LETT" +
"ER WPARENTHESIZED LATIN CAPITAL LETTER XPARENTHESIZED LATIN CAPITAL LETT" +
"ER YPARENTHESIZED LATIN CAPITAL LETTER ZTORTOISE SHELL BRACKETED LATIN C" +
"APITAL LETTER SCIRCLED ITALIC LATIN CAPITAL LETTER CCIRCLED ITALIC LATIN" +
" CAPITAL LETTER RCIRCLED CDCIRCLED WZCOPYLEFT SYMBOLSQUARED LATIN CAPITA" +
"L LETTER ASQUARED LATIN CAPITAL LETTER BSQUARED LATIN CAPITAL LETTER CSQ" +
"UARED LATIN CAPITAL LETTER DSQUARED LATIN CAPITAL LETTER ESQUARED LATIN " +
"CAPITAL LETTER FSQUARED LATIN CAPITAL LETTER GSQUARED LATIN CAPITAL LETT" +
"ER HSQUARED LATIN CAPITAL LETTER ISQUARED LATIN CAPITAL LETTER JSQUARED " +
"LATIN CAPITAL LETTER KSQUARED LATIN CAPITAL LETTER LSQUARED LATIN CAPITA" +
"L LETTER MSQUARED LATIN CAPITAL LETTER NSQUARED LATIN CAPITAL LETTER OSQ" +
"UARED LATIN CAPITAL LETTER PSQUARED LATIN CAPITAL LETTER QSQUARED LATIN " +
"CAPITAL LETTER RSQUARED LATIN CAPITAL LETTER SSQUARED LATIN CAPITAL LETT" +
"ER TSQUARED LATIN CAPITAL LETTER USQUARED LATIN CAPITAL LETTER VSQUARED ") + ("" +
"LATIN CAPITAL LETTER WSQUARED LATIN CAPITAL LETTER XSQUARED LATIN CAPITA" +
"L LETTER YSQUARED LATIN CAPITAL LETTER ZSQUARED HVSQUARED MVSQUARED SDSQ" +
"UARED SSSQUARED PPVSQUARED WCNEGATIVE CIRCLED LATIN CAPITAL LETTER ANEGA" +
"TIVE CIRCLED LATIN CAPITAL LETTER BNEGATIVE CIRCLED LATIN CAPITAL LETTER" +
" CNEGATIVE CIRCLED LATIN CAPITAL LETTER DNEGATIVE CIRCLED LATIN CAPITAL " +
"LETTER ENEGATIVE CIRCLED LATIN CAPITAL LETTER FNEGATIVE CIRCLED LATIN CA" +
"PITAL LETTER GNEGATIVE CIRCLED LATIN CAPITAL LETTER HNEGATIVE CIRCLED LA" +
"TIN CAPITAL LETTER INEGATIVE CIRCLED LATIN CAPITAL LETTER JNEGATIVE CIRC" +
"LED LATIN CAPITAL LETTER KNEGATIVE CIRCLED LATIN CAPITAL LETTER LNEGATIV" +
"E CIRCLED LATIN CAPITAL LETTER MNEGATIVE CIRCLED LATIN CAPITAL LETTER NN" +
"EGATIVE CIRCLED LATIN CAPITAL LETTER ONEGATIVE CIRCLED LATIN CAPITAL LET" +
"TER PNEGATIVE CIRCLED LATIN CAPITAL LETTER QNEGATIVE CIRCLED LATIN CAPIT" +
"AL LETTER RNEGATIVE CIRCLED LATIN CAPITAL LETTER SNEGATIVE CIRCLED LATIN" +
" CAPITAL LETTER TNEGATIVE CIRCLED LATIN CAPITAL LETTER UNEGATIVE CIRCLED" +
" LATIN CAPITAL LETTER VNEGATIVE CIRCLED LATIN CAPITAL LETTER WNEGATIVE C" +
"IRCLED LATIN CAPITAL LETTER XNEGATIVE CIRCLED LATIN CAPITAL LETTER YNEGA" +
"TIVE CIRCLED LATIN CAPITAL LETTER ZRAISED MC SIGNRAISED MD SIGNRAISED MR" +
" SIGNCIRCLED CCCIRCLED C WITH OVERLAID BACKSLASHCIRCLED HUMAN FIGURENEGA" +
"TIVE SQUARED LATIN CAPITAL LETTER ANEGATIVE SQUARED LATIN CAPITAL LETTER" +
" BNEGATIVE SQUARED LATIN CAPITAL LETTER CNEGATIVE SQUARED LATIN CAPITAL " +
"LETTER DNEGATIVE SQUARED LATIN CAPITAL LETTER ENEGATIVE SQUARED LATIN CA" +
"PITAL LETTER FNEGATIVE SQUARED LATIN CAPITAL LETTER GNEGATIVE SQUARED LA" +
"TIN CAPITAL LETTER HNEGATIVE SQUARED LATIN CAPITAL LETTER INEGATIVE SQUA" +
"RED LATIN CAPITAL LETTER JNEGATIVE SQUARED LATIN CAPITAL LETTER KNEGATIV" +
"E SQUARED LATIN CAPITAL LETTER LNEGATIVE SQUARED LATIN CAPITAL LETTER MN" +
"EGATIVE SQUARED LATIN CAPITAL LETTER NNEGATIVE SQUARED LATIN CAPITAL LET" +
"TER ONEGATIVE SQUARED LATIN CAPITAL LETTER PNEGATIVE SQUARED LATIN CAPIT" +
"AL LETTER QNEGATIVE SQUARED LATIN CAPITAL LETTER RNEGATIVE SQUARED LATIN" +
" CAPITAL LETTER SNEGATIVE SQUARED LATIN CAPITAL LETTER TNEGATIVE SQUARED" +
" LATIN CAPITAL LETTER UNEGATIVE SQUARED LATIN CAPITAL LETTER VNEGATIVE S" +
"QUARED LATIN CAPITAL LETTER WNEGATIVE SQUARED LATIN CAPITAL LETTER XNEGA" +
"TIVE SQUARED LATIN CAPITAL LETTER YNEGATIVE SQUARED LATIN CAPITAL LETTER" +
" ZCROSSED NEGATIVE SQUARED LATIN CAPITAL LETTER PNEGATIVE SQUARED ICNEGA" +
"TIVE SQUARED PANEGATIVE SQUARED SANEGATIVE SQUARED ABNEGATIVE SQUARED WC" +
"SQUARE DJSQUARED CLSQUARED COOLSQUARED FREESQUARED IDSQUARED NEWSQUARED " +
"NGSQUARED OKSQUARED SOSSQUARED UP WITH EXCLAMATION MARKSQUARED VSSQUARED" +
" THREE DSQUARED SECOND SCREENSQUARED TWO KSQUARED FOUR KSQUARED EIGHT KS" +
"QUARED FIVE POINT ONESQUARED SEVEN POINT ONESQUARED TWENTY-TWO POINT TWO" +
"SQUARED SIXTY PSQUARED ONE HUNDRED TWENTY PSQUARED LATIN SMALL LETTER DS" +
"QUARED HCSQUARED HDRSQUARED HI-RESSQUARED LOSSLESSSQUARED SHVSQUARED UHD" +
"SQUARED VODMASK WORK SYMBOLREGIONAL INDICATOR SYMBOL LETTER AREGIONAL IN" +
"DICATOR SYMBOL LETTER BREGIONAL INDICATOR SYMBOL LETTER CREGIONAL INDICA" +
"TOR SYMBOL LETTER DREGIONAL INDICATOR SYMBOL LETTER EREGIONAL INDICATOR " +
"SYMBOL LETTER FREGIONAL INDICATOR SYMBOL LETTER GREGIONAL INDICATOR SYMB" +
"OL LETTER HREGIONAL INDICATOR SYMBOL LETTER IREGIONAL INDICATOR SYMBOL L" +
"ETTER JREGIONAL INDICATOR SYMBOL LETTER KREGIONAL INDICATOR SYMBOL LETTE" +
"R LREGIONAL INDICATOR SYMBOL LETTER MREGIONAL INDICATOR SYMBOL LETTER NR" +
"EGIONAL INDICATOR SYMBOL LETTER OREGIONAL INDICATOR SYMBOL LETTER PREGIO" +
"NAL INDICATOR SYMBOL LETTER QREGIONAL INDICATOR SYMBOL LETTER RREGIONAL " +
"INDICATOR SYMBOL LETTER SREGIONAL INDICATOR SYMBOL LETTER TREGIONAL INDI" +
"CATOR SYMBOL LETTER UREGIONAL INDICATOR SYMBOL LETTER VREGIONAL INDICATO" +
"R SYMBOL LETTER WREGIONAL INDICATOR SYMBOL LETTER XREGIONAL INDICATOR SY" +
"MBOL LETTER YREGIONAL INDICATOR SYMBOL LETTER ZSQUARE HIRAGANA HOKASQUAR" +
"ED KATAKANA KOKOSQUARED KATAKANA SASQUARED CJK UNIFIED IDEOGRAPH-624BSQU" +
"ARED CJK UNIFIED IDEOGRAPH-5B57SQUARED CJK UNIFIED IDEOGRAPH-53CCSQUARED" +
" KATAKANA DESQUARED CJK UNIFIED IDEOGRAPH-4E8CSQUARED CJK UNIFIED IDEOGR" +
"APH-591ASQUARED CJK UNIFIED IDEOGRAPH-89E3SQUARED CJK UNIFIED IDEOGRAPH-" +
"5929SQUARED CJK UNIFIED IDEOGRAPH-4EA4SQUARED CJK UNIFIED IDEOGRAPH-6620" +
"SQUARED CJK UNIFIED IDEOGRAPH-7121SQUARED CJK UNIFIED IDEOGRAPH-6599SQUA" +
"RED CJK UNIFIED IDEOGRAPH-524DSQUARED CJK UNIFIED IDEOGRAPH-5F8CSQUARED " +
"CJK UNIFIED IDEOGRAPH-518DSQUARED CJK UNIFIED IDEOGRAPH-65B0SQUARED CJK " +
"UNIFIED IDEOGRAPH-521DSQUARED CJK UNIFIED IDEOGRAPH-7D42SQUARED CJK UNIF" +
"IED IDEOGRAPH-751FSQUARED CJK UNIFIED IDEOGRAPH-8CA9SQUARED CJK UNIFIED " +
"IDEOGRAPH-58F0SQUARED CJK UNIFIED IDEOGRAPH-5439SQUARED CJK UNIFIED IDEO") + ("" +
"GRAPH-6F14SQUARED CJK UNIFIED IDEOGRAPH-6295SQUARED CJK UNIFIED IDEOGRAP" +
"H-6355SQUARED CJK UNIFIED IDEOGRAPH-4E00SQUARED CJK UNIFIED IDEOGRAPH-4E" +
"09SQUARED CJK UNIFIED IDEOGRAPH-904ASQUARED CJK UNIFIED IDEOGRAPH-5DE6SQ" +
"UARED CJK UNIFIED IDEOGRAPH-4E2DSQUARED CJK UNIFIED IDEOGRAPH-53F3SQUARE" +
"D CJK UNIFIED IDEOGRAPH-6307SQUARED CJK UNIFIED IDEOGRAPH-8D70SQUARED CJ" +
"K UNIFIED IDEOGRAPH-6253SQUARED CJK UNIFIED IDEOGRAPH-7981SQUARED CJK UN" +
"IFIED IDEOGRAPH-7A7ASQUARED CJK UNIFIED IDEOGRAPH-5408SQUARED CJK UNIFIE" +
"D IDEOGRAPH-6E80SQUARED CJK UNIFIED IDEOGRAPH-6709SQUARED CJK UNIFIED ID" +
"EOGRAPH-6708SQUARED CJK UNIFIED IDEOGRAPH-7533SQUARED CJK UNIFIED IDEOGR" +
"APH-5272SQUARED CJK UNIFIED IDEOGRAPH-55B6SQUARED CJK UNIFIED IDEOGRAPH-" +
"914DTORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672CTORTOISE SHELL BR" +
"ACKETED CJK UNIFIED IDEOGRAPH-4E09TORTOISE SHELL BRACKETED CJK UNIFIED I" +
"DEOGRAPH-4E8CTORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-5B89TORTOISE" +
" SHELL BRACKETED CJK UNIFIED IDEOGRAPH-70B9TORTOISE SHELL BRACKETED CJK " +
"UNIFIED IDEOGRAPH-6253TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-76D" +
"7TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-52DDTORTOISE SHELL BRACK" +
"ETED CJK UNIFIED IDEOGRAPH-6557CIRCLED IDEOGRAPH ADVANTAGECIRCLED IDEOGR" +
"APH ACCEPTROUNDED SYMBOL FOR FUROUNDED SYMBOL FOR LUROUNDED SYMBOL FOR S" +
"HOUROUNDED SYMBOL FOR XIROUNDED SYMBOL FOR SHUANGXIROUNDED SYMBOL FOR CA" +
"ICYCLONEFOGGYCLOSED UMBRELLANIGHT WITH STARSSUNRISE OVER MOUNTAINSSUNRIS" +
"ECITYSCAPE AT DUSKSUNSET OVER BUILDINGSRAINBOWBRIDGE AT NIGHTWATER WAVEV" +
"OLCANOMILKY WAYEARTH GLOBE EUROPE-AFRICAEARTH GLOBE AMERICASEARTH GLOBE " +
"ASIA-AUSTRALIAGLOBE WITH MERIDIANSNEW MOON SYMBOLWAXING CRESCENT MOON SY" +
"MBOLFIRST QUARTER MOON SYMBOLWAXING GIBBOUS MOON SYMBOLFULL MOON SYMBOLW" +
"ANING GIBBOUS MOON SYMBOLLAST QUARTER MOON SYMBOLWANING CRESCENT MOON SY" +
"MBOLCRESCENT MOONNEW MOON WITH FACEFIRST QUARTER MOON WITH FACELAST QUAR" +
"TER MOON WITH FACEFULL MOON WITH FACESUN WITH FACEGLOWING STARSHOOTING S" +
"TARTHERMOMETERBLACK DROPLETWHITE SUNWHITE SUN WITH SMALL CLOUDWHITE SUN " +
"BEHIND CLOUDWHITE SUN BEHIND CLOUD WITH RAINCLOUD WITH RAINCLOUD WITH SN" +
"OWCLOUD WITH LIGHTNINGCLOUD WITH TORNADOFOGWIND BLOWING FACEHOT DOGTACOB" +
"URRITOCHESTNUTSEEDLINGEVERGREEN TREEDECIDUOUS TREEPALM TREECACTUSHOT PEP" +
"PERTULIPCHERRY BLOSSOMROSEHIBISCUSSUNFLOWERBLOSSOMEAR OF MAIZEEAR OF RIC" +
"EHERBFOUR LEAF CLOVERMAPLE LEAFFALLEN LEAFLEAF FLUTTERING IN WINDMUSHROO" +
"MTOMATOAUBERGINEGRAPESMELONWATERMELONTANGERINELEMONBANANAPINEAPPLERED AP" +
"PLEGREEN APPLEPEARPEACHCHERRIESSTRAWBERRYHAMBURGERSLICE OF PIZZAMEAT ON " +
"BONEPOULTRY LEGRICE CRACKERRICE BALLCOOKED RICECURRY AND RICESTEAMING BO" +
"WLSPAGHETTIBREADFRENCH FRIESROASTED SWEET POTATODANGOODENSUSHIFRIED SHRI" +
"MPFISH CAKE WITH SWIRL DESIGNSOFT ICE CREAMSHAVED ICEICE CREAMDOUGHNUTCO" +
"OKIECHOCOLATE BARCANDYLOLLIPOPCUSTARDHONEY POTSHORTCAKEBENTO BOXPOT OF F" +
"OODCOOKINGFORK AND KNIFETEACUP WITHOUT HANDLESAKE BOTTLE AND CUPWINE GLA" +
"SSCOCKTAIL GLASSTROPICAL DRINKBEER MUGCLINKING BEER MUGSBABY BOTTLEFORK " +
"AND KNIFE WITH PLATEBOTTLE WITH POPPING CORKPOPCORNRIBBONWRAPPED PRESENT" +
"BIRTHDAY CAKEJACK-O-LANTERNCHRISTMAS TREEFATHER CHRISTMASFIREWORKSFIREWO" +
"RK SPARKLERBALLOONPARTY POPPERCONFETTI BALLTANABATA TREECROSSED FLAGSPIN" +
"E DECORATIONJAPANESE DOLLSCARP STREAMERWIND CHIMEMOON VIEWING CEREMONYSC" +
"HOOL SATCHELGRADUATION CAPHEART WITH TIP ON THE LEFTBOUQUET OF FLOWERSMI" +
"LITARY MEDALREMINDER RIBBONMUSICAL KEYBOARD WITH JACKSSTUDIO MICROPHONEL" +
"EVEL SLIDERCONTROL KNOBSBEAMED ASCENDING MUSICAL NOTESBEAMED DESCENDING " +
"MUSICAL NOTESFILM FRAMESADMISSION TICKETSCAROUSEL HORSEFERRIS WHEELROLLE" +
"R COASTERFISHING POLE AND FISHMICROPHONEMOVIE CAMERACINEMAHEADPHONEARTIS" +
"T PALETTETOP HATCIRCUS TENTTICKETCLAPPER BOARDPERFORMING ARTSVIDEO GAMED" +
"IRECT HITSLOT MACHINEBILLIARDSGAME DIEBOWLINGFLOWER PLAYING CARDSMUSICAL" +
" NOTEMULTIPLE MUSICAL NOTESSAXOPHONEGUITARMUSICAL KEYBOARDTRUMPETVIOLINM" +
"USICAL SCORERUNNING SHIRT WITH SASHTENNIS RACQUET AND BALLSKI AND SKI BO" +
"OTBASKETBALL AND HOOPCHEQUERED FLAGSNOWBOARDERRUNNERSURFERSPORTS MEDALTR" +
"OPHYHORSE RACINGAMERICAN FOOTBALLRUGBY FOOTBALLSWIMMERWEIGHT LIFTERGOLFE" +
"RRACING MOTORCYCLERACING CARCRICKET BAT AND BALLVOLLEYBALLFIELD HOCKEY S" +
"TICK AND BALLICE HOCKEY STICK AND PUCKTABLE TENNIS PADDLE AND BALLSNOW C" +
"APPED MOUNTAINCAMPINGBEACH WITH UMBRELLABUILDING CONSTRUCTIONHOUSE BUILD" +
"INGSCITYSCAPEDERELICT HOUSE BUILDINGCLASSICAL BUILDINGDESERTDESERT ISLAN" +
"DNATIONAL PARKSTADIUMHOUSE BUILDINGHOUSE WITH GARDENOFFICE BUILDINGJAPAN" +
"ESE POST OFFICEEUROPEAN POST OFFICEHOSPITALBANKAUTOMATED TELLER MACHINEH" +
"OTELLOVE HOTELCONVENIENCE STORESCHOOLDEPARTMENT STOREFACTORYIZAKAYA LANT" +
"ERNJAPANESE CASTLEEUROPEAN CASTLEWHITE PENNANTBLACK PENNANTWAVING WHITE ") + ("" +
"FLAGWAVING BLACK FLAGROSETTEBLACK ROSETTELABELBADMINTON RACQUET AND SHUT" +
"TLECOCKBOW AND ARROWAMPHORAEMOJI MODIFIER FITZPATRICK TYPE-1-2EMOJI MODI" +
"FIER FITZPATRICK TYPE-3EMOJI MODIFIER FITZPATRICK TYPE-4EMOJI MODIFIER F" +
"ITZPATRICK TYPE-5EMOJI MODIFIER FITZPATRICK TYPE-6RATMOUSEOXWATER BUFFAL" +
"OCOWTIGERLEOPARDRABBITCATDRAGONCROCODILEWHALESNAILSNAKEHORSERAMGOATSHEEP" +
"MONKEYROOSTERCHICKENDOGPIGBOARELEPHANTOCTOPUSSPIRAL SHELLBUGANTHONEYBEEL" +
"ADY BEETLEFISHTROPICAL FISHBLOWFISHTURTLEHATCHING CHICKBABY CHICKFRONT-F" +
"ACING BABY CHICKBIRDPENGUINKOALAPOODLEDROMEDARY CAMELBACTRIAN CAMELDOLPH" +
"INMOUSE FACECOW FACETIGER FACERABBIT FACECAT FACEDRAGON FACESPOUTING WHA" +
"LEHORSE FACEMONKEY FACEDOG FACEPIG FACEFROG FACEHAMSTER FACEWOLF FACEBEA" +
"R FACEPANDA FACEPIG NOSEPAW PRINTSCHIPMUNKEYESEYEEARNOSEMOUTHTONGUEWHITE" +
" UP POINTING BACKHAND INDEXWHITE DOWN POINTING BACKHAND INDEXWHITE LEFT " +
"POINTING BACKHAND INDEXWHITE RIGHT POINTING BACKHAND INDEXFISTED HAND SI" +
"GNWAVING HAND SIGNOK HAND SIGNTHUMBS UP SIGNTHUMBS DOWN SIGNCLAPPING HAN" +
"DS SIGNOPEN HANDS SIGNCROWNWOMANS HATEYEGLASSESNECKTIET-SHIRTJEANSDRESSK" +
"IMONOBIKINIWOMANS CLOTHESPURSEHANDBAGPOUCHMANS SHOEATHLETIC SHOEHIGH-HEE" +
"LED SHOEWOMANS SANDALWOMANS BOOTSFOOTPRINTSBUST IN SILHOUETTEBUSTS IN SI" +
"LHOUETTEBOYGIRLMANWOMANFAMILYMAN AND WOMAN HOLDING HANDSTWO MEN HOLDING " +
"HANDSTWO WOMEN HOLDING HANDSPOLICE OFFICERWOMAN WITH BUNNY EARSBRIDE WIT" +
"H VEILPERSON WITH BLOND HAIRMAN WITH GUA PI MAOMAN WITH TURBANOLDER MANO" +
"LDER WOMANBABYCONSTRUCTION WORKERPRINCESSJAPANESE OGREJAPANESE GOBLINGHO" +
"STBABY ANGELEXTRATERRESTRIAL ALIENALIEN MONSTERIMPSKULLINFORMATION DESK " +
"PERSONGUARDSMANDANCERLIPSTICKNAIL POLISHFACE MASSAGEHAIRCUTBARBER POLESY" +
"RINGEPILLKISS MARKLOVE LETTERRINGGEM STONEKISSBOUQUETCOUPLE WITH HEARTWE" +
"DDINGBEATING HEARTBROKEN HEARTTWO HEARTSSPARKLING HEARTGROWING HEARTHEAR" +
"T WITH ARROWBLUE HEARTGREEN HEARTYELLOW HEARTPURPLE HEARTHEART WITH RIBB" +
"ONREVOLVING HEARTSHEART DECORATIONDIAMOND SHAPE WITH A DOT INSIDEELECTRI" +
"C LIGHT BULBANGER SYMBOLBOMBSLEEPING SYMBOLCOLLISION SYMBOLSPLASHING SWE" +
"AT SYMBOLDROPLETDASH SYMBOLPILE OF POOFLEXED BICEPSDIZZY SYMBOLSPEECH BA" +
"LLOONTHOUGHT BALLOONWHITE FLOWERHUNDRED POINTS SYMBOLMONEY BAGCURRENCY E" +
"XCHANGEHEAVY DOLLAR SIGNCREDIT CARDBANKNOTE WITH YEN SIGNBANKNOTE WITH D" +
"OLLAR SIGNBANKNOTE WITH EURO SIGNBANKNOTE WITH POUND SIGNMONEY WITH WING" +
"SCHART WITH UPWARDS TREND AND YEN SIGNSEATPERSONAL COMPUTERBRIEFCASEMINI" +
"DISCFLOPPY DISKOPTICAL DISCDVDFILE FOLDEROPEN FILE FOLDERPAGE WITH CURLP" +
"AGE FACING UPCALENDARTEAR-OFF CALENDARCARD INDEXCHART WITH UPWARDS TREND" +
"CHART WITH DOWNWARDS TRENDBAR CHARTCLIPBOARDPUSHPINROUND PUSHPINPAPERCLI" +
"PSTRAIGHT RULERTRIANGULAR RULERBOOKMARK TABSLEDGERNOTEBOOKNOTEBOOK WITH " +
"DECORATIVE COVERCLOSED BOOKOPEN BOOKGREEN BOOKBLUE BOOKORANGE BOOKBOOKSN" +
"AME BADGESCROLLMEMOTELEPHONE RECEIVERPAGERFAX MACHINESATELLITE ANTENNAPU" +
"BLIC ADDRESS LOUDSPEAKERCHEERING MEGAPHONEOUTBOX TRAYINBOX TRAYPACKAGEE-" +
"MAIL SYMBOLINCOMING ENVELOPEENVELOPE WITH DOWNWARDS ARROW ABOVECLOSED MA" +
"ILBOX WITH LOWERED FLAGCLOSED MAILBOX WITH RAISED FLAGOPEN MAILBOX WITH " +
"RAISED FLAGOPEN MAILBOX WITH LOWERED FLAGPOSTBOXPOSTAL HORNNEWSPAPERMOBI" +
"LE PHONEMOBILE PHONE WITH RIGHTWARDS ARROW AT LEFTVIBRATION MODEMOBILE P" +
"HONE OFFNO MOBILE PHONESANTENNA WITH BARSCAMERACAMERA WITH FLASHVIDEO CA" +
"MERATELEVISIONRADIOVIDEOCASSETTEFILM PROJECTORPORTABLE STEREOPRAYER BEAD" +
"STWISTED RIGHTWARDS ARROWSCLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE" +
" ARROWSCLOCKWISE RIGHTWARDS AND LEFTWARDS OPEN CIRCLE ARROWS WITH CIRCLE" +
"D ONE OVERLAYCLOCKWISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWSANTICLOCK" +
"WISE DOWNWARDS AND UPWARDS OPEN CIRCLE ARROWSLOW BRIGHTNESS SYMBOLHIGH B" +
"RIGHTNESS SYMBOLSPEAKER WITH CANCELLATION STROKESPEAKERSPEAKER WITH ONE " +
"SOUND WAVESPEAKER WITH THREE SOUND WAVESBATTERYELECTRIC PLUGLEFT-POINTIN" +
"G MAGNIFYING GLASSRIGHT-POINTING MAGNIFYING GLASSLOCK WITH INK PENCLOSED" +
" LOCK WITH KEYKEYLOCKOPEN LOCKBELLBELL WITH CANCELLATION STROKEBOOKMARKL" +
"INK SYMBOLRADIO BUTTONBACK WITH LEFTWARDS ARROW ABOVEEND WITH LEFTWARDS " +
"ARROW ABOVEON WITH EXCLAMATION MARK WITH LEFT RIGHT ARROW ABOVESOON WITH" +
" RIGHTWARDS ARROW ABOVETOP WITH UPWARDS ARROW ABOVENO ONE UNDER EIGHTEEN" +
" SYMBOLKEYCAP TENINPUT SYMBOL FOR LATIN CAPITAL LETTERSINPUT SYMBOL FOR " +
"LATIN SMALL LETTERSINPUT SYMBOL FOR NUMBERSINPUT SYMBOL FOR SYMBOLSINPUT" +
" SYMBOL FOR LATIN LETTERSFIREELECTRIC TORCHWRENCHHAMMERNUT AND BOLTHOCHO" +
"PISTOLMICROSCOPETELESCOPECRYSTAL BALLSIX POINTED STAR WITH MIDDLE DOTJAP" +
"ANESE SYMBOL FOR BEGINNERTRIDENT EMBLEMBLACK SQUARE BUTTONWHITE SQUARE B" +
"UTTONLARGE RED CIRCLELARGE BLUE CIRCLELARGE ORANGE DIAMONDLARGE BLUE DIA" +
"MONDSMALL ORANGE DIAMONDSMALL BLUE DIAMONDUP-POINTING RED TRIANGLEDOWN-P") + ("" +
"OINTING RED TRIANGLEUP-POINTING SMALL RED TRIANGLEDOWN-POINTING SMALL RE" +
"D TRIANGLELOWER RIGHT SHADOWED WHITE CIRCLEUPPER RIGHT SHADOWED WHITE CI" +
"RCLECIRCLED CROSS POMMEECROSS POMMEE WITH HALF-CIRCLE BELOWCROSS POMMEEN" +
"OTCHED LEFT SEMICIRCLE WITH THREE DOTSNOTCHED RIGHT SEMICIRCLE WITH THRE" +
"E DOTSSYMBOL FOR MARKS CHAPTERWHITE LATIN CROSSHEAVY LATIN CROSSCELTIC C" +
"ROSSOM SYMBOLDOVE OF PEACEKAABAMOSQUESYNAGOGUEMENORAH WITH NINE BRANCHES" +
"BOWL OF HYGIEIACLOCK FACE ONE OCLOCKCLOCK FACE TWO OCLOCKCLOCK FACE THRE" +
"E OCLOCKCLOCK FACE FOUR OCLOCKCLOCK FACE FIVE OCLOCKCLOCK FACE SIX OCLOC" +
"KCLOCK FACE SEVEN OCLOCKCLOCK FACE EIGHT OCLOCKCLOCK FACE NINE OCLOCKCLO" +
"CK FACE TEN OCLOCKCLOCK FACE ELEVEN OCLOCKCLOCK FACE TWELVE OCLOCKCLOCK " +
"FACE ONE-THIRTYCLOCK FACE TWO-THIRTYCLOCK FACE THREE-THIRTYCLOCK FACE FO" +
"UR-THIRTYCLOCK FACE FIVE-THIRTYCLOCK FACE SIX-THIRTYCLOCK FACE SEVEN-THI" +
"RTYCLOCK FACE EIGHT-THIRTYCLOCK FACE NINE-THIRTYCLOCK FACE TEN-THIRTYCLO" +
"CK FACE ELEVEN-THIRTYCLOCK FACE TWELVE-THIRTYRIGHT SPEAKERRIGHT SPEAKER " +
"WITH ONE SOUND WAVERIGHT SPEAKER WITH THREE SOUND WAVESBULLHORNBULLHORN " +
"WITH SOUND WAVESRINGING BELLBOOKCANDLEMANTELPIECE CLOCKBLACK SKULL AND C" +
"ROSSBONESNO PIRACYHOLEMAN IN BUSINESS SUIT LEVITATINGSLEUTH OR SPYDARK S" +
"UNGLASSESSPIDERSPIDER WEBJOYSTICKMAN DANCINGLEFT HAND TELEPHONE RECEIVER" +
"TELEPHONE RECEIVER WITH PAGERIGHT HAND TELEPHONE RECEIVERWHITE TOUCHTONE" +
" TELEPHONEBLACK TOUCHTONE TELEPHONETELEPHONE ON TOP OF MODEMCLAMSHELL MO" +
"BILE PHONEBACK OF ENVELOPESTAMPED ENVELOPEENVELOPE WITH LIGHTNINGFLYING " +
"ENVELOPEPEN OVER STAMPED ENVELOPELINKED PAPERCLIPSBLACK PUSHPINLOWER LEF" +
"T PENCILLOWER LEFT BALLPOINT PENLOWER LEFT FOUNTAIN PENLOWER LEFT PAINTB" +
"RUSHLOWER LEFT CRAYONLEFT WRITING HANDTURNED OK HAND SIGNRAISED HAND WIT" +
"H FINGERS SPLAYEDREVERSED RAISED HAND WITH FINGERS SPLAYEDREVERSED THUMB" +
"S UP SIGNREVERSED THUMBS DOWN SIGNREVERSED VICTORY HANDREVERSED HAND WIT" +
"H MIDDLE FINGER EXTENDEDRAISED HAND WITH PART BETWEEN MIDDLE AND RING FI" +
"NGERSWHITE DOWN POINTING LEFT HAND INDEXSIDEWAYS WHITE LEFT POINTING IND" +
"EXSIDEWAYS WHITE RIGHT POINTING INDEXSIDEWAYS BLACK LEFT POINTING INDEXS" +
"IDEWAYS BLACK RIGHT POINTING INDEXBLACK LEFT POINTING BACKHAND INDEXBLAC" +
"K RIGHT POINTING BACKHAND INDEXSIDEWAYS WHITE UP POINTING INDEXSIDEWAYS " +
"WHITE DOWN POINTING INDEXSIDEWAYS BLACK UP POINTING INDEXSIDEWAYS BLACK " +
"DOWN POINTING INDEXBLACK UP POINTING BACKHAND INDEXBLACK DOWN POINTING B" +
"ACKHAND INDEXBLACK HEARTDESKTOP COMPUTERKEYBOARD AND MOUSETHREE NETWORKE" +
"D COMPUTERSPRINTERPOCKET CALCULATORBLACK HARD SHELL FLOPPY DISKWHITE HAR" +
"D SHELL FLOPPY DISKSOFT SHELL FLOPPY DISKTAPE CARTRIDGEWIRED KEYBOARDONE" +
" BUTTON MOUSETWO BUTTON MOUSETHREE BUTTON MOUSETRACKBALLOLD PERSONAL COM" +
"PUTERHARD DISKSCREENPRINTER ICONFAX ICONOPTICAL DISC ICONDOCUMENT WITH T" +
"EXTDOCUMENT WITH TEXT AND PICTUREDOCUMENT WITH PICTUREFRAME WITH PICTURE" +
"FRAME WITH TILESFRAME WITH AN XBLACK FOLDERFOLDEROPEN FOLDERCARD INDEX D" +
"IVIDERSCARD FILE BOXFILE CABINETEMPTY NOTEEMPTY NOTE PAGEEMPTY NOTE PADN" +
"OTENOTE PAGENOTE PADEMPTY DOCUMENTEMPTY PAGEEMPTY PAGESDOCUMENTPAGEPAGES" +
"WASTEBASKETSPIRAL NOTE PADSPIRAL CALENDAR PADDESKTOP WINDOWMINIMIZEMAXIM" +
"IZEOVERLAPCLOCKWISE RIGHT AND LEFT SEMICIRCLE ARROWSCANCELLATION XINCREA" +
"SE FONT SIZE SYMBOLDECREASE FONT SIZE SYMBOLCOMPRESSIONOLD KEYROLLED-UP " +
"NEWSPAPERPAGE WITH CIRCLED TEXTSTOCK CHARTDAGGER KNIFELIPSSPEAKING HEAD " +
"IN SILHOUETTETHREE RAYS ABOVETHREE RAYS BELOWTHREE RAYS LEFTTHREE RAYS R" +
"IGHTLEFT SPEECH BUBBLERIGHT SPEECH BUBBLETWO SPEECH BUBBLESTHREE SPEECH " +
"BUBBLESLEFT THOUGHT BUBBLERIGHT THOUGHT BUBBLELEFT ANGER BUBBLERIGHT ANG" +
"ER BUBBLEMOOD BUBBLELIGHTNING MOOD BUBBLELIGHTNING MOODBALLOT BOX WITH B" +
"ALLOTBALLOT SCRIPT XBALLOT BOX WITH SCRIPT XBALLOT BOLD SCRIPT XBALLOT B" +
"OX WITH BOLD SCRIPT XLIGHT CHECK MARKBALLOT BOX WITH BOLD CHECKWORLD MAP" +
"MOUNT FUJITOKYO TOWERSTATUE OF LIBERTYSILHOUETTE OF JAPANMOYAIGRINNING F" +
"ACEGRINNING FACE WITH SMILING EYESFACE WITH TEARS OF JOYSMILING FACE WIT" +
"H OPEN MOUTHSMILING FACE WITH OPEN MOUTH AND SMILING EYESSMILING FACE WI" +
"TH OPEN MOUTH AND COLD SWEATSMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLO" +
"SED EYESSMILING FACE WITH HALOSMILING FACE WITH HORNSWINKING FACESMILING" +
" FACE WITH SMILING EYESFACE SAVOURING DELICIOUS FOODRELIEVED FACESMILING" +
" FACE WITH HEART-SHAPED EYESSMILING FACE WITH SUNGLASSESSMIRKING FACENEU" +
"TRAL FACEEXPRESSIONLESS FACEUNAMUSED FACEFACE WITH COLD SWEATPENSIVE FAC" +
"ECONFUSED FACECONFOUNDED FACEKISSING FACEFACE THROWING A KISSKISSING FAC" +
"E WITH SMILING EYESKISSING FACE WITH CLOSED EYESFACE WITH STUCK-OUT TONG" +
"UEFACE WITH STUCK-OUT TONGUE AND WINKING EYEFACE WITH STUCK-OUT TONGUE A" +
"ND TIGHTLY-CLOSED EYESDISAPPOINTED FACEWORRIED FACEANGRY FACEPOUTING FAC") + ("" +
"ECRYING FACEPERSEVERING FACEFACE WITH LOOK OF TRIUMPHDISAPPOINTED BUT RE" +
"LIEVED FACEFROWNING FACE WITH OPEN MOUTHANGUISHED FACEFEARFUL FACEWEARY " +
"FACESLEEPY FACETIRED FACEGRIMACING FACELOUDLY CRYING FACEFACE WITH OPEN " +
"MOUTHHUSHED FACEFACE WITH OPEN MOUTH AND COLD SWEATFACE SCREAMING IN FEA" +
"RASTONISHED FACEFLUSHED FACESLEEPING FACEDIZZY FACEFACE WITHOUT MOUTHFAC" +
"E WITH MEDICAL MASKGRINNING CAT FACE WITH SMILING EYESCAT FACE WITH TEAR" +
"S OF JOYSMILING CAT FACE WITH OPEN MOUTHSMILING CAT FACE WITH HEART-SHAP" +
"ED EYESCAT FACE WITH WRY SMILEKISSING CAT FACE WITH CLOSED EYESPOUTING C" +
"AT FACECRYING CAT FACEWEARY CAT FACESLIGHTLY FROWNING FACESLIGHTLY SMILI" +
"NG FACEUPSIDE-DOWN FACEFACE WITH ROLLING EYESFACE WITH NO GOOD GESTUREFA" +
"CE WITH OK GESTUREPERSON BOWING DEEPLYSEE-NO-EVIL MONKEYHEAR-NO-EVIL MON" +
"KEYSPEAK-NO-EVIL MONKEYHAPPY PERSON RAISING ONE HANDPERSON RAISING BOTH " +
"HANDS IN CELEBRATIONPERSON FROWNINGPERSON WITH POUTING FACEPERSON WITH F" +
"OLDED HANDSNORTH WEST POINTING LEAFSOUTH WEST POINTING LEAFNORTH EAST PO" +
"INTING LEAFSOUTH EAST POINTING LEAFTURNED NORTH WEST POINTING LEAFTURNED" +
" SOUTH WEST POINTING LEAFTURNED NORTH EAST POINTING LEAFTURNED SOUTH EAS" +
"T POINTING LEAFNORTH WEST POINTING VINE LEAFSOUTH WEST POINTING VINE LEA" +
"FNORTH EAST POINTING VINE LEAFSOUTH EAST POINTING VINE LEAFHEAVY NORTH W" +
"EST POINTING VINE LEAFHEAVY SOUTH WEST POINTING VINE LEAFHEAVY NORTH EAS" +
"T POINTING VINE LEAFHEAVY SOUTH EAST POINTING VINE LEAFNORTH WEST POINTI" +
"NG BUDSOUTH WEST POINTING BUDNORTH EAST POINTING BUDSOUTH EAST POINTING " +
"BUDHEAVY NORTH WEST POINTING BUDHEAVY SOUTH WEST POINTING BUDHEAVY NORTH" +
" EAST POINTING BUDHEAVY SOUTH EAST POINTING BUDHOLLOW QUILT SQUARE ORNAM" +
"ENTHOLLOW QUILT SQUARE ORNAMENT IN BLACK SQUARESOLID QUILT SQUARE ORNAME" +
"NTSOLID QUILT SQUARE ORNAMENT IN BLACK SQUARELEFTWARDS ROCKETUPWARDS ROC" +
"KETRIGHTWARDS ROCKETDOWNWARDS ROCKETSCRIPT LIGATURE ET ORNAMENTHEAVY SCR" +
"IPT LIGATURE ET ORNAMENTLIGATURE OPEN ET ORNAMENTHEAVY LIGATURE OPEN ET " +
"ORNAMENTHEAVY AMPERSAND ORNAMENTSWASH AMPERSAND ORNAMENTSANS-SERIF HEAVY" +
" DOUBLE TURNED COMMA QUOTATION MARK ORNAMENTSANS-SERIF HEAVY DOUBLE COMM" +
"A QUOTATION MARK ORNAMENTSANS-SERIF HEAVY LOW DOUBLE COMMA QUOTATION MAR" +
"K ORNAMENTHEAVY INTERROBANG ORNAMENTSANS-SERIF INTERROBANG ORNAMENTHEAVY" +
" SANS-SERIF INTERROBANG ORNAMENTVERY HEAVY SOLIDUSVERY HEAVY REVERSE SOL" +
"IDUSCHECKER BOARDREVERSE CHECKER BOARDROCKETHELICOPTERSTEAM LOCOMOTIVERA" +
"ILWAY CARHIGH-SPEED TRAINHIGH-SPEED TRAIN WITH BULLET NOSETRAINMETROLIGH" +
"T RAILSTATIONTRAMTRAM CARBUSONCOMING BUSTROLLEYBUSBUS STOPMINIBUSAMBULAN" +
"CEFIRE ENGINEPOLICE CARONCOMING POLICE CARTAXIONCOMING TAXIAUTOMOBILEONC" +
"OMING AUTOMOBILERECREATIONAL VEHICLEDELIVERY TRUCKARTICULATED LORRYTRACT" +
"ORMONORAILMOUNTAIN RAILWAYSUSPENSION RAILWAYMOUNTAIN CABLEWAYAERIAL TRAM" +
"WAYSHIPROWBOATSPEEDBOATHORIZONTAL TRAFFIC LIGHTVERTICAL TRAFFIC LIGHTCON" +
"STRUCTION SIGNPOLICE CARS REVOLVING LIGHTTRIANGULAR FLAG ON POSTDOORNO E" +
"NTRY SIGNSMOKING SYMBOLNO SMOKING SYMBOLPUT LITTER IN ITS PLACE SYMBOLDO" +
" NOT LITTER SYMBOLPOTABLE WATER SYMBOLNON-POTABLE WATER SYMBOLBICYCLENO " +
"BICYCLESBICYCLISTMOUNTAIN BICYCLISTPEDESTRIANNO PEDESTRIANSCHILDREN CROS" +
"SINGMENS SYMBOLWOMENS SYMBOLRESTROOMBABY SYMBOLTOILETWATER CLOSETSHOWERB" +
"ATHBATHTUBPASSPORT CONTROLCUSTOMSBAGGAGE CLAIMLEFT LUGGAGETRIANGLE WITH " +
"ROUNDED CORNERSPROHIBITED SIGNCIRCLED INFORMATION SOURCEBOYS SYMBOLGIRLS" +
" SYMBOLCOUCH AND LAMPSLEEPING ACCOMMODATIONSHOPPING BAGSBELLHOP BELLBEDP" +
"LACE OF WORSHIPOCTAGONAL SIGNSHOPPING TROLLEYSTUPAPAGODAHINDU TEMPLEHUTE" +
"LEVATORLANDSLIDEWIRELESSPLAYGROUND SLIDEWHEELRING BUOYHAMMER AND WRENCHS" +
"HIELDOIL DRUMMOTORWAYRAILWAY TRACKMOTOR BOATUP-POINTING MILITARY AIRPLAN" +
"EUP-POINTING AIRPLANEUP-POINTING SMALL AIRPLANESMALL AIRPLANENORTHEAST-P" +
"OINTING AIRPLANEAIRPLANE DEPARTUREAIRPLANE ARRIVINGSATELLITEONCOMING FIR" +
"E ENGINEDIESEL LOCOMOTIVEPASSENGER SHIPSCOOTERMOTOR SCOOTERCANOESLEDFLYI" +
"NG SAUCERSKATEBOARDAUTO RICKSHAWPICKUP TRUCKROLLER SKATEALCHEMICAL SYMBO" +
"L FOR QUINTESSENCEALCHEMICAL SYMBOL FOR AIRALCHEMICAL SYMBOL FOR FIREALC" +
"HEMICAL SYMBOL FOR EARTHALCHEMICAL SYMBOL FOR WATERALCHEMICAL SYMBOL FOR" +
" AQUAFORTISALCHEMICAL SYMBOL FOR AQUA REGIAALCHEMICAL SYMBOL FOR AQUA RE" +
"GIA-2ALCHEMICAL SYMBOL FOR AQUA VITAEALCHEMICAL SYMBOL FOR AQUA VITAE-2A" +
"LCHEMICAL SYMBOL FOR VINEGARALCHEMICAL SYMBOL FOR VINEGAR-2ALCHEMICAL SY" +
"MBOL FOR VINEGAR-3ALCHEMICAL SYMBOL FOR SULFURALCHEMICAL SYMBOL FOR PHIL" +
"OSOPHERS SULFURALCHEMICAL SYMBOL FOR BLACK SULFURALCHEMICAL SYMBOL FOR M" +
"ERCURY SUBLIMATEALCHEMICAL SYMBOL FOR MERCURY SUBLIMATE-2ALCHEMICAL SYMB" +
"OL FOR MERCURY SUBLIMATE-3ALCHEMICAL SYMBOL FOR CINNABARALCHEMICAL SYMBO" +
"L FOR SALTALCHEMICAL SYMBOL FOR NITREALCHEMICAL SYMBOL FOR VITRIOLALCHEM") + ("" +
"ICAL SYMBOL FOR VITRIOL-2ALCHEMICAL SYMBOL FOR ROCK SALTALCHEMICAL SYMBO" +
"L FOR ROCK SALT-2ALCHEMICAL SYMBOL FOR GOLDALCHEMICAL SYMBOL FOR SILVERA" +
"LCHEMICAL SYMBOL FOR IRON OREALCHEMICAL SYMBOL FOR IRON ORE-2ALCHEMICAL " +
"SYMBOL FOR CROCUS OF IRONALCHEMICAL SYMBOL FOR REGULUS OF IRONALCHEMICAL" +
" SYMBOL FOR COPPER OREALCHEMICAL SYMBOL FOR IRON-COPPER OREALCHEMICAL SY" +
"MBOL FOR SUBLIMATE OF COPPERALCHEMICAL SYMBOL FOR CROCUS OF COPPERALCHEM" +
"ICAL SYMBOL FOR CROCUS OF COPPER-2ALCHEMICAL SYMBOL FOR COPPER ANTIMONIA" +
"TEALCHEMICAL SYMBOL FOR SALT OF COPPER ANTIMONIATEALCHEMICAL SYMBOL FOR " +
"SUBLIMATE OF SALT OF COPPERALCHEMICAL SYMBOL FOR VERDIGRISALCHEMICAL SYM" +
"BOL FOR TIN OREALCHEMICAL SYMBOL FOR LEAD OREALCHEMICAL SYMBOL FOR ANTIM" +
"ONY OREALCHEMICAL SYMBOL FOR SUBLIMATE OF ANTIMONYALCHEMICAL SYMBOL FOR " +
"SALT OF ANTIMONYALCHEMICAL SYMBOL FOR SUBLIMATE OF SALT OF ANTIMONYALCHE" +
"MICAL SYMBOL FOR VINEGAR OF ANTIMONYALCHEMICAL SYMBOL FOR REGULUS OF ANT" +
"IMONYALCHEMICAL SYMBOL FOR REGULUS OF ANTIMONY-2ALCHEMICAL SYMBOL FOR RE" +
"GULUSALCHEMICAL SYMBOL FOR REGULUS-2ALCHEMICAL SYMBOL FOR REGULUS-3ALCHE" +
"MICAL SYMBOL FOR REGULUS-4ALCHEMICAL SYMBOL FOR ALKALIALCHEMICAL SYMBOL " +
"FOR ALKALI-2ALCHEMICAL SYMBOL FOR MARCASITEALCHEMICAL SYMBOL FOR SAL-AMM" +
"ONIACALCHEMICAL SYMBOL FOR ARSENICALCHEMICAL SYMBOL FOR REALGARALCHEMICA" +
"L SYMBOL FOR REALGAR-2ALCHEMICAL SYMBOL FOR AURIPIGMENTALCHEMICAL SYMBOL" +
" FOR BISMUTH OREALCHEMICAL SYMBOL FOR TARTARALCHEMICAL SYMBOL FOR TARTAR" +
"-2ALCHEMICAL SYMBOL FOR QUICK LIMEALCHEMICAL SYMBOL FOR BORAXALCHEMICAL " +
"SYMBOL FOR BORAX-2ALCHEMICAL SYMBOL FOR BORAX-3ALCHEMICAL SYMBOL FOR ALU" +
"MALCHEMICAL SYMBOL FOR OILALCHEMICAL SYMBOL FOR SPIRITALCHEMICAL SYMBOL " +
"FOR TINCTUREALCHEMICAL SYMBOL FOR GUMALCHEMICAL SYMBOL FOR WAXALCHEMICAL" +
" SYMBOL FOR POWDERALCHEMICAL SYMBOL FOR CALXALCHEMICAL SYMBOL FOR TUTTYA" +
"LCHEMICAL SYMBOL FOR CAPUT MORTUUMALCHEMICAL SYMBOL FOR SCEPTER OF JOVEA" +
"LCHEMICAL SYMBOL FOR CADUCEUSALCHEMICAL SYMBOL FOR TRIDENTALCHEMICAL SYM" +
"BOL FOR STARRED TRIDENTALCHEMICAL SYMBOL FOR LODESTONEALCHEMICAL SYMBOL " +
"FOR SOAPALCHEMICAL SYMBOL FOR URINEALCHEMICAL SYMBOL FOR HORSE DUNGALCHE" +
"MICAL SYMBOL FOR ASHESALCHEMICAL SYMBOL FOR POT ASHESALCHEMICAL SYMBOL F" +
"OR BRICKALCHEMICAL SYMBOL FOR POWDERED BRICKALCHEMICAL SYMBOL FOR AMALGA" +
"MALCHEMICAL SYMBOL FOR STRATUM SUPER STRATUMALCHEMICAL SYMBOL FOR STRATU" +
"M SUPER STRATUM-2ALCHEMICAL SYMBOL FOR SUBLIMATIONALCHEMICAL SYMBOL FOR " +
"PRECIPITATEALCHEMICAL SYMBOL FOR DISTILLALCHEMICAL SYMBOL FOR DISSOLVEAL" +
"CHEMICAL SYMBOL FOR DISSOLVE-2ALCHEMICAL SYMBOL FOR PURIFYALCHEMICAL SYM" +
"BOL FOR PUTREFACTIONALCHEMICAL SYMBOL FOR CRUCIBLEALCHEMICAL SYMBOL FOR " +
"CRUCIBLE-2ALCHEMICAL SYMBOL FOR CRUCIBLE-3ALCHEMICAL SYMBOL FOR CRUCIBLE" +
"-4ALCHEMICAL SYMBOL FOR CRUCIBLE-5ALCHEMICAL SYMBOL FOR ALEMBICALCHEMICA" +
"L SYMBOL FOR BATH OF MARYALCHEMICAL SYMBOL FOR BATH OF VAPOURSALCHEMICAL" +
" SYMBOL FOR RETORTALCHEMICAL SYMBOL FOR HOURALCHEMICAL SYMBOL FOR NIGHTA" +
"LCHEMICAL SYMBOL FOR DAY-NIGHTALCHEMICAL SYMBOL FOR MONTHALCHEMICAL SYMB" +
"OL FOR HALF DRAMALCHEMICAL SYMBOL FOR HALF OUNCELOT OF FORTUNEOCCULTATIO" +
"NLUNAR ECLIPSEVESTA FORM TWOASTRAEA FORM TWOHYGIEA FORM TWOPARTHENOPE FO" +
"RM TWOHAUMEAMAKEMAKEGONGGONGQUAOARORCUSBLACK LEFT-POINTING ISOSCELES RIG" +
"HT TRIANGLEBLACK UP-POINTING ISOSCELES RIGHT TRIANGLEBLACK RIGHT-POINTIN" +
"G ISOSCELES RIGHT TRIANGLEBLACK DOWN-POINTING ISOSCELES RIGHT TRIANGLEBL" +
"ACK SLIGHTLY SMALL CIRCLEMEDIUM BOLD WHITE CIRCLEBOLD WHITE CIRCLEHEAVY " +
"WHITE CIRCLEVERY HEAVY WHITE CIRCLEEXTREMELY HEAVY WHITE CIRCLEWHITE CIR" +
"CLE CONTAINING BLACK SMALL CIRCLEROUND TARGETBLACK TINY SQUAREBLACK SLIG" +
"HTLY SMALL SQUARELIGHT WHITE SQUAREMEDIUM WHITE SQUAREBOLD WHITE SQUAREH" +
"EAVY WHITE SQUAREVERY HEAVY WHITE SQUAREEXTREMELY HEAVY WHITE SQUAREWHIT" +
"E SQUARE CONTAINING BLACK VERY SMALL SQUAREWHITE SQUARE CONTAINING BLACK" +
" MEDIUM SQUARESQUARE TARGETBLACK TINY DIAMONDBLACK VERY SMALL DIAMONDBLA" +
"CK MEDIUM SMALL DIAMONDWHITE DIAMOND CONTAINING BLACK VERY SMALL DIAMOND" +
"WHITE DIAMOND CONTAINING BLACK MEDIUM DIAMONDDIAMOND TARGETBLACK TINY LO" +
"ZENGEBLACK VERY SMALL LOZENGEBLACK MEDIUM SMALL LOZENGEWHITE LOZENGE CON" +
"TAINING BLACK SMALL LOZENGETHIN GREEK CROSSLIGHT GREEK CROSSMEDIUM GREEK" +
" CROSSBOLD GREEK CROSSVERY BOLD GREEK CROSSVERY HEAVY GREEK CROSSEXTREME" +
"LY HEAVY GREEK CROSSTHIN SALTIRELIGHT SALTIREMEDIUM SALTIREBOLD SALTIREH" +
"EAVY SALTIREVERY HEAVY SALTIREEXTREMELY HEAVY SALTIRELIGHT FIVE SPOKED A" +
"STERISKMEDIUM FIVE SPOKED ASTERISKBOLD FIVE SPOKED ASTERISKHEAVY FIVE SP" +
"OKED ASTERISKVERY HEAVY FIVE SPOKED ASTERISKEXTREMELY HEAVY FIVE SPOKED " +
"ASTERISKLIGHT SIX SPOKED ASTERISKMEDIUM SIX SPOKED ASTERISKBOLD SIX SPOK" +
"ED ASTERISKHEAVY SIX SPOKED ASTERISKVERY HEAVY SIX SPOKED ASTERISKEXTREM") + ("" +
"ELY HEAVY SIX SPOKED ASTERISKLIGHT EIGHT SPOKED ASTERISKMEDIUM EIGHT SPO" +
"KED ASTERISKBOLD EIGHT SPOKED ASTERISKHEAVY EIGHT SPOKED ASTERISKVERY HE" +
"AVY EIGHT SPOKED ASTERISKLIGHT THREE POINTED BLACK STARMEDIUM THREE POIN" +
"TED BLACK STARTHREE POINTED BLACK STARMEDIUM THREE POINTED PINWHEEL STAR" +
"LIGHT FOUR POINTED BLACK STARMEDIUM FOUR POINTED BLACK STARFOUR POINTED " +
"BLACK STARMEDIUM FOUR POINTED PINWHEEL STARREVERSE LIGHT FOUR POINTED PI" +
"NWHEEL STARLIGHT FIVE POINTED BLACK STARHEAVY FIVE POINTED BLACK STARMED" +
"IUM SIX POINTED BLACK STARHEAVY SIX POINTED BLACK STARSIX POINTED PINWHE" +
"EL STARMEDIUM EIGHT POINTED BLACK STARHEAVY EIGHT POINTED BLACK STARVERY" +
" HEAVY EIGHT POINTED BLACK STARHEAVY EIGHT POINTED PINWHEEL STARLIGHT TW" +
"ELVE POINTED BLACK STARHEAVY TWELVE POINTED BLACK STARHEAVY TWELVE POINT" +
"ED PINWHEEL STARCIRCLED TRIANGLENEGATIVE CIRCLED TRIANGLECIRCLED SQUAREN" +
"EGATIVE CIRCLED SQUARENINE POINTED WHITE STARLARGE ORANGE CIRCLELARGE YE" +
"LLOW CIRCLELARGE GREEN CIRCLELARGE PURPLE CIRCLELARGE BROWN CIRCLELARGE " +
"RED SQUARELARGE BLUE SQUARELARGE ORANGE SQUARELARGE YELLOW SQUARELARGE G" +
"REEN SQUARELARGE PURPLE SQUARELARGE BROWN SQUAREHEAVY EQUALS SIGNLEFTWAR" +
"DS ARROW WITH SMALL TRIANGLE ARROWHEADUPWARDS ARROW WITH SMALL TRIANGLE " +
"ARROWHEADRIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEADDOWNWARDS ARROW W" +
"ITH SMALL TRIANGLE ARROWHEADLEFTWARDS ARROW WITH MEDIUM TRIANGLE ARROWHE" +
"ADUPWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEADRIGHTWARDS ARROW WITH MEDI" +
"UM TRIANGLE ARROWHEADDOWNWARDS ARROW WITH MEDIUM TRIANGLE ARROWHEADLEFTW" +
"ARDS ARROW WITH LARGE TRIANGLE ARROWHEADUPWARDS ARROW WITH LARGE TRIANGL" +
"E ARROWHEADRIGHTWARDS ARROW WITH LARGE TRIANGLE ARROWHEADDOWNWARDS ARROW" +
" WITH LARGE TRIANGLE ARROWHEADLEFTWARDS ARROW WITH SMALL EQUILATERAL ARR" +
"OWHEADUPWARDS ARROW WITH SMALL EQUILATERAL ARROWHEADRIGHTWARDS ARROW WIT" +
"H SMALL EQUILATERAL ARROWHEADDOWNWARDS ARROW WITH SMALL EQUILATERAL ARRO" +
"WHEADLEFTWARDS ARROW WITH EQUILATERAL ARROWHEADUPWARDS ARROW WITH EQUILA" +
"TERAL ARROWHEADRIGHTWARDS ARROW WITH EQUILATERAL ARROWHEADDOWNWARDS ARRO" +
"W WITH EQUILATERAL ARROWHEADHEAVY LEFTWARDS ARROW WITH EQUILATERAL ARROW" +
"HEADHEAVY UPWARDS ARROW WITH EQUILATERAL ARROWHEADHEAVY RIGHTWARDS ARROW" +
" WITH EQUILATERAL ARROWHEADHEAVY DOWNWARDS ARROW WITH EQUILATERAL ARROWH" +
"EADHEAVY LEFTWARDS ARROW WITH LARGE EQUILATERAL ARROWHEADHEAVY UPWARDS A" +
"RROW WITH LARGE EQUILATERAL ARROWHEADHEAVY RIGHTWARDS ARROW WITH LARGE E" +
"QUILATERAL ARROWHEADHEAVY DOWNWARDS ARROW WITH LARGE EQUILATERAL ARROWHE" +
"ADLEFTWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFTUPWARDS TRIANGLE-HEAD" +
"ED ARROW WITH NARROW SHAFTRIGHTWARDS TRIANGLE-HEADED ARROW WITH NARROW S" +
"HAFTDOWNWARDS TRIANGLE-HEADED ARROW WITH NARROW SHAFTLEFTWARDS TRIANGLE-" +
"HEADED ARROW WITH MEDIUM SHAFTUPWARDS TRIANGLE-HEADED ARROW WITH MEDIUM " +
"SHAFTRIGHTWARDS TRIANGLE-HEADED ARROW WITH MEDIUM SHAFTDOWNWARDS TRIANGL" +
"E-HEADED ARROW WITH MEDIUM SHAFTLEFTWARDS TRIANGLE-HEADED ARROW WITH BOL" +
"D SHAFTUPWARDS TRIANGLE-HEADED ARROW WITH BOLD SHAFTRIGHTWARDS TRIANGLE-" +
"HEADED ARROW WITH BOLD SHAFTDOWNWARDS TRIANGLE-HEADED ARROW WITH BOLD SH" +
"AFTLEFTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFTUPWARDS TRIANGLE-HEAD" +
"ED ARROW WITH HEAVY SHAFTRIGHTWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHA" +
"FTDOWNWARDS TRIANGLE-HEADED ARROW WITH HEAVY SHAFTLEFTWARDS TRIANGLE-HEA" +
"DED ARROW WITH VERY HEAVY SHAFTUPWARDS TRIANGLE-HEADED ARROW WITH VERY H" +
"EAVY SHAFTRIGHTWARDS TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFTDOWNWARD" +
"S TRIANGLE-HEADED ARROW WITH VERY HEAVY SHAFTLEFTWARDS FINGER-POST ARROW" +
"UPWARDS FINGER-POST ARROWRIGHTWARDS FINGER-POST ARROWDOWNWARDS FINGER-PO" +
"ST ARROWLEFTWARDS SQUARED ARROWUPWARDS SQUARED ARROWRIGHTWARDS SQUARED A" +
"RROWDOWNWARDS SQUARED ARROWLEFTWARDS COMPRESSED ARROWUPWARDS COMPRESSED " +
"ARROWRIGHTWARDS COMPRESSED ARROWDOWNWARDS COMPRESSED ARROWLEFTWARDS HEAV" +
"Y COMPRESSED ARROWUPWARDS HEAVY COMPRESSED ARROWRIGHTWARDS HEAVY COMPRES" +
"SED ARROWDOWNWARDS HEAVY COMPRESSED ARROWLEFTWARDS HEAVY ARROWUPWARDS HE" +
"AVY ARROWRIGHTWARDS HEAVY ARROWDOWNWARDS HEAVY ARROWLEFTWARDS SANS-SERIF" +
" ARROWUPWARDS SANS-SERIF ARROWRIGHTWARDS SANS-SERIF ARROWDOWNWARDS SANS-" +
"SERIF ARROWNORTH WEST SANS-SERIF ARROWNORTH EAST SANS-SERIF ARROWSOUTH E" +
"AST SANS-SERIF ARROWSOUTH WEST SANS-SERIF ARROWLEFT RIGHT SANS-SERIF ARR" +
"OWUP DOWN SANS-SERIF ARROWWIDE-HEADED LEFTWARDS LIGHT BARB ARROWWIDE-HEA" +
"DED UPWARDS LIGHT BARB ARROWWIDE-HEADED RIGHTWARDS LIGHT BARB ARROWWIDE-" +
"HEADED DOWNWARDS LIGHT BARB ARROWWIDE-HEADED NORTH WEST LIGHT BARB ARROW" +
"WIDE-HEADED NORTH EAST LIGHT BARB ARROWWIDE-HEADED SOUTH EAST LIGHT BARB" +
" ARROWWIDE-HEADED SOUTH WEST LIGHT BARB ARROWWIDE-HEADED LEFTWARDS BARB " +
"ARROWWIDE-HEADED UPWARDS BARB ARROWWIDE-HEADED RIGHTWARDS BARB ARROWWIDE") + ("" +
"-HEADED DOWNWARDS BARB ARROWWIDE-HEADED NORTH WEST BARB ARROWWIDE-HEADED" +
" NORTH EAST BARB ARROWWIDE-HEADED SOUTH EAST BARB ARROWWIDE-HEADED SOUTH" +
" WEST BARB ARROWWIDE-HEADED LEFTWARDS MEDIUM BARB ARROWWIDE-HEADED UPWAR" +
"DS MEDIUM BARB ARROWWIDE-HEADED RIGHTWARDS MEDIUM BARB ARROWWIDE-HEADED " +
"DOWNWARDS MEDIUM BARB ARROWWIDE-HEADED NORTH WEST MEDIUM BARB ARROWWIDE-" +
"HEADED NORTH EAST MEDIUM BARB ARROWWIDE-HEADED SOUTH EAST MEDIUM BARB AR" +
"ROWWIDE-HEADED SOUTH WEST MEDIUM BARB ARROWWIDE-HEADED LEFTWARDS HEAVY B" +
"ARB ARROWWIDE-HEADED UPWARDS HEAVY BARB ARROWWIDE-HEADED RIGHTWARDS HEAV" +
"Y BARB ARROWWIDE-HEADED DOWNWARDS HEAVY BARB ARROWWIDE-HEADED NORTH WEST" +
" HEAVY BARB ARROWWIDE-HEADED NORTH EAST HEAVY BARB ARROWWIDE-HEADED SOUT" +
"H EAST HEAVY BARB ARROWWIDE-HEADED SOUTH WEST HEAVY BARB ARROWWIDE-HEADE" +
"D LEFTWARDS VERY HEAVY BARB ARROWWIDE-HEADED UPWARDS VERY HEAVY BARB ARR" +
"OWWIDE-HEADED RIGHTWARDS VERY HEAVY BARB ARROWWIDE-HEADED DOWNWARDS VERY" +
" HEAVY BARB ARROWWIDE-HEADED NORTH WEST VERY HEAVY BARB ARROWWIDE-HEADED" +
" NORTH EAST VERY HEAVY BARB ARROWWIDE-HEADED SOUTH EAST VERY HEAVY BARB " +
"ARROWWIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROWLEFTWARDS TRIANGLE ARRO" +
"WHEADUPWARDS TRIANGLE ARROWHEADRIGHTWARDS TRIANGLE ARROWHEADDOWNWARDS TR" +
"IANGLE ARROWHEADLEFTWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEADUPWARDS W" +
"HITE ARROW WITHIN TRIANGLE ARROWHEADRIGHTWARDS WHITE ARROW WITHIN TRIANG" +
"LE ARROWHEADDOWNWARDS WHITE ARROW WITHIN TRIANGLE ARROWHEADLEFTWARDS ARR" +
"OW WITH NOTCHED TAILUPWARDS ARROW WITH NOTCHED TAILRIGHTWARDS ARROW WITH" +
" NOTCHED TAILDOWNWARDS ARROW WITH NOTCHED TAILHEAVY ARROW SHAFT WIDTH ON" +
"EHEAVY ARROW SHAFT WIDTH TWO THIRDSHEAVY ARROW SHAFT WIDTH ONE HALFHEAVY" +
" ARROW SHAFT WIDTH ONE THIRDLEFTWARDS BOTTOM-SHADED WHITE ARROWRIGHTWARD" +
"S BOTTOM SHADED WHITE ARROWLEFTWARDS TOP SHADED WHITE ARROWRIGHTWARDS TO" +
"P SHADED WHITE ARROWLEFTWARDS LEFT-SHADED WHITE ARROWRIGHTWARDS RIGHT-SH" +
"ADED WHITE ARROWLEFTWARDS RIGHT-SHADED WHITE ARROWRIGHTWARDS LEFT-SHADED" +
" WHITE ARROWLEFTWARDS BACK-TILTED SHADOWED WHITE ARROWRIGHTWARDS BACK-TI" +
"LTED SHADOWED WHITE ARROWLEFTWARDS FRONT-TILTED SHADOWED WHITE ARROWRIGH" +
"TWARDS FRONT-TILTED SHADOWED WHITE ARROWWHITE ARROW SHAFT WIDTH ONEWHITE" +
" ARROW SHAFT WIDTH TWO THIRDSARROW POINTING UPWARDS THEN NORTH WESTARROW" +
" POINTING RIGHTWARDS THEN CURVING SOUTH WESTRIGHTWARDS ARROW WITH LOWER " +
"HOOKDOWNWARDS BLACK ARROW TO BARNEGATIVE SQUARED LEFTWARDS ARROWNEGATIVE" +
" SQUARED UPWARDS ARROWNEGATIVE SQUARED RIGHTWARDS ARROWNEGATIVE SQUARED " +
"DOWNWARDS ARROWNORTH WEST ARROW FROM BARNORTH EAST ARROW FROM BARSOUTH E" +
"AST ARROW FROM BARSOUTH WEST ARROW FROM BARLEFTWARDS ARROW FROM DOWNWARD" +
"S ARROWRIGHTWARDS ARROW FROM DOWNWARDS ARROWLONG RIGHTWARDS ARROW OVER L" +
"ONG LEFTWARDS ARROWLONG RIGHTWARDS HARPOON OVER LONG LEFTWARDS HARPOONLO" +
"NG RIGHTWARDS HARPOON ABOVE SHORT LEFTWARDS HARPOONSHORT RIGHTWARDS HARP" +
"OON ABOVE LONG LEFTWARDS HARPOONLONG LEFTWARDS HARPOON ABOVE SHORT RIGHT" +
"WARDS HARPOONSHORT LEFTWARDS HARPOON ABOVE LONG RIGHTWARDS HARPOONLONG R" +
"IGHTWARDS ARROW THROUGH XLONG RIGHTWARDS ARROW WITH DOUBLE SLASHLONG LEF" +
"T RIGHT ARROW WITH DEPENDENT LOBECIRCLED CROSS FORMEE WITH FOUR DOTSCIRC" +
"LED CROSS FORMEE WITH TWO DOTSCIRCLED CROSS FORMEELEFT HALF CIRCLE WITH " +
"FOUR DOTSLEFT HALF CIRCLE WITH THREE DOTSLEFT HALF CIRCLE WITH TWO DOTSL" +
"EFT HALF CIRCLE WITH DOTLEFT HALF CIRCLEDOWNWARD FACING HOOKDOWNWARD FAC" +
"ING NOTCHED HOOKDOWNWARD FACING HOOK WITH DOTDOWNWARD FACING NOTCHED HOO" +
"K WITH DOTPINCHED FINGERSWHITE HEARTBROWN HEARTPINCHING HANDZIPPER-MOUTH" +
" FACEMONEY-MOUTH FACEFACE WITH THERMOMETERNERD FACETHINKING FACEFACE WIT" +
"H HEAD-BANDAGEROBOT FACEHUGGING FACESIGN OF THE HORNSCALL ME HANDRAISED " +
"BACK OF HANDLEFT-FACING FISTRIGHT-FACING FISTHANDSHAKEHAND WITH INDEX AN" +
"D MIDDLE FINGERS CROSSEDI LOVE YOU HAND SIGNFACE WITH COWBOY HATCLOWN FA" +
"CENAUSEATED FACEROLLING ON THE FLOOR LAUGHINGDROOLING FACELYING FACEFACE" +
" PALMSNEEZING FACEFACE WITH ONE EYEBROW RAISEDGRINNING FACE WITH STAR EY" +
"ESGRINNING FACE WITH ONE LARGE AND ONE SMALL EYEFACE WITH FINGER COVERIN" +
"G CLOSED LIPSSERIOUS FACE WITH SYMBOLS COVERING MOUTHSMILING FACE WITH S" +
"MILING EYES AND HAND COVERING MOUTHFACE WITH OPEN MOUTH VOMITINGSHOCKED " +
"FACE WITH EXPLODING HEADPREGNANT WOMANBREAST-FEEDINGPALMS UP TOGETHERSEL" +
"FIEPRINCEMAN IN TUXEDOMOTHER CHRISTMASSHRUGPERSON DOING CARTWHEELJUGGLIN" +
"GFENCERMODERN PENTATHLONWRESTLERSWATER POLOHANDBALLDIVING MASKWILTED FLO" +
"WERDRUM WITH DRUMSTICKSCLINKING GLASSESTUMBLER GLASSSPOONGOAL NETRIFLEFI" +
"RST PLACE MEDALSECOND PLACE MEDALTHIRD PLACE MEDALBOXING GLOVEMARTIAL AR" +
"TS UNIFORMCURLING STONELACROSSE STICK AND BALLSOFTBALLFLYING DISCCROISSA" +
"NTAVOCADOCUCUMBERBACONPOTATOCARROTBAGUETTE BREADGREEN SALADSHALLOW PAN O") + ("" +
"F FOODSTUFFED FLATBREADEGGGLASS OF MILKPEANUTSKIWIFRUITPANCAKESDUMPLINGF" +
"ORTUNE COOKIETAKEOUT BOXCHOPSTICKSBOWL WITH SPOONCUP WITH STRAWCOCONUTBR" +
"OCCOLIPIEPRETZELCUT OF MEATSANDWICHCANNED FOODLEAFY GREENMANGOMOON CAKEB" +
"AGELSMILING FACE WITH SMILING EYES AND THREE HEARTSYAWNING FACESMILING F" +
"ACE WITH TEARFACE WITH PARTY HORN AND PARTY HATFACE WITH UNEVEN EYES AND" +
" WAVY MOUTHOVERHEATED FACEFREEZING FACENINJADISGUISED FACEFACE HOLDING B" +
"ACK TEARSFACE WITH PLEADING EYESSARILAB COATGOGGLESHIKING BOOTFLAT SHOEC" +
"RABLION FACESCORPIONTURKEYUNICORN FACEEAGLEDUCKBATSHARKOWLFOX FACEBUTTER" +
"FLYDEERGORILLALIZARDRHINOCEROSSHRIMPSQUIDGIRAFFE FACEZEBRA FACEHEDGEHOGS" +
"AUROPODT-REXCRICKETKANGAROOLLAMAPEACOCKHIPPOPOTAMUSPARROTRACCOONLOBSTERM" +
"OSQUITOMICROBEBADGERSWANMAMMOTHDODOSLOTHOTTERORANGUTANSKUNKFLAMINGOOYSTE" +
"RBEAVERBISONSEALGUIDE DOGPROBING CANEEMOJI COMPONENT RED HAIREMOJI COMPO" +
"NENT CURLY HAIREMOJI COMPONENT BALDEMOJI COMPONENT WHITE HAIRBONELEGFOOT" +
"TOOTHSUPERHEROSUPERVILLAINSAFETY VESTEAR WITH HEARING AIDMOTORIZED WHEEL" +
"CHAIRMANUAL WHEELCHAIRMECHANICAL ARMMECHANICAL LEGCHEESE WEDGECUPCAKESAL" +
"T SHAKERBEVERAGE BOXGARLICONIONFALAFELWAFFLEBUTTERMATE DRINKICE CUBEBUBB" +
"LE TEATROLLSTANDING PERSONKNEELING PERSONDEAF PERSONFACE WITH MONOCLEADU" +
"LTCHILDOLDER ADULTBEARDED PERSONPERSON WITH HEADSCARFPERSON IN STEAMY RO" +
"OMPERSON CLIMBINGPERSON IN LOTUS POSITIONMAGEFAIRYVAMPIREMERPERSONELFGEN" +
"IEZOMBIEBRAINORANGE HEARTBILLED CAPSCARFGLOVESCOATSOCKSRED GIFT ENVELOPE" +
"FIRECRACKERJIGSAW PUZZLE PIECETEST TUBEPETRI DISHDNA DOUBLE HELIXCOMPASS" +
"ABACUSFIRE EXTINGUISHERTOOLBOXBRICKMAGNETLUGGAGELOTION BOTTLESPOOL OF TH" +
"READBALL OF YARNSAFETY PINTEDDY BEARBROOMBASKETROLL OF PAPERBAR OF SOAPS" +
"PONGERECEIPTNAZAR AMULETNEUTRAL CHESS KINGNEUTRAL CHESS QUEENNEUTRAL CHE" +
"SS ROOKNEUTRAL CHESS BISHOPNEUTRAL CHESS KNIGHTNEUTRAL CHESS PAWNWHITE C" +
"HESS KNIGHT ROTATED FORTY-FIVE DEGREESBLACK CHESS KNIGHT ROTATED FORTY-F" +
"IVE DEGREESNEUTRAL CHESS KNIGHT ROTATED FORTY-FIVE DEGREESWHITE CHESS KI" +
"NG ROTATED NINETY DEGREESWHITE CHESS QUEEN ROTATED NINETY DEGREESWHITE C" +
"HESS ROOK ROTATED NINETY DEGREESWHITE CHESS BISHOP ROTATED NINETY DEGREE" +
"SWHITE CHESS KNIGHT ROTATED NINETY DEGREESWHITE CHESS PAWN ROTATED NINET" +
"Y DEGREESBLACK CHESS KING ROTATED NINETY DEGREESBLACK CHESS QUEEN ROTATE" +
"D NINETY DEGREESBLACK CHESS ROOK ROTATED NINETY DEGREESBLACK CHESS BISHO" +
"P ROTATED NINETY DEGREESBLACK CHESS KNIGHT ROTATED NINETY DEGREESBLACK C" +
"HESS PAWN ROTATED NINETY DEGREESNEUTRAL CHESS KING ROTATED NINETY DEGREE" +
"SNEUTRAL CHESS QUEEN ROTATED NINETY DEGREESNEUTRAL CHESS ROOK ROTATED NI" +
"NETY DEGREESNEUTRAL CHESS BISHOP ROTATED NINETY DEGREESNEUTRAL CHESS KNI" +
"GHT ROTATED NINETY DEGREESNEUTRAL 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 DEGREESWHITE CHESS TURNED KINGWHITE CHESS TURNED QUE" +
"ENWHITE CHESS TURNED ROOKWHITE CHESS TURNED BISHOPWHITE CHESS TURNED KNI" +
"GHTWHITE CHESS TURNED PAWNBLACK CHESS TURNED KINGBLACK CHESS TURNED QUEE" +
"NBLACK CHESS TURNED ROOKBLACK CHESS TURNED BISHOPBLACK CHESS TURNED KNIG" +
"HTBLACK CHESS TURNED PAWNNEUTRAL CHESS TURNED KINGNEUTRAL CHESS TURNED Q" +
"UEENNEUTRAL CHESS TURNED ROOKNEUTRAL CHESS TURNED BISHOPNEUTRAL CHESS TU" +
"RNED KNIGHTNEUTRAL CHESS TURNED PAWNWHITE CHESS KNIGHT ROTATED TWO HUNDR" +
"ED TWENTY-FIVE DEGREESBLACK CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE" +
" DEGREESNEUTRAL CHESS KNIGHT ROTATED TWO HUNDRED TWENTY-FIVE DEGREESWHIT" +
"E CHESS KING ROTATED TWO HUNDRED SEVENTY DEGREESWHITE CHESS QUEEN ROTATE" +
"D TWO HUNDRED SEVENTY DEGREESWHITE CHESS ROOK ROTATED TWO HUNDRED SEVENT" +
"Y DEGREESWHITE CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREESWHITE CHE" +
"SS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGREESWHITE CHESS PAWN ROTATED TW" +
"O HUNDRED SEVENTY DEGREESBLACK CHESS KING ROTATED TWO HUNDRED SEVENTY DE" +
"GREESBLACK CHESS QUEEN ROTATED TWO HUNDRED SEVENTY DEGREESBLACK CHESS RO" +
"OK ROTATED TWO HUNDRED SEVENTY DEGREESBLACK CHESS BISHOP ROTATED TWO HUN" +
"DRED SEVENTY DEGREESBLACK CHESS KNIGHT ROTATED TWO HUNDRED SEVENTY DEGRE" +
"ESBLACK CHESS PAWN ROTATED TWO HUNDRED SEVENTY DEGREESNEUTRAL CHESS KING" +
" ROTATED TWO HUNDRED SEVENTY DEGREESNEUTRAL CHESS QUEEN ROTATED TWO HUND" +
"RED SEVENTY DEGREESNEUTRAL CHESS ROOK ROTATED TWO HUNDRED SEVENTY DEGREE" +
"SNEUTRAL CHESS BISHOP ROTATED TWO HUNDRED SEVENTY DEGREESNEUTRAL CHESS K" +
"NIGHT ROTATED TWO HUNDRED SEVENTY DEGREESNEUTRAL CHESS PAWN ROTATED TWO " +
"HUNDRED SEVENTY DEGREESWHITE CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN " +
"DEGREESBLACK CHESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREESNEUTRAL C" +
"HESS KNIGHT ROTATED THREE HUNDRED FIFTEEN DEGREESWHITE CHESS EQUIHOPPERB") + ("" +
"LACK CHESS EQUIHOPPERNEUTRAL CHESS EQUIHOPPERWHITE CHESS EQUIHOPPER ROTA" +
"TED NINETY DEGREESBLACK CHESS EQUIHOPPER ROTATED NINETY DEGREESNEUTRAL C" +
"HESS EQUIHOPPER ROTATED NINETY DEGREESWHITE CHESS KNIGHT-QUEENWHITE CHES" +
"S KNIGHT-ROOKWHITE CHESS KNIGHT-BISHOPBLACK CHESS KNIGHT-QUEENBLACK CHES" +
"S KNIGHT-ROOKBLACK CHESS KNIGHT-BISHOPWHITE CHESS FERZWHITE CHESS ALFILB" +
"LACK CHESS FERZBLACK CHESS ALFILXIANGQI RED GENERALXIANGQI RED MANDARINX" +
"IANGQI RED ELEPHANTXIANGQI RED HORSEXIANGQI RED CHARIOTXIANGQI RED CANNO" +
"NXIANGQI RED SOLDIERXIANGQI BLACK GENERALXIANGQI BLACK MANDARINXIANGQI B" +
"LACK ELEPHANTXIANGQI BLACK HORSEXIANGQI BLACK CHARIOTXIANGQI BLACK CANNO" +
"NXIANGQI BLACK SOLDIERBALLET SHOESONE-PIECE SWIMSUITBRIEFSSHORTSTHONG SA" +
"NDALLIGHT BLUE HEARTGREY HEARTPINK HEARTDROP OF BLOODADHESIVE BANDAGESTE" +
"THOSCOPEX-RAYCRUTCHYO-YOKITEPARACHUTEBOOMERANGMAGIC WANDPINATANESTING DO" +
"LLSMARACASFLUTEHARPTROMBONETREASURE CHESTSHOVELRINGED PLANETCHAIRRAZORAX" +
"EDIYA LAMPBANJOMILITARY HELMETACCORDIONLONG DRUMCOINCARPENTRY SAWSCREWDR" +
"IVERLADDERHOOKMIRRORWINDOWPLUNGERSEWING NEEDLEKNOTBUCKETMOUSE TRAPTOOTHB" +
"RUSHHEADSTONEPLACARDROCKMIRROR BALLIDENTIFICATION CARDLOW BATTERYHAMSAFO" +
"LDING HAND FANHAIR PICKKHANDAFLYWORMBEETLECOCKROACHPOTTED PLANTWOODFEATH" +
"ERLOTUSCORALEMPTY NESTNEST WITH EGGSHYACINTHJELLYFISHWINGLEAFLESS TREEGO" +
"OSEANATOMICAL HEARTLUNGSPEOPLE HUGGINGPREGNANT MANPREGNANT PERSONPERSON " +
"WITH CROWNFINGERPRINTHAIRY CREATUREORCAMOOSEDONKEYBLUEBERRIESBELL PEPPER" +
"OLIVEFLATBREADTAMALEFONDUETEAPOTPOURING LIQUIDBEANSJARGINGER ROOTPEA POD" +
"ROOT VEGETABLESPLATTERMELTING FACESALUTING FACEFACE WITH OPEN EYES AND H" +
"AND OVER MOUTHFACE WITH PEEKING EYEFACE WITH DIAGONAL MOUTHDOTTED LINE F" +
"ACEBITING LIPBUBBLESSHAKING FACEFACE WITH BAGS UNDER EYESDISTORTED FACEF" +
"IGHT CLOUDHAND WITH INDEX FINGER AND THUMB CROSSEDRIGHTWARDS HANDLEFTWAR" +
"DS HANDPALM DOWN HANDPALM UP HANDINDEX POINTING AT THE VIEWERHEART HANDS" +
"LEFTWARDS PUSHING HANDRIGHTWARDS PUSHING HANDBLOCK SEXTANT-1BLOCK SEXTAN" +
"T-2BLOCK SEXTANT-12BLOCK SEXTANT-3BLOCK SEXTANT-13BLOCK SEXTANT-23BLOCK " +
"SEXTANT-123BLOCK SEXTANT-4BLOCK SEXTANT-14BLOCK SEXTANT-24BLOCK SEXTANT-" +
"124BLOCK SEXTANT-34BLOCK SEXTANT-134BLOCK SEXTANT-234BLOCK SEXTANT-1234B" +
"LOCK SEXTANT-5BLOCK SEXTANT-15BLOCK SEXTANT-25BLOCK SEXTANT-125BLOCK SEX" +
"TANT-35BLOCK SEXTANT-235BLOCK SEXTANT-1235BLOCK SEXTANT-45BLOCK SEXTANT-" +
"145BLOCK SEXTANT-245BLOCK SEXTANT-1245BLOCK SEXTANT-345BLOCK SEXTANT-134" +
"5BLOCK SEXTANT-2345BLOCK SEXTANT-12345BLOCK SEXTANT-6BLOCK SEXTANT-16BLO" +
"CK SEXTANT-26BLOCK SEXTANT-126BLOCK SEXTANT-36BLOCK SEXTANT-136BLOCK SEX" +
"TANT-236BLOCK SEXTANT-1236BLOCK SEXTANT-46BLOCK SEXTANT-146BLOCK SEXTANT" +
"-1246BLOCK SEXTANT-346BLOCK SEXTANT-1346BLOCK SEXTANT-2346BLOCK SEXTANT-" +
"12346BLOCK SEXTANT-56BLOCK SEXTANT-156BLOCK SEXTANT-256BLOCK SEXTANT-125" +
"6BLOCK SEXTANT-356BLOCK SEXTANT-1356BLOCK SEXTANT-2356BLOCK SEXTANT-1235" +
"6BLOCK SEXTANT-456BLOCK SEXTANT-1456BLOCK SEXTANT-2456BLOCK SEXTANT-1245" +
"6BLOCK SEXTANT-3456BLOCK SEXTANT-13456BLOCK SEXTANT-23456LOWER LEFT BLOC" +
"K DIAGONAL LOWER MIDDLE LEFT TO LOWER CENTRELOWER LEFT BLOCK DIAGONAL LO" +
"WER MIDDLE LEFT TO LOWER RIGHTLOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEF" +
"T TO LOWER CENTRELOWER LEFT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RI" +
"GHTLOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTRELOWER RIGHT BLOCK" +
" DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTRELOWER RIGHT BLOCK DIAGONAL UP" +
"PER MIDDLE LEFT TO UPPER RIGHTLOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LE" +
"FT TO UPPER CENTRELOWER RIGHT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER " +
"RIGHTLOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTRELOWER RIGHT BL" +
"OCK DIAGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHTLOWER RIGHT BLOCK DI" +
"AGONAL LOWER CENTRE TO LOWER MIDDLE RIGHTLOWER RIGHT BLOCK DIAGONAL LOWE" +
"R LEFT TO LOWER MIDDLE RIGHTLOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO U" +
"PPER MIDDLE RIGHTLOWER RIGHT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE R" +
"IGHTLOWER RIGHT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHTLOWER LEFT BLO" +
"CK DIAGONAL UPPER CENTRE TO UPPER MIDDLE RIGHTLOWER LEFT BLOCK DIAGONAL " +
"UPPER LEFT TO UPPER MIDDLE RIGHTLOWER LEFT BLOCK DIAGONAL UPPER CENTRE T" +
"O LOWER MIDDLE RIGHTLOWER LEFT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE" +
" RIGHTLOWER LEFT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHTLOWER LEFT BL" +
"OCK DIAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHTUPPER RIGHT BLOCK DI" +
"AGONAL LOWER MIDDLE LEFT TO LOWER CENTREUPPER RIGHT BLOCK DIAGONAL LOWER" +
" MIDDLE LEFT TO LOWER RIGHTUPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT " +
"TO LOWER CENTREUPPER RIGHT BLOCK DIAGONAL UPPER MIDDLE LEFT TO LOWER RIG" +
"HTUPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER CENTREUPPER LEFT BLOCK " +
"DIAGONAL UPPER MIDDLE LEFT TO UPPER CENTREUPPER LEFT BLOCK DIAGONAL UPPE") + ("" +
"R MIDDLE LEFT TO UPPER RIGHTUPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT " +
"TO UPPER CENTREUPPER LEFT BLOCK DIAGONAL LOWER MIDDLE LEFT TO UPPER RIGH" +
"TUPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER CENTREUPPER LEFT BLOCK DI" +
"AGONAL LOWER MIDDLE LEFT TO UPPER MIDDLE RIGHTUPPER LEFT BLOCK DIAGONAL " +
"LOWER CENTRE TO LOWER MIDDLE RIGHTUPPER LEFT BLOCK DIAGONAL LOWER LEFT T" +
"O LOWER MIDDLE RIGHTUPPER LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER MIDD" +
"LE RIGHTUPPER LEFT BLOCK DIAGONAL LOWER LEFT TO UPPER MIDDLE RIGHTUPPER " +
"LEFT BLOCK DIAGONAL LOWER CENTRE TO UPPER RIGHTUPPER RIGHT BLOCK DIAGONA" +
"L UPPER CENTRE TO UPPER MIDDLE RIGHTUPPER RIGHT BLOCK DIAGONAL UPPER LEF" +
"T TO UPPER MIDDLE RIGHTUPPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER " +
"MIDDLE RIGHTUPPER RIGHT BLOCK DIAGONAL UPPER LEFT TO LOWER MIDDLE RIGHTU" +
"PPER RIGHT BLOCK DIAGONAL UPPER CENTRE TO LOWER RIGHTUPPER RIGHT BLOCK D" +
"IAGONAL UPPER MIDDLE LEFT TO LOWER MIDDLE RIGHTUPPER AND RIGHT AND LOWER" +
" TRIANGULAR THREE QUARTERS BLOCKLEFT AND LOWER AND RIGHT TRIANGULAR THRE" +
"E QUARTERS BLOCKUPPER AND LEFT AND LOWER TRIANGULAR THREE QUARTERS BLOCK" +
"LEFT AND UPPER AND RIGHT TRIANGULAR THREE QUARTERS BLOCKLEFT TRIANGULAR " +
"ONE QUARTER BLOCKUPPER TRIANGULAR ONE QUARTER BLOCKRIGHT TRIANGULAR ONE " +
"QUARTER BLOCKLOWER TRIANGULAR ONE QUARTER BLOCKVERTICAL ONE EIGHTH BLOCK" +
"-2VERTICAL ONE EIGHTH BLOCK-3VERTICAL ONE EIGHTH BLOCK-4VERTICAL ONE EIG" +
"HTH BLOCK-5VERTICAL ONE EIGHTH BLOCK-6VERTICAL ONE EIGHTH BLOCK-7HORIZON" +
"TAL ONE EIGHTH BLOCK-2HORIZONTAL ONE EIGHTH BLOCK-3HORIZONTAL ONE EIGHTH" +
" BLOCK-4HORIZONTAL ONE EIGHTH BLOCK-5HORIZONTAL ONE EIGHTH BLOCK-6HORIZO" +
"NTAL 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 ONE EIGHTH BLOCKHORIZONTAL ONE EIGHTH BLOCK-1358UPP" +
"ER ONE QUARTER BLOCKUPPER THREE EIGHTHS BLOCKUPPER FIVE EIGHTHS BLOCKUPP" +
"ER THREE QUARTERS BLOCKUPPER SEVEN EIGHTHS BLOCKRIGHT ONE QUARTER BLOCKR" +
"IGHT THREE EIGHTHS BLOCKRIGHT FIVE EIGHTHS BLOCKRIGHT THREE QUARTERS BLO" +
"CKRIGHT SEVEN EIGHTHS BLOCKLEFT HALF MEDIUM SHADERIGHT HALF MEDIUM SHADE" +
"UPPER HALF MEDIUM SHADELOWER HALF MEDIUM SHADEINVERSE MEDIUM SHADEUPPER " +
"HALF BLOCK AND LOWER HALF INVERSE MEDIUM SHADEUPPER HALF INVERSE MEDIUM " +
"SHADE AND LOWER HALF BLOCKLEFT HALF INVERSE MEDIUM SHADE AND RIGHT HALF " +
"BLOCKCHECKER BOARD FILLINVERSE CHECKER BOARD FILLHEAVY HORIZONTAL FILLUP" +
"PER LEFT TO LOWER RIGHT FILLUPPER RIGHT TO LOWER LEFT FILLUPPER AND LOWE" +
"R TRIANGULAR HALF BLOCKLEFT AND RIGHT TRIANGULAR HALF BLOCKUPPER LEFT TR" +
"IANGULAR MEDIUM SHADEUPPER RIGHT TRIANGULAR MEDIUM SHADELOWER RIGHT TRIA" +
"NGULAR MEDIUM SHADELOWER LEFT TRIANGULAR MEDIUM SHADEBOX DRAWINGS LIGHT " +
"DIAGONAL UPPER CENTRE TO MIDDLE LEFTBOX DRAWINGS LIGHT DIAGONAL UPPER CE" +
"NTRE TO MIDDLE RIGHTBOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER CEN" +
"TREBOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER CENTREBOX DRAWINGS " +
"LIGHT DIAGONAL UPPER CENTRE TO MIDDLE LEFT TO LOWER CENTREBOX DRAWINGS L" +
"IGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTREBOX DRAWINGS L" +
"IGHT DIAGONAL MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHTBOX DRAWINGS LI" +
"GHT DIAGONAL MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHTBOX DRAWINGS LIG" +
"HT DIAGONAL UPPER CENTRE TO MIDDLE LEFT AND MIDDLE RIGHT TO LOWER CENTRE" +
"BOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT AND MIDDLE LEFT" +
" TO LOWER CENTREBOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO MIDDLE RIGHT" +
" TO LOWER CENTRE TO MIDDLE LEFTBOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE " +
"TO MIDDLE LEFT TO LOWER CENTRE TO MIDDLE RIGHTBOX DRAWINGS LIGHT DIAGONA" +
"L MIDDLE LEFT TO UPPER CENTRE TO MIDDLE RIGHT TO LOWER CENTREBOX DRAWING" +
"S LIGHT DIAGONAL MIDDLE RIGHT TO UPPER CENTRE TO MIDDLE LEFT TO LOWER CE" +
"NTREBOX DRAWINGS LIGHT DIAGONAL DIAMONDBOX DRAWINGS LIGHT HORIZONTAL WIT" +
"H VERTICAL STROKEARROWHEAD-SHAPED POINTERINVERSE CHECK MARKLEFT HALF RUN" +
"NING MANRIGHT HALF RUNNING MANINVERSE DOWNWARDS ARROW WITH TIP LEFTWARDS" +
"LEFTWARDS ARROW AND UPPER AND LOWER ONE EIGHTH BLOCKRIGHTWARDS ARROW AND" +
" UPPER AND LOWER ONE EIGHTH BLOCKDOWNWARDS ARROW AND RIGHT ONE EIGHTH BL" +
"OCKUPWARDS ARROW AND RIGHT ONE EIGHTH BLOCKLEFT HALF FOLDERRIGHT HALF FO" +
"LDERVOIDED GREEK CROSSRIGHT OPEN SQUARED DOTNEGATIVE DIAGONAL CROSSNEGAT" +
"IVE DIAGONAL MIDDLE RIGHT TO LOWER CENTRENEGATIVE DIAGONAL DIAMONDWHITE " +
"HEAVY SALTIRE WITH ROUNDED CORNERSLEFT THIRD WHITE RIGHT POINTING INDEXM" +
"IDDLE THIRD WHITE RIGHT POINTING INDEXRIGHT THIRD WHITE RIGHT POINTING I" +
"NDEXNEGATIVE SQUARED QUESTION MARKSTICK FIGURESTICK FIGURE WITH ARMS RAI" +
"SEDSTICK FIGURE LEANING LEFTSTICK FIGURE LEANING RIGHTSTICK FIGURE WITH " +
"DRESSWHITE UP-POINTING CHEVRONWHITE CROSS MARKRAISED SMALL LEFT SQUARE B") + ("" +
"RACKETBLACK SMALL UP-POINTING CHEVRONLEFT TWO THIRDS BLOCKLEFT ONE THIRD" +
" BLOCKBOX DRAWINGS LIGHT DIAGONAL MIDDLE RIGHT TO LOWER LEFTBOX DRAWINGS" +
" LIGHT DIAGONAL UPPER RIGHT TO MIDDLE LEFTBOX DRAWINGS LIGHT DIAGONAL UP" +
"PER LEFT TO MIDDLE RIGHTBOX DRAWINGS LIGHT DIAGONAL MIDDLE LEFT TO LOWER" +
" RIGHTBOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER CENTREBOX DRAWINGS" +
" LIGHT DIAGONAL UPPER CENTRE TO LOWER RIGHTBOX DRAWINGS LIGHT DIAGONAL U" +
"PPER RIGHT TO LOWER CENTREBOX DRAWINGS LIGHT DIAGONAL UPPER CENTRE TO LO" +
"WER LEFTBOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO UPPER" +
" RIGHTBOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE CENTRE TO LOWER " +
"RIGHTBOX DRAWINGS LIGHT DIAGONAL LOWER LEFT TO MIDDLE CENTRE TO LOWER RI" +
"GHTBOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE CENTRE TO LOWER LEFT" +
"BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER CENTRE TO UPPER RIGHTBOX" +
" DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO MIDDLE LEFT TO LOWER RIGHTBOX DR" +
"AWINGS LIGHT DIAGONAL LOWER LEFT TO UPPER CENTRE TO LOWER RIGHTBOX DRAWI" +
"NGS LIGHT DIAGONAL UPPER LEFT TO MIDDLE RIGHT TO LOWER LEFTTOP JUSTIFIED" +
" LOWER HALF WHITE CIRCLERIGHT JUSTIFIED LEFT HALF WHITE CIRCLEBOTTOM JUS" +
"TIFIED UPPER HALF WHITE CIRCLELEFT JUSTIFIED RIGHT HALF WHITE CIRCLEUPPE" +
"R CENTRE ONE QUARTER BLOCKLOWER CENTRE ONE QUARTER BLOCKMIDDLE LEFT ONE " +
"QUARTER BLOCKMIDDLE RIGHT ONE QUARTER BLOCKTOP JUSTIFIED LOWER HALF BLAC" +
"K CIRCLERIGHT JUSTIFIED LEFT HALF BLACK CIRCLEBOTTOM JUSTIFIED UPPER HAL" +
"F BLACK CIRCLELEFT JUSTIFIED RIGHT HALF BLACK CIRCLETOP RIGHT JUSTIFIED " +
"LOWER LEFT QUARTER BLACK CIRCLEBOTTOM LEFT JUSTIFIED UPPER RIGHT QUARTER" +
" BLACK CIRCLEBOTTOM RIGHT JUSTIFIED UPPER LEFT QUARTER BLACK CIRCLETOP L" +
"EFT JUSTIFIED LOWER RIGHT QUARTER BLACK CIRCLESEGMENTED DIGIT ZEROSEGMEN" +
"TED DIGIT ONESEGMENTED DIGIT TWOSEGMENTED DIGIT THREESEGMENTED DIGIT FOU" +
"RSEGMENTED DIGIT FIVESEGMENTED DIGIT SIXSEGMENTED DIGIT SEVENSEGMENTED D" +
"IGIT EIGHTSEGMENTED DIGIT NINEALARM BELL SYMBOLCJK COMPATIBILITY IDEOGRA" +
"PH-2F800CJK COMPATIBILITY IDEOGRAPH-2F801CJK COMPATIBILITY IDEOGRAPH-2F8" +
"02CJK COMPATIBILITY IDEOGRAPH-2F803CJK COMPATIBILITY IDEOGRAPH-2F804CJK " +
"COMPATIBILITY IDEOGRAPH-2F805CJK COMPATIBILITY IDEOGRAPH-2F806CJK COMPAT" +
"IBILITY IDEOGRAPH-2F807CJK COMPATIBILITY IDEOGRAPH-2F808CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F809CJK COMPATIBILITY IDEOGRAPH-2F80ACJK COMPATIBILITY IDEO" +
"GRAPH-2F80BCJK COMPATIBILITY IDEOGRAPH-2F80CCJK COMPATIBILITY IDEOGRAPH-" +
"2F80DCJK COMPATIBILITY IDEOGRAPH-2F80ECJK COMPATIBILITY IDEOGRAPH-2F80FC" +
"JK COMPATIBILITY IDEOGRAPH-2F810CJK COMPATIBILITY IDEOGRAPH-2F811CJK COM" +
"PATIBILITY IDEOGRAPH-2F812CJK COMPATIBILITY IDEOGRAPH-2F813CJK COMPATIBI" +
"LITY IDEOGRAPH-2F814CJK COMPATIBILITY IDEOGRAPH-2F815CJK COMPATIBILITY I" +
"DEOGRAPH-2F816CJK COMPATIBILITY IDEOGRAPH-2F817CJK COMPATIBILITY IDEOGRA" +
"PH-2F818CJK COMPATIBILITY IDEOGRAPH-2F819CJK COMPATIBILITY IDEOGRAPH-2F8" +
"1ACJK COMPATIBILITY IDEOGRAPH-2F81BCJK COMPATIBILITY IDEOGRAPH-2F81CCJK " +
"COMPATIBILITY IDEOGRAPH-2F81DCJK COMPATIBILITY IDEOGRAPH-2F81ECJK COMPAT" +
"IBILITY IDEOGRAPH-2F81FCJK COMPATIBILITY IDEOGRAPH-2F820CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F821CJK COMPATIBILITY IDEOGRAPH-2F822CJK COMPATIBILITY IDEO" +
"GRAPH-2F823CJK COMPATIBILITY IDEOGRAPH-2F824CJK COMPATIBILITY IDEOGRAPH-" +
"2F825CJK COMPATIBILITY IDEOGRAPH-2F826CJK COMPATIBILITY IDEOGRAPH-2F827C" +
"JK COMPATIBILITY IDEOGRAPH-2F828CJK COMPATIBILITY IDEOGRAPH-2F829CJK COM" +
"PATIBILITY IDEOGRAPH-2F82ACJK COMPATIBILITY IDEOGRAPH-2F82BCJK COMPATIBI" +
"LITY IDEOGRAPH-2F82CCJK COMPATIBILITY IDEOGRAPH-2F82DCJK COMPATIBILITY I" +
"DEOGRAPH-2F82ECJK COMPATIBILITY IDEOGRAPH-2F82FCJK COMPATIBILITY IDEOGRA" +
"PH-2F830CJK COMPATIBILITY IDEOGRAPH-2F831CJK COMPATIBILITY IDEOGRAPH-2F8" +
"32CJK COMPATIBILITY IDEOGRAPH-2F833CJK COMPATIBILITY IDEOGRAPH-2F834CJK " +
"COMPATIBILITY IDEOGRAPH-2F835CJK COMPATIBILITY IDEOGRAPH-2F836CJK COMPAT" +
"IBILITY IDEOGRAPH-2F837CJK COMPATIBILITY IDEOGRAPH-2F838CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F839CJK COMPATIBILITY IDEOGRAPH-2F83ACJK COMPATIBILITY IDEO" +
"GRAPH-2F83BCJK COMPATIBILITY IDEOGRAPH-2F83CCJK COMPATIBILITY IDEOGRAPH-" +
"2F83DCJK COMPATIBILITY IDEOGRAPH-2F83ECJK COMPATIBILITY IDEOGRAPH-2F83FC" +
"JK COMPATIBILITY IDEOGRAPH-2F840CJK COMPATIBILITY IDEOGRAPH-2F841CJK COM" +
"PATIBILITY IDEOGRAPH-2F842CJK COMPATIBILITY IDEOGRAPH-2F843CJK COMPATIBI" +
"LITY IDEOGRAPH-2F844CJK COMPATIBILITY IDEOGRAPH-2F845CJK COMPATIBILITY I" +
"DEOGRAPH-2F846CJK COMPATIBILITY IDEOGRAPH-2F847CJK COMPATIBILITY IDEOGRA" +
"PH-2F848CJK COMPATIBILITY IDEOGRAPH-2F849CJK COMPATIBILITY IDEOGRAPH-2F8" +
"4ACJK COMPATIBILITY IDEOGRAPH-2F84BCJK COMPATIBILITY IDEOGRAPH-2F84CCJK " +
"COMPATIBILITY IDEOGRAPH-2F84DCJK COMPATIBILITY IDEOGRAPH-2F84ECJK COMPAT" +
"IBILITY IDEOGRAPH-2F84FCJK COMPATIBILITY IDEOGRAPH-2F850CJK COMPATIBILIT") + ("" +
"Y IDEOGRAPH-2F851CJK COMPATIBILITY IDEOGRAPH-2F852CJK COMPATIBILITY IDEO" +
"GRAPH-2F853CJK COMPATIBILITY IDEOGRAPH-2F854CJK COMPATIBILITY IDEOGRAPH-" +
"2F855CJK COMPATIBILITY IDEOGRAPH-2F856CJK COMPATIBILITY IDEOGRAPH-2F857C" +
"JK COMPATIBILITY IDEOGRAPH-2F858CJK COMPATIBILITY IDEOGRAPH-2F859CJK COM" +
"PATIBILITY IDEOGRAPH-2F85ACJK COMPATIBILITY IDEOGRAPH-2F85BCJK COMPATIBI" +
"LITY IDEOGRAPH-2F85CCJK COMPATIBILITY IDEOGRAPH-2F85DCJK COMPATIBILITY I" +
"DEOGRAPH-2F85ECJK COMPATIBILITY IDEOGRAPH-2F85FCJK COMPATIBILITY IDEOGRA" +
"PH-2F860CJK COMPATIBILITY IDEOGRAPH-2F861CJK COMPATIBILITY IDEOGRAPH-2F8" +
"62CJK COMPATIBILITY IDEOGRAPH-2F863CJK COMPATIBILITY IDEOGRAPH-2F864CJK " +
"COMPATIBILITY IDEOGRAPH-2F865CJK COMPATIBILITY IDEOGRAPH-2F866CJK COMPAT" +
"IBILITY IDEOGRAPH-2F867CJK COMPATIBILITY IDEOGRAPH-2F868CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F869CJK COMPATIBILITY IDEOGRAPH-2F86ACJK COMPATIBILITY IDEO" +
"GRAPH-2F86BCJK COMPATIBILITY IDEOGRAPH-2F86CCJK COMPATIBILITY IDEOGRAPH-" +
"2F86DCJK COMPATIBILITY IDEOGRAPH-2F86ECJK COMPATIBILITY IDEOGRAPH-2F86FC" +
"JK COMPATIBILITY IDEOGRAPH-2F870CJK COMPATIBILITY IDEOGRAPH-2F871CJK COM" +
"PATIBILITY IDEOGRAPH-2F872CJK COMPATIBILITY IDEOGRAPH-2F873CJK COMPATIBI" +
"LITY IDEOGRAPH-2F874CJK COMPATIBILITY IDEOGRAPH-2F875CJK COMPATIBILITY I" +
"DEOGRAPH-2F876CJK COMPATIBILITY IDEOGRAPH-2F877CJK COMPATIBILITY IDEOGRA" +
"PH-2F878CJK COMPATIBILITY IDEOGRAPH-2F879CJK COMPATIBILITY IDEOGRAPH-2F8" +
"7ACJK COMPATIBILITY IDEOGRAPH-2F87BCJK COMPATIBILITY IDEOGRAPH-2F87CCJK " +
"COMPATIBILITY IDEOGRAPH-2F87DCJK COMPATIBILITY IDEOGRAPH-2F87ECJK COMPAT" +
"IBILITY IDEOGRAPH-2F87FCJK COMPATIBILITY IDEOGRAPH-2F880CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F881CJK COMPATIBILITY IDEOGRAPH-2F882CJK COMPATIBILITY IDEO" +
"GRAPH-2F883CJK COMPATIBILITY IDEOGRAPH-2F884CJK COMPATIBILITY IDEOGRAPH-" +
"2F885CJK COMPATIBILITY IDEOGRAPH-2F886CJK COMPATIBILITY IDEOGRAPH-2F887C" +
"JK COMPATIBILITY IDEOGRAPH-2F888CJK COMPATIBILITY IDEOGRAPH-2F889CJK COM" +
"PATIBILITY IDEOGRAPH-2F88ACJK COMPATIBILITY IDEOGRAPH-2F88BCJK COMPATIBI" +
"LITY IDEOGRAPH-2F88CCJK COMPATIBILITY IDEOGRAPH-2F88DCJK COMPATIBILITY I" +
"DEOGRAPH-2F88ECJK COMPATIBILITY IDEOGRAPH-2F88FCJK COMPATIBILITY IDEOGRA" +
"PH-2F890CJK COMPATIBILITY IDEOGRAPH-2F891CJK COMPATIBILITY IDEOGRAPH-2F8" +
"92CJK COMPATIBILITY IDEOGRAPH-2F893CJK COMPATIBILITY IDEOGRAPH-2F894CJK " +
"COMPATIBILITY IDEOGRAPH-2F895CJK COMPATIBILITY IDEOGRAPH-2F896CJK COMPAT" +
"IBILITY IDEOGRAPH-2F897CJK COMPATIBILITY IDEOGRAPH-2F898CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F899CJK COMPATIBILITY IDEOGRAPH-2F89ACJK COMPATIBILITY IDEO" +
"GRAPH-2F89BCJK COMPATIBILITY IDEOGRAPH-2F89CCJK COMPATIBILITY IDEOGRAPH-" +
"2F89DCJK COMPATIBILITY IDEOGRAPH-2F89ECJK COMPATIBILITY IDEOGRAPH-2F89FC" +
"JK COMPATIBILITY IDEOGRAPH-2F8A0CJK COMPATIBILITY IDEOGRAPH-2F8A1CJK COM" +
"PATIBILITY IDEOGRAPH-2F8A2CJK COMPATIBILITY IDEOGRAPH-2F8A3CJK COMPATIBI" +
"LITY IDEOGRAPH-2F8A4CJK COMPATIBILITY IDEOGRAPH-2F8A5CJK COMPATIBILITY I" +
"DEOGRAPH-2F8A6CJK COMPATIBILITY IDEOGRAPH-2F8A7CJK COMPATIBILITY IDEOGRA" +
"PH-2F8A8CJK COMPATIBILITY IDEOGRAPH-2F8A9CJK COMPATIBILITY IDEOGRAPH-2F8" +
"AACJK COMPATIBILITY IDEOGRAPH-2F8ABCJK COMPATIBILITY IDEOGRAPH-2F8ACCJK " +
"COMPATIBILITY IDEOGRAPH-2F8ADCJK COMPATIBILITY IDEOGRAPH-2F8AECJK COMPAT" +
"IBILITY IDEOGRAPH-2F8AFCJK COMPATIBILITY IDEOGRAPH-2F8B0CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F8B1CJK COMPATIBILITY IDEOGRAPH-2F8B2CJK COMPATIBILITY IDEO" +
"GRAPH-2F8B3CJK COMPATIBILITY IDEOGRAPH-2F8B4CJK COMPATIBILITY IDEOGRAPH-" +
"2F8B5CJK COMPATIBILITY IDEOGRAPH-2F8B6CJK COMPATIBILITY IDEOGRAPH-2F8B7C" +
"JK COMPATIBILITY IDEOGRAPH-2F8B8CJK COMPATIBILITY IDEOGRAPH-2F8B9CJK COM" +
"PATIBILITY IDEOGRAPH-2F8BACJK COMPATIBILITY IDEOGRAPH-2F8BBCJK COMPATIBI" +
"LITY IDEOGRAPH-2F8BCCJK COMPATIBILITY IDEOGRAPH-2F8BDCJK COMPATIBILITY I" +
"DEOGRAPH-2F8BECJK COMPATIBILITY IDEOGRAPH-2F8BFCJK COMPATIBILITY IDEOGRA" +
"PH-2F8C0CJK COMPATIBILITY IDEOGRAPH-2F8C1CJK COMPATIBILITY IDEOGRAPH-2F8" +
"C2CJK COMPATIBILITY IDEOGRAPH-2F8C3CJK COMPATIBILITY IDEOGRAPH-2F8C4CJK " +
"COMPATIBILITY IDEOGRAPH-2F8C5CJK COMPATIBILITY IDEOGRAPH-2F8C6CJK COMPAT" +
"IBILITY IDEOGRAPH-2F8C7CJK COMPATIBILITY IDEOGRAPH-2F8C8CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F8C9CJK COMPATIBILITY IDEOGRAPH-2F8CACJK COMPATIBILITY IDEO" +
"GRAPH-2F8CBCJK COMPATIBILITY IDEOGRAPH-2F8CCCJK COMPATIBILITY IDEOGRAPH-" +
"2F8CDCJK COMPATIBILITY IDEOGRAPH-2F8CECJK COMPATIBILITY IDEOGRAPH-2F8CFC" +
"JK COMPATIBILITY IDEOGRAPH-2F8D0CJK COMPATIBILITY IDEOGRAPH-2F8D1CJK COM" +
"PATIBILITY IDEOGRAPH-2F8D2CJK COMPATIBILITY IDEOGRAPH-2F8D3CJK COMPATIBI" +
"LITY IDEOGRAPH-2F8D4CJK COMPATIBILITY IDEOGRAPH-2F8D5CJK COMPATIBILITY I" +
"DEOGRAPH-2F8D6CJK COMPATIBILITY IDEOGRAPH-2F8D7CJK COMPATIBILITY IDEOGRA" +
"PH-2F8D8CJK COMPATIBILITY IDEOGRAPH-2F8D9CJK COMPATIBILITY IDEOGRAPH-2F8" +
"DACJK COMPATIBILITY IDEOGRAPH-2F8DBCJK COMPATIBILITY IDEOGRAPH-2F8DCCJK ") + ("" +
"COMPATIBILITY IDEOGRAPH-2F8DDCJK COMPATIBILITY IDEOGRAPH-2F8DECJK COMPAT" +
"IBILITY IDEOGRAPH-2F8DFCJK COMPATIBILITY IDEOGRAPH-2F8E0CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F8E1CJK COMPATIBILITY IDEOGRAPH-2F8E2CJK COMPATIBILITY IDEO" +
"GRAPH-2F8E3CJK COMPATIBILITY IDEOGRAPH-2F8E4CJK COMPATIBILITY IDEOGRAPH-" +
"2F8E5CJK COMPATIBILITY IDEOGRAPH-2F8E6CJK COMPATIBILITY IDEOGRAPH-2F8E7C" +
"JK COMPATIBILITY IDEOGRAPH-2F8E8CJK COMPATIBILITY IDEOGRAPH-2F8E9CJK COM" +
"PATIBILITY IDEOGRAPH-2F8EACJK COMPATIBILITY IDEOGRAPH-2F8EBCJK COMPATIBI" +
"LITY IDEOGRAPH-2F8ECCJK COMPATIBILITY IDEOGRAPH-2F8EDCJK COMPATIBILITY I" +
"DEOGRAPH-2F8EECJK COMPATIBILITY IDEOGRAPH-2F8EFCJK COMPATIBILITY IDEOGRA" +
"PH-2F8F0CJK COMPATIBILITY IDEOGRAPH-2F8F1CJK COMPATIBILITY IDEOGRAPH-2F8" +
"F2CJK COMPATIBILITY IDEOGRAPH-2F8F3CJK COMPATIBILITY IDEOGRAPH-2F8F4CJK " +
"COMPATIBILITY IDEOGRAPH-2F8F5CJK COMPATIBILITY IDEOGRAPH-2F8F6CJK COMPAT" +
"IBILITY IDEOGRAPH-2F8F7CJK COMPATIBILITY IDEOGRAPH-2F8F8CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F8F9CJK COMPATIBILITY IDEOGRAPH-2F8FACJK COMPATIBILITY IDEO" +
"GRAPH-2F8FBCJK COMPATIBILITY IDEOGRAPH-2F8FCCJK COMPATIBILITY IDEOGRAPH-" +
"2F8FDCJK COMPATIBILITY IDEOGRAPH-2F8FECJK COMPATIBILITY IDEOGRAPH-2F8FFC" +
"JK COMPATIBILITY IDEOGRAPH-2F900CJK COMPATIBILITY IDEOGRAPH-2F901CJK COM" +
"PATIBILITY IDEOGRAPH-2F902CJK COMPATIBILITY IDEOGRAPH-2F903CJK COMPATIBI" +
"LITY IDEOGRAPH-2F904CJK COMPATIBILITY IDEOGRAPH-2F905CJK COMPATIBILITY I" +
"DEOGRAPH-2F906CJK COMPATIBILITY IDEOGRAPH-2F907CJK COMPATIBILITY IDEOGRA" +
"PH-2F908CJK COMPATIBILITY IDEOGRAPH-2F909CJK COMPATIBILITY IDEOGRAPH-2F9" +
"0ACJK COMPATIBILITY IDEOGRAPH-2F90BCJK COMPATIBILITY IDEOGRAPH-2F90CCJK " +
"COMPATIBILITY IDEOGRAPH-2F90DCJK COMPATIBILITY IDEOGRAPH-2F90ECJK COMPAT" +
"IBILITY IDEOGRAPH-2F90FCJK COMPATIBILITY IDEOGRAPH-2F910CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F911CJK COMPATIBILITY IDEOGRAPH-2F912CJK COMPATIBILITY IDEO" +
"GRAPH-2F913CJK COMPATIBILITY IDEOGRAPH-2F914CJK COMPATIBILITY IDEOGRAPH-" +
"2F915CJK COMPATIBILITY IDEOGRAPH-2F916CJK COMPATIBILITY IDEOGRAPH-2F917C" +
"JK COMPATIBILITY IDEOGRAPH-2F918CJK COMPATIBILITY IDEOGRAPH-2F919CJK COM" +
"PATIBILITY IDEOGRAPH-2F91ACJK COMPATIBILITY IDEOGRAPH-2F91BCJK COMPATIBI" +
"LITY IDEOGRAPH-2F91CCJK COMPATIBILITY IDEOGRAPH-2F91DCJK COMPATIBILITY I" +
"DEOGRAPH-2F91ECJK COMPATIBILITY IDEOGRAPH-2F91FCJK COMPATIBILITY IDEOGRA" +
"PH-2F920CJK COMPATIBILITY IDEOGRAPH-2F921CJK COMPATIBILITY IDEOGRAPH-2F9" +
"22CJK COMPATIBILITY IDEOGRAPH-2F923CJK COMPATIBILITY IDEOGRAPH-2F924CJK " +
"COMPATIBILITY IDEOGRAPH-2F925CJK COMPATIBILITY IDEOGRAPH-2F926CJK COMPAT" +
"IBILITY IDEOGRAPH-2F927CJK COMPATIBILITY IDEOGRAPH-2F928CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F929CJK COMPATIBILITY IDEOGRAPH-2F92ACJK COMPATIBILITY IDEO" +
"GRAPH-2F92BCJK COMPATIBILITY IDEOGRAPH-2F92CCJK COMPATIBILITY IDEOGRAPH-" +
"2F92DCJK COMPATIBILITY IDEOGRAPH-2F92ECJK COMPATIBILITY IDEOGRAPH-2F92FC" +
"JK COMPATIBILITY IDEOGRAPH-2F930CJK COMPATIBILITY IDEOGRAPH-2F931CJK COM" +
"PATIBILITY IDEOGRAPH-2F932CJK COMPATIBILITY IDEOGRAPH-2F933CJK COMPATIBI" +
"LITY IDEOGRAPH-2F934CJK COMPATIBILITY IDEOGRAPH-2F935CJK COMPATIBILITY I" +
"DEOGRAPH-2F936CJK COMPATIBILITY IDEOGRAPH-2F937CJK COMPATIBILITY IDEOGRA" +
"PH-2F938CJK COMPATIBILITY IDEOGRAPH-2F939CJK COMPATIBILITY IDEOGRAPH-2F9" +
"3ACJK COMPATIBILITY IDEOGRAPH-2F93BCJK COMPATIBILITY IDEOGRAPH-2F93CCJK " +
"COMPATIBILITY IDEOGRAPH-2F93DCJK COMPATIBILITY IDEOGRAPH-2F93ECJK COMPAT" +
"IBILITY IDEOGRAPH-2F93FCJK COMPATIBILITY IDEOGRAPH-2F940CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F941CJK COMPATIBILITY IDEOGRAPH-2F942CJK COMPATIBILITY IDEO" +
"GRAPH-2F943CJK COMPATIBILITY IDEOGRAPH-2F944CJK COMPATIBILITY IDEOGRAPH-" +
"2F945CJK COMPATIBILITY IDEOGRAPH-2F946CJK COMPATIBILITY IDEOGRAPH-2F947C" +
"JK COMPATIBILITY IDEOGRAPH-2F948CJK COMPATIBILITY IDEOGRAPH-2F949CJK COM" +
"PATIBILITY IDEOGRAPH-2F94ACJK COMPATIBILITY IDEOGRAPH-2F94BCJK COMPATIBI" +
"LITY IDEOGRAPH-2F94CCJK COMPATIBILITY IDEOGRAPH-2F94DCJK COMPATIBILITY I" +
"DEOGRAPH-2F94ECJK COMPATIBILITY IDEOGRAPH-2F94FCJK COMPATIBILITY IDEOGRA" +
"PH-2F950CJK COMPATIBILITY IDEOGRAPH-2F951CJK COMPATIBILITY IDEOGRAPH-2F9" +
"52CJK COMPATIBILITY IDEOGRAPH-2F953CJK COMPATIBILITY IDEOGRAPH-2F954CJK " +
"COMPATIBILITY IDEOGRAPH-2F955CJK COMPATIBILITY IDEOGRAPH-2F956CJK COMPAT" +
"IBILITY IDEOGRAPH-2F957CJK COMPATIBILITY IDEOGRAPH-2F958CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F959CJK COMPATIBILITY IDEOGRAPH-2F95ACJK COMPATIBILITY IDEO" +
"GRAPH-2F95BCJK COMPATIBILITY IDEOGRAPH-2F95CCJK COMPATIBILITY IDEOGRAPH-" +
"2F95DCJK COMPATIBILITY IDEOGRAPH-2F95ECJK COMPATIBILITY IDEOGRAPH-2F95FC" +
"JK COMPATIBILITY IDEOGRAPH-2F960CJK COMPATIBILITY IDEOGRAPH-2F961CJK COM" +
"PATIBILITY IDEOGRAPH-2F962CJK COMPATIBILITY IDEOGRAPH-2F963CJK COMPATIBI" +
"LITY IDEOGRAPH-2F964CJK COMPATIBILITY IDEOGRAPH-2F965CJK COMPATIBILITY I" +
"DEOGRAPH-2F966CJK COMPATIBILITY IDEOGRAPH-2F967CJK COMPATIBILITY IDEOGRA") + ("" +
"PH-2F968CJK COMPATIBILITY IDEOGRAPH-2F969CJK COMPATIBILITY IDEOGRAPH-2F9" +
"6ACJK COMPATIBILITY IDEOGRAPH-2F96BCJK COMPATIBILITY IDEOGRAPH-2F96CCJK " +
"COMPATIBILITY IDEOGRAPH-2F96DCJK COMPATIBILITY IDEOGRAPH-2F96ECJK COMPAT" +
"IBILITY IDEOGRAPH-2F96FCJK COMPATIBILITY IDEOGRAPH-2F970CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F971CJK COMPATIBILITY IDEOGRAPH-2F972CJK COMPATIBILITY IDEO" +
"GRAPH-2F973CJK COMPATIBILITY IDEOGRAPH-2F974CJK COMPATIBILITY IDEOGRAPH-" +
"2F975CJK COMPATIBILITY IDEOGRAPH-2F976CJK COMPATIBILITY IDEOGRAPH-2F977C" +
"JK COMPATIBILITY IDEOGRAPH-2F978CJK COMPATIBILITY IDEOGRAPH-2F979CJK COM" +
"PATIBILITY IDEOGRAPH-2F97ACJK COMPATIBILITY IDEOGRAPH-2F97BCJK COMPATIBI" +
"LITY IDEOGRAPH-2F97CCJK COMPATIBILITY IDEOGRAPH-2F97DCJK COMPATIBILITY I" +
"DEOGRAPH-2F97ECJK COMPATIBILITY IDEOGRAPH-2F97FCJK COMPATIBILITY IDEOGRA" +
"PH-2F980CJK COMPATIBILITY IDEOGRAPH-2F981CJK COMPATIBILITY IDEOGRAPH-2F9" +
"82CJK COMPATIBILITY IDEOGRAPH-2F983CJK COMPATIBILITY IDEOGRAPH-2F984CJK " +
"COMPATIBILITY IDEOGRAPH-2F985CJK COMPATIBILITY IDEOGRAPH-2F986CJK COMPAT" +
"IBILITY IDEOGRAPH-2F987CJK COMPATIBILITY IDEOGRAPH-2F988CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F989CJK COMPATIBILITY IDEOGRAPH-2F98ACJK COMPATIBILITY IDEO" +
"GRAPH-2F98BCJK COMPATIBILITY IDEOGRAPH-2F98CCJK COMPATIBILITY IDEOGRAPH-" +
"2F98DCJK COMPATIBILITY IDEOGRAPH-2F98ECJK COMPATIBILITY IDEOGRAPH-2F98FC" +
"JK COMPATIBILITY IDEOGRAPH-2F990CJK COMPATIBILITY IDEOGRAPH-2F991CJK COM" +
"PATIBILITY IDEOGRAPH-2F992CJK COMPATIBILITY IDEOGRAPH-2F993CJK COMPATIBI" +
"LITY IDEOGRAPH-2F994CJK COMPATIBILITY IDEOGRAPH-2F995CJK COMPATIBILITY I" +
"DEOGRAPH-2F996CJK COMPATIBILITY IDEOGRAPH-2F997CJK COMPATIBILITY IDEOGRA" +
"PH-2F998CJK COMPATIBILITY IDEOGRAPH-2F999CJK COMPATIBILITY IDEOGRAPH-2F9" +
"9ACJK COMPATIBILITY IDEOGRAPH-2F99BCJK COMPATIBILITY IDEOGRAPH-2F99CCJK " +
"COMPATIBILITY IDEOGRAPH-2F99DCJK COMPATIBILITY IDEOGRAPH-2F99ECJK COMPAT" +
"IBILITY IDEOGRAPH-2F99FCJK COMPATIBILITY IDEOGRAPH-2F9A0CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F9A1CJK COMPATIBILITY IDEOGRAPH-2F9A2CJK COMPATIBILITY IDEO" +
"GRAPH-2F9A3CJK COMPATIBILITY IDEOGRAPH-2F9A4CJK COMPATIBILITY IDEOGRAPH-" +
"2F9A5CJK COMPATIBILITY IDEOGRAPH-2F9A6CJK COMPATIBILITY IDEOGRAPH-2F9A7C" +
"JK COMPATIBILITY IDEOGRAPH-2F9A8CJK COMPATIBILITY IDEOGRAPH-2F9A9CJK COM" +
"PATIBILITY IDEOGRAPH-2F9AACJK COMPATIBILITY IDEOGRAPH-2F9ABCJK COMPATIBI" +
"LITY IDEOGRAPH-2F9ACCJK COMPATIBILITY IDEOGRAPH-2F9ADCJK COMPATIBILITY I" +
"DEOGRAPH-2F9AECJK COMPATIBILITY IDEOGRAPH-2F9AFCJK COMPATIBILITY IDEOGRA" +
"PH-2F9B0CJK COMPATIBILITY IDEOGRAPH-2F9B1CJK COMPATIBILITY IDEOGRAPH-2F9" +
"B2CJK COMPATIBILITY IDEOGRAPH-2F9B3CJK COMPATIBILITY IDEOGRAPH-2F9B4CJK " +
"COMPATIBILITY IDEOGRAPH-2F9B5CJK COMPATIBILITY IDEOGRAPH-2F9B6CJK COMPAT" +
"IBILITY IDEOGRAPH-2F9B7CJK COMPATIBILITY IDEOGRAPH-2F9B8CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F9B9CJK COMPATIBILITY IDEOGRAPH-2F9BACJK COMPATIBILITY IDEO" +
"GRAPH-2F9BBCJK COMPATIBILITY IDEOGRAPH-2F9BCCJK COMPATIBILITY IDEOGRAPH-" +
"2F9BDCJK COMPATIBILITY IDEOGRAPH-2F9BECJK COMPATIBILITY IDEOGRAPH-2F9BFC" +
"JK COMPATIBILITY IDEOGRAPH-2F9C0CJK COMPATIBILITY IDEOGRAPH-2F9C1CJK COM" +
"PATIBILITY IDEOGRAPH-2F9C2CJK COMPATIBILITY IDEOGRAPH-2F9C3CJK COMPATIBI" +
"LITY IDEOGRAPH-2F9C4CJK COMPATIBILITY IDEOGRAPH-2F9C5CJK COMPATIBILITY I" +
"DEOGRAPH-2F9C6CJK COMPATIBILITY IDEOGRAPH-2F9C7CJK COMPATIBILITY IDEOGRA" +
"PH-2F9C8CJK COMPATIBILITY IDEOGRAPH-2F9C9CJK COMPATIBILITY IDEOGRAPH-2F9" +
"CACJK COMPATIBILITY IDEOGRAPH-2F9CBCJK COMPATIBILITY IDEOGRAPH-2F9CCCJK " +
"COMPATIBILITY IDEOGRAPH-2F9CDCJK COMPATIBILITY IDEOGRAPH-2F9CECJK COMPAT" +
"IBILITY IDEOGRAPH-2F9CFCJK COMPATIBILITY IDEOGRAPH-2F9D0CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F9D1CJK COMPATIBILITY IDEOGRAPH-2F9D2CJK COMPATIBILITY IDEO" +
"GRAPH-2F9D3CJK COMPATIBILITY IDEOGRAPH-2F9D4CJK COMPATIBILITY IDEOGRAPH-" +
"2F9D5CJK COMPATIBILITY IDEOGRAPH-2F9D6CJK COMPATIBILITY IDEOGRAPH-2F9D7C" +
"JK COMPATIBILITY IDEOGRAPH-2F9D8CJK COMPATIBILITY IDEOGRAPH-2F9D9CJK COM" +
"PATIBILITY IDEOGRAPH-2F9DACJK COMPATIBILITY IDEOGRAPH-2F9DBCJK COMPATIBI" +
"LITY IDEOGRAPH-2F9DCCJK COMPATIBILITY IDEOGRAPH-2F9DDCJK COMPATIBILITY I" +
"DEOGRAPH-2F9DECJK COMPATIBILITY IDEOGRAPH-2F9DFCJK COMPATIBILITY IDEOGRA" +
"PH-2F9E0CJK COMPATIBILITY IDEOGRAPH-2F9E1CJK COMPATIBILITY IDEOGRAPH-2F9" +
"E2CJK COMPATIBILITY IDEOGRAPH-2F9E3CJK COMPATIBILITY IDEOGRAPH-2F9E4CJK " +
"COMPATIBILITY IDEOGRAPH-2F9E5CJK COMPATIBILITY IDEOGRAPH-2F9E6CJK COMPAT" +
"IBILITY IDEOGRAPH-2F9E7CJK COMPATIBILITY IDEOGRAPH-2F9E8CJK COMPATIBILIT" +
"Y IDEOGRAPH-2F9E9CJK COMPATIBILITY IDEOGRAPH-2F9EACJK COMPATIBILITY IDEO" +
"GRAPH-2F9EBCJK COMPATIBILITY IDEOGRAPH-2F9ECCJK COMPATIBILITY IDEOGRAPH-" +
"2F9EDCJK COMPATIBILITY IDEOGRAPH-2F9EECJK COMPATIBILITY IDEOGRAPH-2F9EFC" +
"JK COMPATIBILITY IDEOGRAPH-2F9F0CJK COMPATIBILITY IDEOGRAPH-2F9F1CJK COM" +
"PATIBILITY IDEOGRAPH-2F9F2CJK COMPATIBILITY IDEOGRAPH-2F9F3CJK COMPATIBI") + ("" +
"LITY IDEOGRAPH-2F9F4CJK COMPATIBILITY IDEOGRAPH-2F9F5CJK COMPATIBILITY I" +
"DEOGRAPH-2F9F6CJK COMPATIBILITY IDEOGRAPH-2F9F7CJK COMPATIBILITY IDEOGRA" +
"PH-2F9F8CJK COMPATIBILITY IDEOGRAPH-2F9F9CJK COMPATIBILITY IDEOGRAPH-2F9" +
"FACJK COMPATIBILITY IDEOGRAPH-2F9FBCJK COMPATIBILITY IDEOGRAPH-2F9FCCJK " +
"COMPATIBILITY IDEOGRAPH-2F9FDCJK COMPATIBILITY IDEOGRAPH-2F9FECJK COMPAT" +
"IBILITY IDEOGRAPH-2F9FFCJK COMPATIBILITY IDEOGRAPH-2FA00CJK COMPATIBILIT" +
"Y IDEOGRAPH-2FA01CJK COMPATIBILITY IDEOGRAPH-2FA02CJK COMPATIBILITY IDEO" +
"GRAPH-2FA03CJK COMPATIBILITY IDEOGRAPH-2FA04CJK COMPATIBILITY IDEOGRAPH-" +
"2FA05CJK COMPATIBILITY IDEOGRAPH-2FA06CJK COMPATIBILITY IDEOGRAPH-2FA07C" +
"JK COMPATIBILITY IDEOGRAPH-2FA08CJK COMPATIBILITY IDEOGRAPH-2FA09CJK COM" +
"PATIBILITY IDEOGRAPH-2FA0ACJK COMPATIBILITY IDEOGRAPH-2FA0BCJK COMPATIBI" +
"LITY IDEOGRAPH-2FA0CCJK COMPATIBILITY IDEOGRAPH-2FA0DCJK COMPATIBILITY I" +
"DEOGRAPH-2FA0ECJK COMPATIBILITY IDEOGRAPH-2FA0FCJK COMPATIBILITY IDEOGRA" +
"PH-2FA10CJK COMPATIBILITY IDEOGRAPH-2FA11CJK COMPATIBILITY IDEOGRAPH-2FA" +
"12CJK COMPATIBILITY IDEOGRAPH-2FA13CJK COMPATIBILITY IDEOGRAPH-2FA14CJK " +
"COMPATIBILITY IDEOGRAPH-2FA15CJK COMPATIBILITY IDEOGRAPH-2FA16CJK COMPAT" +
"IBILITY IDEOGRAPH-2FA17CJK COMPATIBILITY IDEOGRAPH-2FA18CJK COMPATIBILIT" +
"Y IDEOGRAPH-2FA19CJK COMPATIBILITY IDEOGRAPH-2FA1ACJK COMPATIBILITY IDEO" +
"GRAPH-2FA1BCJK COMPATIBILITY IDEOGRAPH-2FA1CCJK COMPATIBILITY IDEOGRAPH-" +
"2FA1DLANGUAGE TAGTAG SPACETAG EXCLAMATION MARKTAG QUOTATION MARKTAG NUMB" +
"ER SIGNTAG DOLLAR SIGNTAG PERCENT SIGNTAG AMPERSANDTAG APOSTROPHETAG LEF" +
"T PARENTHESISTAG RIGHT PARENTHESISTAG ASTERISKTAG PLUS SIGNTAG COMMATAG " +
"HYPHEN-MINUSTAG FULL STOPTAG SOLIDUSTAG DIGIT ZEROTAG DIGIT ONETAG DIGIT" +
" TWOTAG DIGIT THREETAG DIGIT FOURTAG DIGIT FIVETAG DIGIT SIXTAG DIGIT SE" +
"VENTAG DIGIT EIGHTTAG DIGIT NINETAG COLONTAG SEMICOLONTAG LESS-THAN SIGN" +
"TAG EQUALS SIGNTAG GREATER-THAN SIGNTAG QUESTION MARKTAG COMMERCIAL ATTA" +
"G LATIN CAPITAL LETTER ATAG LATIN CAPITAL LETTER BTAG LATIN CAPITAL LETT" +
"ER CTAG LATIN CAPITAL LETTER DTAG LATIN CAPITAL LETTER ETAG LATIN CAPITA" +
"L LETTER FTAG LATIN CAPITAL LETTER GTAG LATIN CAPITAL LETTER HTAG LATIN " +
"CAPITAL LETTER ITAG LATIN CAPITAL LETTER JTAG LATIN CAPITAL LETTER KTAG " +
"LATIN CAPITAL LETTER LTAG LATIN CAPITAL LETTER MTAG LATIN CAPITAL LETTER" +
" NTAG LATIN CAPITAL LETTER OTAG LATIN CAPITAL LETTER PTAG LATIN CAPITAL " +
"LETTER QTAG LATIN CAPITAL LETTER RTAG LATIN CAPITAL LETTER STAG LATIN CA" +
"PITAL LETTER TTAG LATIN CAPITAL LETTER UTAG LATIN CAPITAL LETTER VTAG LA" +
"TIN CAPITAL LETTER WTAG LATIN CAPITAL LETTER XTAG LATIN CAPITAL LETTER Y" +
"TAG LATIN CAPITAL LETTER ZTAG LEFT SQUARE BRACKETTAG REVERSE SOLIDUSTAG " +
"RIGHT SQUARE BRACKETTAG CIRCUMFLEX ACCENTTAG LOW LINETAG 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 CURLY BRACKETTAG V" +
"ERTICAL LINETAG RIGHT CURLY BRACKETTAG TILDECANCEL TAGVARIATION SELECTOR" +
"-17VARIATION SELECTOR-18VARIATION SELECTOR-19VARIATION SELECTOR-20VARIAT" +
"ION SELECTOR-21VARIATION SELECTOR-22VARIATION SELECTOR-23VARIATION SELEC" +
"TOR-24VARIATION SELECTOR-25VARIATION SELECTOR-26VARIATION SELECTOR-27VAR" +
"IATION SELECTOR-28VARIATION SELECTOR-29VARIATION SELECTOR-30VARIATION SE" +
"LECTOR-31VARIATION SELECTOR-32VARIATION SELECTOR-33VARIATION SELECTOR-34" +
"VARIATION SELECTOR-35VARIATION SELECTOR-36VARIATION SELECTOR-37VARIATION" +
" SELECTOR-38VARIATION SELECTOR-39VARIATION SELECTOR-40VARIATION SELECTOR" +
"-41VARIATION SELECTOR-42VARIATION SELECTOR-43VARIATION SELECTOR-44VARIAT" +
"ION SELECTOR-45VARIATION SELECTOR-46VARIATION SELECTOR-47VARIATION SELEC" +
"TOR-48VARIATION SELECTOR-49VARIATION SELECTOR-50VARIATION SELECTOR-51VAR" +
"IATION SELECTOR-52VARIATION SELECTOR-53VARIATION SELECTOR-54VARIATION SE" +
"LECTOR-55VARIATION SELECTOR-56VARIATION SELECTOR-57VARIATION SELECTOR-58" +
"VARIATION SELECTOR-59VARIATION SELECTOR-60VARIATION SELECTOR-61VARIATION" +
" SELECTOR-62VARIATION SELECTOR-63VARIATION SELECTOR-64VARIATION SELECTOR" +
"-65VARIATION SELECTOR-66VARIATION SELECTOR-67VARIATION SELECTOR-68VARIAT" +
"ION SELECTOR-69VARIATION SELECTOR-70VARIATION SELECTOR-71VARIATION SELEC" +
"TOR-72VARIATION SELECTOR-73VARIATION SELECTOR-74VARIATION SELECTOR-75VAR") + ("" +
"IATION SELECTOR-76VARIATION SELECTOR-77VARIATION SELECTOR-78VARIATION SE" +
"LECTOR-79VARIATION SELECTOR-80VARIATION SELECTOR-81VARIATION SELECTOR-82" +
"VARIATION SELECTOR-83VARIATION SELECTOR-84VARIATION SELECTOR-85VARIATION" +
" SELECTOR-86VARIATION SELECTOR-87VARIATION SELECTOR-88VARIATION SELECTOR" +
"-89VARIATION SELECTOR-90VARIATION SELECTOR-91VARIATION SELECTOR-92VARIAT" +
"ION SELECTOR-93VARIATION SELECTOR-94VARIATION SELECTOR-95VARIATION SELEC" +
"TOR-96VARIATION SELECTOR-97VARIATION SELECTOR-98VARIATION SELECTOR-99VAR" +
"IATION SELECTOR-100VARIATION SELECTOR-101VARIATION SELECTOR-102VARIATION" +
" SELECTOR-103VARIATION SELECTOR-104VARIATION SELECTOR-105VARIATION SELEC" +
"TOR-106VARIATION SELECTOR-107VARIATION SELECTOR-108VARIATION SELECTOR-10" +
"9VARIATION SELECTOR-110VARIATION SELECTOR-111VARIATION SELECTOR-112VARIA" +
"TION SELECTOR-113VARIATION SELECTOR-114VARIATION SELECTOR-115VARIATION S" +
"ELECTOR-116VARIATION SELECTOR-117VARIATION SELECTOR-118VARIATION SELECTO" +
"R-119VARIATION SELECTOR-120VARIATION SELECTOR-121VARIATION SELECTOR-122V" +
"ARIATION SELECTOR-123VARIATION SELECTOR-124VARIATION SELECTOR-125VARIATI" +
"ON SELECTOR-126VARIATION SELECTOR-127VARIATION SELECTOR-128VARIATION SEL" +
"ECTOR-129VARIATION SELECTOR-130VARIATION SELECTOR-131VARIATION SELECTOR-" +
"132VARIATION SELECTOR-133VARIATION SELECTOR-134VARIATION SELECTOR-135VAR" +
"IATION SELECTOR-136VARIATION SELECTOR-137VARIATION SELECTOR-138VARIATION" +
" SELECTOR-139VARIATION SELECTOR-140VARIATION SELECTOR-141VARIATION SELEC" +
"TOR-142VARIATION SELECTOR-143VARIATION SELECTOR-144VARIATION SELECTOR-14" +
"5VARIATION SELECTOR-146VARIATION SELECTOR-147VARIATION SELECTOR-148VARIA" +
"TION SELECTOR-149VARIATION SELECTOR-150VARIATION SELECTOR-151VARIATION S" +
"ELECTOR-152VARIATION SELECTOR-153VARIATION SELECTOR-154VARIATION SELECTO" +
"R-155VARIATION SELECTOR-156VARIATION SELECTOR-157VARIATION SELECTOR-158V" +
"ARIATION SELECTOR-159VARIATION SELECTOR-160VARIATION SELECTOR-161VARIATI" +
"ON SELECTOR-162VARIATION SELECTOR-163VARIATION SELECTOR-164VARIATION SEL" +
"ECTOR-165VARIATION SELECTOR-166VARIATION SELECTOR-167VARIATION SELECTOR-" +
"168VARIATION SELECTOR-169VARIATION SELECTOR-170VARIATION SELECTOR-171VAR" +
"IATION SELECTOR-172VARIATION SELECTOR-173VARIATION SELECTOR-174VARIATION" +
" SELECTOR-175VARIATION SELECTOR-176VARIATION SELECTOR-177VARIATION SELEC" +
"TOR-178VARIATION SELECTOR-179VARIATION SELECTOR-180VARIATION SELECTOR-18" +
"1VARIATION SELECTOR-182VARIATION SELECTOR-183VARIATION SELECTOR-184VARIA" +
"TION SELECTOR-185VARIATION SELECTOR-186VARIATION SELECTOR-187VARIATION S" +
"ELECTOR-188VARIATION SELECTOR-189VARIATION SELECTOR-190VARIATION SELECTO" +
"R-191VARIATION SELECTOR-192VARIATION SELECTOR-193VARIATION SELECTOR-194V" +
"ARIATION SELECTOR-195VARIATION SELECTOR-196VARIATION SELECTOR-197VARIATI" +
"ON SELECTOR-198VARIATION SELECTOR-199VARIATION SELECTOR-200VARIATION SEL" +
"ECTOR-201VARIATION SELECTOR-202VARIATION SELECTOR-203VARIATION SELECTOR-" +
"204VARIATION SELECTOR-205VARIATION SELECTOR-206VARIATION SELECTOR-207VAR" +
"IATION SELECTOR-208VARIATION SELECTOR-209VARIATION SELECTOR-210VARIATION" +
" SELECTOR-211VARIATION SELECTOR-212VARIATION SELECTOR-213VARIATION SELEC" +
"TOR-214VARIATION SELECTOR-215VARIATION SELECTOR-216VARIATION SELECTOR-21" +
"7VARIATION SELECTOR-218VARIATION SELECTOR-219VARIATION SELECTOR-220VARIA" +
"TION SELECTOR-221VARIATION SELECTOR-222VARIATION SELECTOR-223VARIATION S" +
"ELECTOR-224VARIATION SELECTOR-225VARIATION SELECTOR-226VARIATION SELECTO" +
"R-227VARIATION SELECTOR-228VARIATION SELECTOR-229VARIATION SELECTOR-230V" +
"ARIATION SELECTOR-231VARIATION SELECTOR-232VARIATION SELECTOR-233VARIATI" +
"ON SELECTOR-234VARIATION SELECTOR-235VARIATION SELECTOR-236VARIATION SEL" +
"ECTOR-237VARIATION SELECTOR-238VARIATION SELECTOR-239VARIATION SELECTOR-" +
"240VARIATION SELECTOR-241VARIATION SELECTOR-242VARIATION SELECTOR-243VAR" +
"IATION SELECTOR-244VARIATION SELECTOR-245VARIATION SELECTOR-246VARIATION" +
" SELECTOR-247VARIATION SELECTOR-248VARIATION SELECTOR-249VARIATION SELEC" +
"TOR-250VARIATION SELECTOR-251VARIATION SELECTOR-252VARIATION SELECTOR-25" +
"3VARIATION SELECTOR-254VARIATION SELECTOR-255VARIATION SELECTOR-256")
// Total table size 1128283 bytes (1101KiB); checksum: AED7E173
// 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.27
package width
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
const UnicodeVersion = "17.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: 15040 bytes (14.69 KiB). Checksum: 1c37fc66dcf8f532.
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: 106 blocks, 6784 entries, 13568 bytes
// The third block is the zero block.
var widthValues = [6784]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,
0x930: 0x4000, 0x931: 0x4000, 0x932: 0x4000, 0x933: 0x4000, 0x934: 0x4000, 0x935: 0x4000,
0x936: 0x4000, 0x937: 0x4000,
// 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
0x98a: 0x4000, 0x98b: 0x4000,
0x98c: 0x4000, 0x98d: 0x4000, 0x98e: 0x4000, 0x98f: 0x4000,
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,
0xc7c: 0x4000, 0xc7d: 0x4000, 0xc7e: 0x4000, 0xc7f: 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,
0xe64: 0x4000, 0xe65: 0x4000,
0xe6f: 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, 0x11b2: 0x4000, 0x11b3: 0x4000, 0x11b4: 0x4000, 0x11b5: 0x4000,
0x11b6: 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,
0x11ff: 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, 0x1216: 0x4000, 0x1217: 0x4000,
0x1218: 0x4000, 0x1219: 0x4000, 0x121a: 0x4000, 0x121b: 0x4000, 0x121c: 0x4000, 0x121d: 0x4000,
0x121e: 0x4000,
// Block 0x49, offset 0x1240
0x1240: 0x4000, 0x1241: 0x4000, 0x1242: 0x4000, 0x1243: 0x4000, 0x1244: 0x4000, 0x1245: 0x4000,
0x1246: 0x4000, 0x1247: 0x4000, 0x1248: 0x4000, 0x1249: 0x4000, 0x124a: 0x4000, 0x124b: 0x4000,
0x124c: 0x4000, 0x124d: 0x4000, 0x124e: 0x4000, 0x124f: 0x4000, 0x1250: 0x4000, 0x1251: 0x4000,
0x1252: 0x4000, 0x1253: 0x4000, 0x1254: 0x4000, 0x1255: 0x4000, 0x1256: 0x4000, 0x1257: 0x4000,
0x1258: 0x4000, 0x1259: 0x4000, 0x125a: 0x4000, 0x125b: 0x4000, 0x125c: 0x4000, 0x125d: 0x4000,
0x125e: 0x4000, 0x125f: 0x4000, 0x1260: 0x4000, 0x1261: 0x4000, 0x1262: 0x4000, 0x1263: 0x4000,
0x1264: 0x4000, 0x1265: 0x4000, 0x1266: 0x4000, 0x1267: 0x4000, 0x1268: 0x4000, 0x1269: 0x4000,
0x126a: 0x4000, 0x126b: 0x4000, 0x126c: 0x4000, 0x126d: 0x4000, 0x126e: 0x4000, 0x126f: 0x4000,
0x1270: 0x4000, 0x1271: 0x4000, 0x1272: 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
0x1380: 0x4000, 0x1381: 0x4000, 0x1382: 0x4000, 0x1383: 0x4000, 0x1384: 0x4000, 0x1385: 0x4000,
0x1386: 0x4000, 0x1387: 0x4000, 0x1388: 0x4000, 0x1389: 0x4000, 0x138a: 0x4000, 0x138b: 0x4000,
0x138c: 0x4000, 0x138d: 0x4000, 0x138e: 0x4000, 0x138f: 0x4000, 0x1390: 0x4000, 0x1391: 0x4000,
0x1392: 0x4000, 0x1393: 0x4000, 0x1394: 0x4000, 0x1395: 0x4000, 0x1396: 0x4000,
0x13a0: 0x4000, 0x13a1: 0x4000, 0x13a2: 0x4000, 0x13a3: 0x4000,
0x13a4: 0x4000, 0x13a5: 0x4000, 0x13a6: 0x4000, 0x13a7: 0x4000, 0x13a8: 0x4000, 0x13a9: 0x4000,
0x13aa: 0x4000, 0x13ab: 0x4000, 0x13ac: 0x4000, 0x13ad: 0x4000, 0x13ae: 0x4000, 0x13af: 0x4000,
0x13b0: 0x4000, 0x13b1: 0x4000, 0x13b2: 0x4000, 0x13b3: 0x4000, 0x13b4: 0x4000, 0x13b5: 0x4000,
0x13b6: 0x4000,
// Block 0x4f, offset 0x13c0
0x13c4: 0x4000,
// Block 0x50, offset 0x1400
0x140f: 0x4000,
// 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,
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,
0x146a: 0x2000, 0x146b: 0x2000, 0x146c: 0x2000, 0x146d: 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: 0x2000, 0x148f: 0x2000, 0x1490: 0x2000, 0x1491: 0x2000,
0x1492: 0x2000, 0x1493: 0x2000, 0x1494: 0x2000, 0x1495: 0x2000, 0x1496: 0x2000, 0x1497: 0x2000,
0x1498: 0x2000, 0x1499: 0x2000, 0x149a: 0x2000, 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,
0x14b0: 0x2000, 0x14b1: 0x2000, 0x14b2: 0x2000, 0x14b3: 0x2000, 0x14b4: 0x2000, 0x14b5: 0x2000,
0x14b6: 0x2000, 0x14b7: 0x2000, 0x14b8: 0x2000, 0x14b9: 0x2000, 0x14ba: 0x2000, 0x14bb: 0x2000,
0x14bc: 0x2000, 0x14bd: 0x2000, 0x14be: 0x2000, 0x14bf: 0x2000,
// Block 0x53, offset 0x14c0
0x14c0: 0x2000, 0x14c1: 0x2000, 0x14c2: 0x2000, 0x14c3: 0x2000, 0x14c4: 0x2000, 0x14c5: 0x2000,
0x14c6: 0x2000, 0x14c7: 0x2000, 0x14c8: 0x2000, 0x14c9: 0x2000, 0x14ca: 0x2000, 0x14cb: 0x2000,
0x14cc: 0x2000, 0x14cd: 0x2000, 0x14ce: 0x4000, 0x14cf: 0x2000, 0x14d0: 0x2000, 0x14d1: 0x4000,
0x14d2: 0x4000, 0x14d3: 0x4000, 0x14d4: 0x4000, 0x14d5: 0x4000, 0x14d6: 0x4000, 0x14d7: 0x4000,
0x14d8: 0x4000, 0x14d9: 0x4000, 0x14da: 0x4000, 0x14db: 0x2000, 0x14dc: 0x2000, 0x14dd: 0x2000,
0x14de: 0x2000, 0x14df: 0x2000, 0x14e0: 0x2000, 0x14e1: 0x2000, 0x14e2: 0x2000, 0x14e3: 0x2000,
0x14e4: 0x2000, 0x14e5: 0x2000, 0x14e6: 0x2000, 0x14e7: 0x2000, 0x14e8: 0x2000, 0x14e9: 0x2000,
0x14ea: 0x2000, 0x14eb: 0x2000, 0x14ec: 0x2000,
// Block 0x54, offset 0x1500
0x1500: 0x4000, 0x1501: 0x4000, 0x1502: 0x4000,
0x1510: 0x4000, 0x1511: 0x4000,
0x1512: 0x4000, 0x1513: 0x4000, 0x1514: 0x4000, 0x1515: 0x4000, 0x1516: 0x4000, 0x1517: 0x4000,
0x1518: 0x4000, 0x1519: 0x4000, 0x151a: 0x4000, 0x151b: 0x4000, 0x151c: 0x4000, 0x151d: 0x4000,
0x151e: 0x4000, 0x151f: 0x4000, 0x1520: 0x4000, 0x1521: 0x4000, 0x1522: 0x4000, 0x1523: 0x4000,
0x1524: 0x4000, 0x1525: 0x4000, 0x1526: 0x4000, 0x1527: 0x4000, 0x1528: 0x4000, 0x1529: 0x4000,
0x152a: 0x4000, 0x152b: 0x4000, 0x152c: 0x4000, 0x152d: 0x4000, 0x152e: 0x4000, 0x152f: 0x4000,
0x1530: 0x4000, 0x1531: 0x4000, 0x1532: 0x4000, 0x1533: 0x4000, 0x1534: 0x4000, 0x1535: 0x4000,
0x1536: 0x4000, 0x1537: 0x4000, 0x1538: 0x4000, 0x1539: 0x4000, 0x153a: 0x4000, 0x153b: 0x4000,
// Block 0x55, offset 0x1540
0x1540: 0x4000, 0x1541: 0x4000, 0x1542: 0x4000, 0x1543: 0x4000, 0x1544: 0x4000, 0x1545: 0x4000,
0x1546: 0x4000, 0x1547: 0x4000, 0x1548: 0x4000,
0x1550: 0x4000, 0x1551: 0x4000,
0x1560: 0x4000, 0x1561: 0x4000, 0x1562: 0x4000, 0x1563: 0x4000,
0x1564: 0x4000, 0x1565: 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,
0x15ad: 0x4000, 0x15ae: 0x4000, 0x15af: 0x4000,
0x15b0: 0x4000, 0x15b1: 0x4000, 0x15b2: 0x4000, 0x15b3: 0x4000, 0x15b4: 0x4000, 0x15b5: 0x4000,
0x15b7: 0x4000, 0x15b8: 0x4000, 0x15b9: 0x4000, 0x15ba: 0x4000, 0x15bb: 0x4000,
0x15bc: 0x4000, 0x15bd: 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, 0x15d4: 0x4000, 0x15d5: 0x4000, 0x15d6: 0x4000, 0x15d7: 0x4000,
0x15d8: 0x4000, 0x15d9: 0x4000, 0x15da: 0x4000, 0x15db: 0x4000, 0x15dc: 0x4000, 0x15dd: 0x4000,
0x15de: 0x4000, 0x15df: 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, 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, 0x160b: 0x4000,
0x160c: 0x4000, 0x160d: 0x4000, 0x160e: 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, 0x1631: 0x4000, 0x1632: 0x4000, 0x1633: 0x4000, 0x1634: 0x4000, 0x1635: 0x4000,
0x1636: 0x4000, 0x1637: 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,
0x164f: 0x4000, 0x1650: 0x4000, 0x1651: 0x4000,
0x1652: 0x4000, 0x1653: 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, 0x1674: 0x4000,
0x1678: 0x4000, 0x1679: 0x4000, 0x167a: 0x4000, 0x167b: 0x4000,
0x167c: 0x4000, 0x167d: 0x4000, 0x167e: 0x4000, 0x167f: 0x4000,
// Block 0x5a, offset 0x1680
0x1680: 0x4000, 0x1681: 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,
// Block 0x5b, offset 0x16c0
0x16c0: 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, 0x16fd: 0x4000, 0x16fe: 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, 0x173f: 0x4000,
// Block 0x5d, offset 0x1740
0x1740: 0x4000, 0x1741: 0x4000, 0x1742: 0x4000, 0x1743: 0x4000, 0x1744: 0x4000, 0x1745: 0x4000,
0x1746: 0x4000, 0x1747: 0x4000, 0x1748: 0x4000, 0x1749: 0x4000, 0x174a: 0x4000, 0x174b: 0x4000,
0x174c: 0x4000, 0x174d: 0x4000, 0x174e: 0x4000, 0x174f: 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, 0x1768: 0x4000, 0x1769: 0x4000,
0x176a: 0x4000, 0x176b: 0x4000, 0x176c: 0x4000, 0x176d: 0x4000, 0x176e: 0x4000, 0x176f: 0x4000,
0x1770: 0x4000, 0x1771: 0x4000, 0x1772: 0x4000, 0x1773: 0x4000, 0x1774: 0x4000, 0x1775: 0x4000,
0x1776: 0x4000, 0x1777: 0x4000, 0x1778: 0x4000, 0x1779: 0x4000, 0x177a: 0x4000, 0x177b: 0x4000,
0x177c: 0x4000, 0x177d: 0x4000,
// Block 0x5e, offset 0x1780
0x178b: 0x4000,
0x178c: 0x4000, 0x178d: 0x4000, 0x178e: 0x4000, 0x1790: 0x4000, 0x1791: 0x4000,
0x1792: 0x4000, 0x1793: 0x4000, 0x1794: 0x4000, 0x1795: 0x4000, 0x1796: 0x4000, 0x1797: 0x4000,
0x1798: 0x4000, 0x1799: 0x4000, 0x179a: 0x4000, 0x179b: 0x4000, 0x179c: 0x4000, 0x179d: 0x4000,
0x179e: 0x4000, 0x179f: 0x4000, 0x17a0: 0x4000, 0x17a1: 0x4000, 0x17a2: 0x4000, 0x17a3: 0x4000,
0x17a4: 0x4000, 0x17a5: 0x4000, 0x17a6: 0x4000, 0x17a7: 0x4000,
0x17ba: 0x4000,
// Block 0x5f, offset 0x17c0
0x17d5: 0x4000, 0x17d6: 0x4000,
0x17e4: 0x4000,
// Block 0x60, offset 0x1800
0x183b: 0x4000,
0x183c: 0x4000, 0x183d: 0x4000, 0x183e: 0x4000, 0x183f: 0x4000,
// Block 0x61, offset 0x1840
0x1840: 0x4000, 0x1841: 0x4000, 0x1842: 0x4000, 0x1843: 0x4000, 0x1844: 0x4000, 0x1845: 0x4000,
0x1846: 0x4000, 0x1847: 0x4000, 0x1848: 0x4000, 0x1849: 0x4000, 0x184a: 0x4000, 0x184b: 0x4000,
0x184c: 0x4000, 0x184d: 0x4000, 0x184e: 0x4000, 0x184f: 0x4000,
// Block 0x62, offset 0x1880
0x1880: 0x4000, 0x1881: 0x4000, 0x1882: 0x4000, 0x1883: 0x4000, 0x1884: 0x4000, 0x1885: 0x4000,
0x188c: 0x4000, 0x1890: 0x4000, 0x1891: 0x4000,
0x1892: 0x4000, 0x1895: 0x4000, 0x1896: 0x4000, 0x1897: 0x4000,
0x1898: 0x4000, 0x189c: 0x4000, 0x189d: 0x4000,
0x189e: 0x4000, 0x189f: 0x4000,
0x18ab: 0x4000, 0x18ac: 0x4000,
0x18b4: 0x4000, 0x18b5: 0x4000,
0x18b6: 0x4000, 0x18b7: 0x4000, 0x18b8: 0x4000, 0x18b9: 0x4000, 0x18ba: 0x4000, 0x18bb: 0x4000,
0x18bc: 0x4000,
// Block 0x63, offset 0x18c0
0x18e0: 0x4000, 0x18e1: 0x4000, 0x18e2: 0x4000, 0x18e3: 0x4000,
0x18e4: 0x4000, 0x18e5: 0x4000, 0x18e6: 0x4000, 0x18e7: 0x4000, 0x18e8: 0x4000, 0x18e9: 0x4000,
0x18ea: 0x4000, 0x18eb: 0x4000,
0x18f0: 0x4000,
// Block 0x64, offset 0x1900
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,
0x193c: 0x4000, 0x193d: 0x4000, 0x193e: 0x4000, 0x193f: 0x4000,
// Block 0x65, offset 0x1940
0x1940: 0x4000, 0x1941: 0x4000, 0x1942: 0x4000, 0x1943: 0x4000, 0x1944: 0x4000, 0x1945: 0x4000,
0x1947: 0x4000, 0x1948: 0x4000, 0x1949: 0x4000, 0x194a: 0x4000, 0x194b: 0x4000,
0x194c: 0x4000, 0x194d: 0x4000, 0x194e: 0x4000, 0x194f: 0x4000, 0x1950: 0x4000, 0x1951: 0x4000,
0x1952: 0x4000, 0x1953: 0x4000, 0x1954: 0x4000, 0x1955: 0x4000, 0x1956: 0x4000, 0x1957: 0x4000,
0x1958: 0x4000, 0x1959: 0x4000, 0x195a: 0x4000, 0x195b: 0x4000, 0x195c: 0x4000, 0x195d: 0x4000,
0x195e: 0x4000, 0x195f: 0x4000, 0x1960: 0x4000, 0x1961: 0x4000, 0x1962: 0x4000, 0x1963: 0x4000,
0x1964: 0x4000, 0x1965: 0x4000, 0x1966: 0x4000, 0x1967: 0x4000, 0x1968: 0x4000, 0x1969: 0x4000,
0x196a: 0x4000, 0x196b: 0x4000, 0x196c: 0x4000, 0x196d: 0x4000, 0x196e: 0x4000, 0x196f: 0x4000,
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, 0x197d: 0x4000, 0x197e: 0x4000, 0x197f: 0x4000,
// Block 0x66, offset 0x1980
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,
// Block 0x67, offset 0x19c0
0x19c0: 0x4000, 0x19c1: 0x4000, 0x19c2: 0x4000, 0x19c3: 0x4000, 0x19c4: 0x4000, 0x19c5: 0x4000,
0x19c6: 0x4000, 0x19c7: 0x4000, 0x19c8: 0x4000, 0x19c9: 0x4000, 0x19ca: 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, 0x19dc: 0x4000, 0x19dd: 0x4000,
0x19de: 0x4000, 0x19df: 0x4000, 0x19e0: 0x4000, 0x19e1: 0x4000, 0x19e2: 0x4000, 0x19e3: 0x4000,
0x19e4: 0x4000, 0x19e5: 0x4000, 0x19e6: 0x4000, 0x19e7: 0x4000, 0x19e8: 0x4000, 0x19e9: 0x4000,
0x19ea: 0x4000, 0x19eb: 0x4000, 0x19ec: 0x4000, 0x19ed: 0x4000, 0x19ee: 0x4000, 0x19ef: 0x4000,
0x19f0: 0x4000, 0x19f1: 0x4000, 0x19f2: 0x4000, 0x19f3: 0x4000, 0x19f4: 0x4000, 0x19f5: 0x4000,
0x19f6: 0x4000, 0x19f7: 0x4000, 0x19f8: 0x4000, 0x19f9: 0x4000, 0x19fa: 0x4000, 0x19fb: 0x4000,
0x19fc: 0x4000, 0x19fd: 0x4000, 0x19fe: 0x4000, 0x19ff: 0x4000,
// Block 0x68, offset 0x1a00
0x1a00: 0x4000, 0x1a01: 0x4000, 0x1a02: 0x4000, 0x1a03: 0x4000, 0x1a04: 0x4000, 0x1a05: 0x4000,
0x1a06: 0x4000, 0x1a08: 0x4000,
0x1a0d: 0x4000, 0x1a0e: 0x4000, 0x1a0f: 0x4000, 0x1a10: 0x4000, 0x1a11: 0x4000,
0x1a12: 0x4000, 0x1a13: 0x4000, 0x1a14: 0x4000, 0x1a15: 0x4000, 0x1a16: 0x4000, 0x1a17: 0x4000,
0x1a18: 0x4000, 0x1a19: 0x4000, 0x1a1a: 0x4000, 0x1a1b: 0x4000, 0x1a1c: 0x4000,
0x1a1f: 0x4000, 0x1a20: 0x4000, 0x1a21: 0x4000, 0x1a22: 0x4000, 0x1a23: 0x4000,
0x1a24: 0x4000, 0x1a25: 0x4000, 0x1a26: 0x4000, 0x1a27: 0x4000, 0x1a28: 0x4000, 0x1a29: 0x4000,
0x1a2a: 0x4000, 0x1a2f: 0x4000,
0x1a30: 0x4000, 0x1a31: 0x4000, 0x1a32: 0x4000, 0x1a33: 0x4000, 0x1a34: 0x4000, 0x1a35: 0x4000,
0x1a36: 0x4000, 0x1a37: 0x4000, 0x1a38: 0x4000,
// Block 0x69, offset 0x1a40
0x1a40: 0x2000, 0x1a41: 0x2000, 0x1a42: 0x2000, 0x1a43: 0x2000, 0x1a44: 0x2000, 0x1a45: 0x2000,
0x1a46: 0x2000, 0x1a47: 0x2000, 0x1a48: 0x2000, 0x1a49: 0x2000, 0x1a4a: 0x2000, 0x1a4b: 0x2000,
0x1a4c: 0x2000, 0x1a4d: 0x2000, 0x1a4e: 0x2000, 0x1a4f: 0x2000, 0x1a50: 0x2000, 0x1a51: 0x2000,
0x1a52: 0x2000, 0x1a53: 0x2000, 0x1a54: 0x2000, 0x1a55: 0x2000, 0x1a56: 0x2000, 0x1a57: 0x2000,
0x1a58: 0x2000, 0x1a59: 0x2000, 0x1a5a: 0x2000, 0x1a5b: 0x2000, 0x1a5c: 0x2000, 0x1a5d: 0x2000,
0x1a5e: 0x2000, 0x1a5f: 0x2000, 0x1a60: 0x2000, 0x1a61: 0x2000, 0x1a62: 0x2000, 0x1a63: 0x2000,
0x1a64: 0x2000, 0x1a65: 0x2000, 0x1a66: 0x2000, 0x1a67: 0x2000, 0x1a68: 0x2000, 0x1a69: 0x2000,
0x1a6a: 0x2000, 0x1a6b: 0x2000, 0x1a6c: 0x2000, 0x1a6d: 0x2000, 0x1a6e: 0x2000, 0x1a6f: 0x2000,
0x1a70: 0x2000, 0x1a71: 0x2000, 0x1a72: 0x2000, 0x1a73: 0x2000, 0x1a74: 0x2000, 0x1a75: 0x2000,
0x1a76: 0x2000, 0x1a77: 0x2000, 0x1a78: 0x2000, 0x1a79: 0x2000, 0x1a7a: 0x2000, 0x1a7b: 0x2000,
0x1a7c: 0x2000, 0x1a7d: 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: 0x05, 0xe6: 0x05, 0xe7: 0x05,
0xe8: 0x05, 0xe9: 0x05, 0xea: 0x06, 0xeb: 0x05, 0xec: 0x05, 0xed: 0x07, 0xee: 0x08, 0xef: 0x09,
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, 0x1f7: 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: 0x3a, 0x213: 0x3b,
0x225: 0x3c,
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: 0x0e, 0x253: 0x0e, 0x254: 0x0e, 0x255: 0x0e, 0x256: 0x0e, 0x257: 0x0e,
0x258: 0x0e, 0x259: 0x0e, 0x25a: 0x0e, 0x25b: 0x0e, 0x25c: 0x0e, 0x25d: 0x0e, 0x25e: 0x3d,
// Block 0xa, offset 0x280
0x280: 0x08, 0x281: 0x08, 0x282: 0x08, 0x283: 0x08, 0x284: 0x08, 0x285: 0x08, 0x286: 0x08, 0x287: 0x08,
0x288: 0x08, 0x289: 0x08, 0x28a: 0x08, 0x28b: 0x08, 0x28c: 0x08, 0x28d: 0x08, 0x28e: 0x08, 0x28f: 0x08,
0x290: 0x08, 0x291: 0x08, 0x292: 0x08, 0x293: 0x08, 0x294: 0x08, 0x295: 0x08, 0x296: 0x08, 0x297: 0x08,
0x298: 0x08, 0x299: 0x08, 0x29a: 0x08, 0x29b: 0x08, 0x29c: 0x08, 0x29d: 0x08, 0x29e: 0x08, 0x29f: 0x08,
0x2a0: 0x08, 0x2a1: 0x08, 0x2a2: 0x08, 0x2a3: 0x08, 0x2a4: 0x08, 0x2a5: 0x08, 0x2a6: 0x08, 0x2a7: 0x08,
0x2a8: 0x08, 0x2a9: 0x08, 0x2aa: 0x08, 0x2ab: 0x08, 0x2ac: 0x08, 0x2ad: 0x08, 0x2ae: 0x08, 0x2af: 0x08,
0x2b0: 0x08, 0x2b1: 0x08, 0x2b2: 0x08, 0x2b3: 0x08, 0x2b4: 0x08, 0x2b5: 0x08, 0x2b6: 0x08, 0x2b7: 0x08,
0x2b8: 0x08, 0x2b9: 0x08, 0x2ba: 0x08, 0x2bb: 0x08, 0x2bc: 0x08, 0x2bd: 0x08, 0x2be: 0x08, 0x2bf: 0x08,
// 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: 0x0e, 0x2e5: 0x0e, 0x2e6: 0x0e, 0x2e7: 0x0e,
0x2e8: 0x0e, 0x2e9: 0x0e, 0x2ea: 0x0e, 0x2eb: 0x0e,
0x2f8: 0x3e, 0x2f9: 0x3f, 0x2fc: 0x40, 0x2fd: 0x41, 0x2fe: 0x42, 0x2ff: 0x43,
// Block 0xc, offset 0x300
0x33f: 0x44,
// Block 0xd, offset 0x340
0x340: 0x0e, 0x341: 0x0e, 0x342: 0x0e, 0x343: 0x0e, 0x344: 0x0e, 0x345: 0x0e, 0x346: 0x0e, 0x347: 0x0e,
0x348: 0x0e, 0x349: 0x0e, 0x34a: 0x0e, 0x34b: 0x0e, 0x34c: 0x0e, 0x34d: 0x0e, 0x34e: 0x0e, 0x34f: 0x0e,
0x350: 0x0e, 0x351: 0x0e, 0x352: 0x0e, 0x353: 0x0e, 0x354: 0x0e, 0x355: 0x0e, 0x356: 0x0e, 0x357: 0x0e,
0x358: 0x0e, 0x359: 0x0e, 0x35a: 0x0e, 0x35b: 0x0e, 0x35c: 0x0e, 0x35d: 0x0e, 0x35e: 0x0e, 0x35f: 0x0e,
0x360: 0x0e, 0x361: 0x0e, 0x362: 0x0e, 0x363: 0x0e, 0x364: 0x0e, 0x365: 0x0e, 0x366: 0x0e, 0x367: 0x0e,
0x368: 0x0e, 0x369: 0x0e, 0x36a: 0x0e, 0x36b: 0x0e, 0x36c: 0x0e, 0x36d: 0x0e, 0x36e: 0x0e, 0x36f: 0x0e,
0x370: 0x0e, 0x371: 0x0e, 0x372: 0x0e, 0x373: 0x45, 0x374: 0x46, 0x376: 0x0e, 0x377: 0x47,
// Block 0xe, offset 0x380
0x3bf: 0x48,
// Block 0xf, offset 0x3c0
0x3c0: 0x0e, 0x3c1: 0x0e, 0x3c2: 0x0e, 0x3c3: 0x0e, 0x3c4: 0x49, 0x3c5: 0x4a, 0x3c6: 0x0e, 0x3c7: 0x0e,
0x3c8: 0x0e, 0x3c9: 0x0e, 0x3ca: 0x0e, 0x3cb: 0x4b,
// Block 0x10, offset 0x400
0x40c: 0x0e, 0x40d: 0x4c,
// Block 0x11, offset 0x440
0x440: 0x4d, 0x443: 0x4e, 0x444: 0x4f, 0x445: 0x50, 0x446: 0x51,
0x448: 0x52, 0x449: 0x53, 0x44c: 0x54, 0x44d: 0x55, 0x44e: 0x56, 0x44f: 0x57,
0x450: 0x58, 0x451: 0x59, 0x452: 0x0e, 0x453: 0x5a, 0x454: 0x5b, 0x455: 0x5c, 0x456: 0x5d, 0x457: 0x5e,
0x458: 0x0e, 0x459: 0x5f, 0x45a: 0x0e, 0x45b: 0x60, 0x45f: 0x61,
0x464: 0x62, 0x465: 0x63, 0x466: 0x0e, 0x467: 0x0e,
0x469: 0x64, 0x46a: 0x65, 0x46b: 0x66,
// Block 0x12, offset 0x480
0x496: 0x0a, 0x497: 0x05,
0x498: 0x0b, 0x49a: 0x0c, 0x49b: 0x0d, 0x49d: 0x0e, 0x49f: 0x0f,
0x4a0: 0x05, 0x4a1: 0x05, 0x4a2: 0x05, 0x4a3: 0x05, 0x4a4: 0x05, 0x4a5: 0x05, 0x4a6: 0x05, 0x4a7: 0x05,
0x4a8: 0x05, 0x4a9: 0x05, 0x4aa: 0x05, 0x4ab: 0x05, 0x4ac: 0x05, 0x4ad: 0x05, 0x4ae: 0x05, 0x4af: 0x05,
0x4b0: 0x05, 0x4b1: 0x05, 0x4b2: 0x05, 0x4b3: 0x05, 0x4b4: 0x05, 0x4b5: 0x05, 0x4b6: 0x05, 0x4b7: 0x05,
0x4b8: 0x05, 0x4b9: 0x05, 0x4ba: 0x05, 0x4bb: 0x05, 0x4bc: 0x05, 0x4bd: 0x05, 0x4be: 0x05, 0x4bf: 0x05,
// 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: 0x67,
// Block 0x15, offset 0x540
0x560: 0x11,
0x570: 0x08, 0x571: 0x08, 0x572: 0x08, 0x573: 0x08, 0x574: 0x08, 0x575: 0x08, 0x576: 0x08, 0x577: 0x08,
0x578: 0x08, 0x579: 0x08, 0x57a: 0x08, 0x57b: 0x08, 0x57c: 0x08, 0x57d: 0x08, 0x57e: 0x08, 0x57f: 0x12,
// Block 0x16, offset 0x580
0x580: 0x08, 0x581: 0x08, 0x582: 0x08, 0x583: 0x08, 0x584: 0x08, 0x585: 0x08, 0x586: 0x08, 0x587: 0x08,
0x588: 0x08, 0x589: 0x08, 0x58a: 0x08, 0x58b: 0x08, 0x58c: 0x08, 0x58d: 0x08, 0x58e: 0x08, 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 15640 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).