services
This commit is contained in:
+3
@@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/AUTHORS.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
||||
+1097
File diff suppressed because it is too large
Load Diff
+1249
File diff suppressed because it is too large
Load Diff
+136
@@ -0,0 +1,136 @@
|
||||
// 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"
|
||||
"io/ioutil"
|
||||
"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), name)
|
||||
var (
|
||||
data []byte
|
||||
err error
|
||||
done = make(chan struct{})
|
||||
)
|
||||
go func() {
|
||||
data, err = ioutil.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), 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), 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 := ioutil.TempFile(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()
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package autocert
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"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{
|
||||
m: m,
|
||||
conf: m.TLSConfig(),
|
||||
}
|
||||
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
|
||||
return ln
|
||||
}
|
||||
|
||||
type listener struct {
|
||||
m *Manager
|
||||
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 homeDir() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||
}
|
||||
if h := os.Getenv("HOME"); h != "" {
|
||||
return h
|
||||
}
|
||||
return "/"
|
||||
}
|
||||
|
||||
func cacheDir() string {
|
||||
const base = "golang-autocert"
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
return filepath.Join(homeDir(), "Library", "Caches", base)
|
||||
case "windows":
|
||||
for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
|
||||
if v := os.Getenv(ev); v != "" {
|
||||
return filepath.Join(v, base)
|
||||
}
|
||||
}
|
||||
// Worst case:
|
||||
return filepath.Join(homeDir(), base)
|
||||
}
|
||||
if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
|
||||
return filepath.Join(xdg, base)
|
||||
}
|
||||
return filepath.Join(homeDir(), ".cache", base)
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package autocert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// renewJitter is the maximum deviation from Manager.RenewBefore.
|
||||
const renewJitter = time.Hour
|
||||
|
||||
// domainRenewal tracks the state used by the periodic timers
|
||||
// renewing a single domain's cert.
|
||||
type domainRenewal struct {
|
||||
m *Manager
|
||||
ck certKey
|
||||
key crypto.Signer
|
||||
|
||||
timerMu sync.Mutex
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
// start starts a cert renewal timer at the time
|
||||
// defined by the certificate expiration time exp.
|
||||
//
|
||||
// If the timer is already started, calling start is a noop.
|
||||
func (dr *domainRenewal) start(exp time.Time) {
|
||||
dr.timerMu.Lock()
|
||||
defer dr.timerMu.Unlock()
|
||||
if dr.timer != nil {
|
||||
return
|
||||
}
|
||||
dr.timer = time.AfterFunc(dr.next(exp), dr.renew)
|
||||
}
|
||||
|
||||
// stop stops the cert renewal timer.
|
||||
// If the timer is already stopped, calling stop is a noop.
|
||||
func (dr *domainRenewal) stop() {
|
||||
dr.timerMu.Lock()
|
||||
defer dr.timerMu.Unlock()
|
||||
if dr.timer == nil {
|
||||
return
|
||||
}
|
||||
dr.timer.Stop()
|
||||
dr.timer = nil
|
||||
}
|
||||
|
||||
// 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.timer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||
defer cancel()
|
||||
// TODO: rotate dr.key at some point?
|
||||
next, err := dr.do(ctx)
|
||||
if err != nil {
|
||||
next = renewJitter / 2
|
||||
next += time.Duration(pseudoRand.int63n(int64(next)))
|
||||
}
|
||||
dr.timer = time.AfterFunc(next, dr.renew)
|
||||
testDidRenewLoop(next, err)
|
||||
}
|
||||
|
||||
// updateState locks and replaces the relevant Manager.state item with the given
|
||||
// state. It additionally updates dr.key with the given state's key.
|
||||
func (dr *domainRenewal) updateState(state *certState) {
|
||||
dr.m.stateMu.Lock()
|
||||
defer dr.m.stateMu.Unlock()
|
||||
dr.key = state.key
|
||||
dr.m.state[dr.ck] = state
|
||||
}
|
||||
|
||||
// do is similar to Manager.createCert but it doesn't lock a Manager.state item.
|
||||
// Instead, it requests a new certificate independently and, upon success,
|
||||
// replaces dr.m.state item with a new one and updates cache for the given domain.
|
||||
//
|
||||
// It may lock and update the Manager.state if the expiration date of the currently
|
||||
// cached cert is far enough in the future.
|
||||
//
|
||||
// The returned value is a time interval after which the renewal should occur again.
|
||||
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
||||
// a race is likely unavoidable in a distributed environment
|
||||
// but we try nonetheless
|
||||
if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil {
|
||||
next := dr.next(tlscert.Leaf.NotAfter)
|
||||
if next > dr.m.renewBefore()+renewJitter {
|
||||
signer, ok := tlscert.PrivateKey.(crypto.Signer)
|
||||
if ok {
|
||||
state := &certState{
|
||||
key: signer,
|
||||
cert: tlscert.Certificate,
|
||||
leaf: tlscert.Leaf,
|
||||
}
|
||||
dr.updateState(state)
|
||||
return next, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
state := &certState{
|
||||
key: dr.key,
|
||||
cert: der,
|
||||
leaf: leaf,
|
||||
}
|
||||
tlscert, err := state.tlscert()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dr.updateState(state)
|
||||
return dr.next(leaf.NotAfter), nil
|
||||
}
|
||||
|
||||
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
|
||||
d := expiry.Sub(dr.m.now()) - dr.m.renewBefore()
|
||||
// add a bit of randomness to renew deadline
|
||||
n := pseudoRand.int63n(int64(renewJitter))
|
||||
d -= time.Duration(n)
|
||||
if d < 0 {
|
||||
return 0
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
var testDidRenewLoop = func(next time.Duration, err error) {}
|
||||
+321
@@ -0,0 +1,321 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"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 max = 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
|
||||
if d > max {
|
||||
return max
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// 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.NewRequest("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 RFC8555
|
||||
// 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 {
|
||||
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.NewRequest("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. It's set in version_go112.go.
|
||||
var packageVersion string
|
||||
|
||||
// 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, _ := ioutil.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)
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
// 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/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
_ "crypto/sha512" // need for EC keys
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// keyID is the account 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 = ""
|
||||
|
||||
// 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.
|
||||
//
|
||||
// If kid is non-empty, its quoted value is inserted in the protected head
|
||||
// as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted
|
||||
// as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive.
|
||||
//
|
||||
// See https://tools.ietf.org/html/rfc7515#section-7.
|
||||
func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, url string) ([]byte, error) {
|
||||
alg, sha := jwsHasher(key.Public())
|
||||
if alg == "" || !sha.Available() {
|
||||
return nil, ErrUnsupportedKey
|
||||
}
|
||||
var phead string
|
||||
switch kid {
|
||||
case noKeyID:
|
||||
jwk, err := jwkEncode(key.Public())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
phead = fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q,"url":%q}`, alg, jwk, nonce, url)
|
||||
default:
|
||||
phead = fmt.Sprintf(`{"alg":%q,"kid":%q,"nonce":%q,"url":%q}`, alg, kid, nonce, url)
|
||||
}
|
||||
phead = base64.RawURLEncoding.EncodeToString([]byte(phead))
|
||||
var payload string
|
||||
if claimset != noPayload {
|
||||
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 := struct {
|
||||
Protected string `json:"protected"`
|
||||
Payload string `json:"payload"`
|
||||
Sig string `json:"signature"`
|
||||
}{
|
||||
Protected: phead,
|
||||
Payload: payload,
|
||||
Sig: base64.RawURLEncoding.EncodeToString(sig),
|
||||
}
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
+392
@@ -0,0 +1,392 @@
|
||||
// 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"
|
||||
"io/ioutil"
|
||||
"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 {
|
||||
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 quivalent to c.Register but for CAs implementing RFC 8555.
|
||||
// It expects c.Discover to have already been called.
|
||||
// TODO: Implement externalAccountBinding.
|
||||
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"`
|
||||
}{
|
||||
Contact: acct.Contact,
|
||||
}
|
||||
if c.dir.Terms != "" {
|
||||
req.TermsAgreed = prompt(c.dir.Terms)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// updateGegRFC 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)
|
||||
}
|
||||
|
||||
// getGegRFC 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
|
||||
}
|
||||
|
||||
// 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 retrives 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}
|
||||
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}
|
||||
}
|
||||
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 := ioutil.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"
|
||||
}
|
||||
+548
@@ -0,0 +1,548 @@
|
||||
// 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"
|
||||
"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")
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, 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.
|
||||
//
|
||||
// The clients can still fetch the order object from CA using GetOrder
|
||||
// to inspect its state.
|
||||
type OrderError struct {
|
||||
OrderURL string
|
||||
Status string
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
// Term 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 RFC6844.
|
||||
CAA []string
|
||||
|
||||
// ExternalAccountRequired indicates that the CA requires for all account-related
|
||||
// requests to include external account binding information.
|
||||
ExternalAccountRequired bool
|
||||
}
|
||||
|
||||
// rfcCompliant reports whether the ACME server implements RFC 8555.
|
||||
// Note that some servers may have incomplete RFC implementation
|
||||
// even if the returned value is true.
|
||||
// If rfcCompliant reports false, the server most likely implements draft-02.
|
||||
func (d *Directory) rfcCompliant() bool {
|
||||
return d.OrderURL != ""
|
||||
}
|
||||
|
||||
// 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 RFC1123 Section 2.1 for IPv4 and in RFC5952 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
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (e *wireError) error(h http.Header) *Error {
|
||||
return &Error{
|
||||
StatusCode: e.Status,
|
||||
ProblemType: e.Type,
|
||||
Detail: e.Detail,
|
||||
Instance: e.Instance,
|
||||
Header: h,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 field of t is always overwritten for tls-sni challenge certs.
|
||||
func WithTemplate(t *x509.Certificate) CertOption {
|
||||
return (*certOptTemplate)(t)
|
||||
}
|
||||
|
||||
type certOptTemplate x509.Certificate
|
||||
|
||||
func (*certOptTemplate) privateCertOpt() {}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
|
||||
// +build go1.12
|
||||
|
||||
package acme
|
||||
|
||||
import "runtime/debug"
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
// 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 an 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) (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
|
||||
}
|
||||
var tmp [4]byte
|
||||
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 := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
|
||||
if _, err := io.ReadFull(r, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Each row is 4-byte aligned.
|
||||
if c.Width%4 != 0 {
|
||||
_, err := io.ReadFull(r, tmp[:4-c.Width%4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
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 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]
|
||||
}
|
||||
}
|
||||
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, err := decodeConfig(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch bpp {
|
||||
case 8:
|
||||
return decodePaletted(r, c, topDown)
|
||||
case 24:
|
||||
return decodeRGB(r, c, topDown)
|
||||
case 32:
|
||||
return decodeNRGBA(r, c, topDown)
|
||||
}
|
||||
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, err error) {
|
||||
// We only support those BMP images that are a BITMAPFILEHEADER
|
||||
// immediately followed by a BITMAPINFOHEADER.
|
||||
const (
|
||||
fileHeaderLen = 14
|
||||
infoHeaderLen = 40
|
||||
v4InfoHeaderLen = 108
|
||||
v5InfoHeaderLen = 124
|
||||
)
|
||||
var b [1024]byte
|
||||
if _, err := io.ReadFull(r, b[:fileHeaderLen+4]); err != nil {
|
||||
return image.Config{}, 0, false, err
|
||||
}
|
||||
if string(b[:2]) != "BM" {
|
||||
return image.Config{}, 0, 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, ErrUnsupported
|
||||
}
|
||||
if _, err := io.ReadFull(r, b[fileHeaderLen+4:fileHeaderLen+infoLen]); err != nil {
|
||||
return image.Config{}, 0, 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, 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 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, ErrUnsupported
|
||||
}
|
||||
switch bpp {
|
||||
case 8:
|
||||
if offset != fileHeaderLen+infoLen+256*4 {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
_, err = io.ReadFull(r, b[:256*4])
|
||||
if err != nil {
|
||||
return image.Config{}, 0, false, err
|
||||
}
|
||||
pcm := make(color.Palette, 256)
|
||||
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}, 8, topDown, nil
|
||||
case 24:
|
||||
if offset != fileHeaderLen+infoLen {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, nil
|
||||
case 32:
|
||||
if offset != fileHeaderLen+infoLen {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, nil
|
||||
}
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
|
||||
func init() {
|
||||
image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig)
|
||||
}
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
// 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)
|
||||
}
|
||||
+697
@@ -0,0 +1,697 @@
|
||||
// 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 (
|
||||
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
|
||||
)
|
||||
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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. 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
|
||||
|
||||
// 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 {
|
||||
if z.readErr = z.finishDecode(); z.readErr != nil {
|
||||
break
|
||||
}
|
||||
z.readErr = io.EOF
|
||||
break
|
||||
}
|
||||
if z.readErr = z.decodeRow(); z.readErr != nil {
|
||||
break
|
||||
}
|
||||
z.rowsRemaining--
|
||||
}
|
||||
|
||||
// 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() error {
|
||||
numberOfEOLs := 0
|
||||
switch z.subFormat {
|
||||
case Group3:
|
||||
// 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:
|
||||
// The stream ends with two EOL's, the first of which is possibly
|
||||
// byte-aligned.
|
||||
numberOfEOLs = 2
|
||||
if err := z.decodeEOL(); err == nil {
|
||||
numberOfEOLs--
|
||||
} else if err == errInvalidCode {
|
||||
// Try again, this time starting from a byte boundary.
|
||||
z.br.alignToByteBoundary()
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
default:
|
||||
return errUnsupportedSubFormat
|
||||
}
|
||||
|
||||
for ; numberOfEOLs > 0; numberOfEOLs-- {
|
||||
if err := z.decodeEOL(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (z *reader) decodeEOL() error {
|
||||
// TODO: EOL doesn't have to be in the modeDecodeTable. It could be in its
|
||||
// own table, or we could just hard-code it, especially if we might need to
|
||||
// cater for optional byte-alignment, or an arbitrary number (potentially
|
||||
// more than 8) of 0-valued padding bits.
|
||||
if mode, err := decode(&z.br, modeDecodeTable[:]); err != nil {
|
||||
return err
|
||||
} else if mode != modeEOL {
|
||||
return errMissingEOL
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (z *reader) decodeRow() 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
|
||||
}
|
||||
}
|
||||
return z.decodeEOL()
|
||||
|
||||
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(); err != nil {
|
||||
return err
|
||||
}
|
||||
z.curr, z.prev = nil, z.curr
|
||||
}
|
||||
|
||||
if err := z.finishDecode(); 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.
|
||||
func NewReader(r io.Reader, order Order, sf SubFormat, width int, height int, opts *Options) io.Reader {
|
||||
readErr := error(nil)
|
||||
if (width < 0) || (height < 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,
|
||||
}
|
||||
}
|
||||
+989
@@ -0,0 +1,989 @@
|
||||
// generated by "go run gen.go". DO NOT EDIT.
|
||||
|
||||
package ccitt
|
||||
|
||||
// Each decodeTable is represented by an array of [2]int16's: a binary tree.
|
||||
// Each array element (other than element 0, which means invalid) is a branch
|
||||
// node in that tree. The root node is always element 1 (the second element).
|
||||
//
|
||||
// To walk the tree, look at the next bit in the bit stream, using it to select
|
||||
// the first or second element of the [2]int16. If that int16 is 0, we have an
|
||||
// invalid code. If it is positive, go to that branch node. If it is negative,
|
||||
// then we have a leaf node, whose value is the bitwise complement (the ^
|
||||
// operator) of that int16.
|
||||
//
|
||||
// Comments above each decodeTable also show the same structure visually. The
|
||||
// "b123" lines show the 123'rd branch node. The "=XXXXX" lines show an invalid
|
||||
// code. The "=v1234" lines show a leaf node with value 1234. When reading the
|
||||
// bit stream, a 0 or 1 bit means to go up or down, as you move left to right.
|
||||
//
|
||||
// For example, in modeDecodeTable, branch node b005 is three steps up from the
|
||||
// root node, meaning that we have already seen "000". If the next bit is "0"
|
||||
// then we move to branch node b006. Otherwise, the next bit is "1", and we
|
||||
// move to the leaf node v0000 (also known as the modePass constant). Indeed,
|
||||
// the bits that encode modePass are "0001".
|
||||
//
|
||||
// Tables 1, 2 and 3 come from the "ITU-T Recommendation T.6: FACSIMILE CODING
|
||||
// SCHEMES AND CODING CONTROL FUNCTIONS FOR GROUP 4 FACSIMILE APPARATUS"
|
||||
// specification:
|
||||
//
|
||||
// https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.6-198811-I!!PDF-E&type=items
|
||||
|
||||
// modeDecodeTable represents Table 1 and the End-of-Line code.
|
||||
//
|
||||
// +=XXXXX
|
||||
// b015 +-+
|
||||
// | +=v0010
|
||||
// b014 +-+
|
||||
// | +=XXXXX
|
||||
// b013 +-+
|
||||
// | +=XXXXX
|
||||
// b012 +-+
|
||||
// | +=XXXXX
|
||||
// b011 +-+
|
||||
// | +=XXXXX
|
||||
// b009 +-+
|
||||
// | +=v0009
|
||||
// b007 +-+
|
||||
// | | +=v0008
|
||||
// b010 | +-+
|
||||
// | +=v0005
|
||||
// b006 +-+
|
||||
// | | +=v0007
|
||||
// b008 | +-+
|
||||
// | +=v0004
|
||||
// b005 +-+
|
||||
// | +=v0000
|
||||
// b003 +-+
|
||||
// | +=v0001
|
||||
// b002 +-+
|
||||
// | | +=v0006
|
||||
// b004 | +-+
|
||||
// | +=v0003
|
||||
// b001 +-+
|
||||
// +=v0002
|
||||
var modeDecodeTable = [...][2]int16{
|
||||
0: {0, 0},
|
||||
1: {2, ^2},
|
||||
2: {3, 4},
|
||||
3: {5, ^1},
|
||||
4: {^6, ^3},
|
||||
5: {6, ^0},
|
||||
6: {7, 8},
|
||||
7: {9, 10},
|
||||
8: {^7, ^4},
|
||||
9: {11, ^9},
|
||||
10: {^8, ^5},
|
||||
11: {12, 0},
|
||||
12: {13, 0},
|
||||
13: {14, 0},
|
||||
14: {15, 0},
|
||||
15: {0, ^10},
|
||||
}
|
||||
|
||||
// whiteDecodeTable represents Tables 2 and 3 for a white run.
|
||||
//
|
||||
// +=XXXXX
|
||||
// b059 +-+
|
||||
// | | +=v1792
|
||||
// b096 | | +-+
|
||||
// | | | | +=v1984
|
||||
// b100 | | | +-+
|
||||
// | | | +=v2048
|
||||
// b094 | | +-+
|
||||
// | | | | +=v2112
|
||||
// b101 | | | | +-+
|
||||
// | | | | | +=v2176
|
||||
// b097 | | | +-+
|
||||
// | | | | +=v2240
|
||||
// b102 | | | +-+
|
||||
// | | | +=v2304
|
||||
// b085 | +-+
|
||||
// | | +=v1856
|
||||
// b098 | | +-+
|
||||
// | | | +=v1920
|
||||
// b095 | +-+
|
||||
// | | +=v2368
|
||||
// b103 | | +-+
|
||||
// | | | +=v2432
|
||||
// b099 | +-+
|
||||
// | | +=v2496
|
||||
// b104 | +-+
|
||||
// | +=v2560
|
||||
// b040 +-+
|
||||
// | | +=v0029
|
||||
// b060 | +-+
|
||||
// | +=v0030
|
||||
// b026 +-+
|
||||
// | | +=v0045
|
||||
// b061 | | +-+
|
||||
// | | | +=v0046
|
||||
// b041 | +-+
|
||||
// | +=v0022
|
||||
// b016 +-+
|
||||
// | | +=v0023
|
||||
// b042 | | +-+
|
||||
// | | | | +=v0047
|
||||
// b062 | | | +-+
|
||||
// | | | +=v0048
|
||||
// b027 | +-+
|
||||
// | +=v0013
|
||||
// b008 +-+
|
||||
// | | +=v0020
|
||||
// b043 | | +-+
|
||||
// | | | | +=v0033
|
||||
// b063 | | | +-+
|
||||
// | | | +=v0034
|
||||
// b028 | | +-+
|
||||
// | | | | +=v0035
|
||||
// b064 | | | | +-+
|
||||
// | | | | | +=v0036
|
||||
// b044 | | | +-+
|
||||
// | | | | +=v0037
|
||||
// b065 | | | +-+
|
||||
// | | | +=v0038
|
||||
// b017 | +-+
|
||||
// | | +=v0019
|
||||
// b045 | | +-+
|
||||
// | | | | +=v0031
|
||||
// b066 | | | +-+
|
||||
// | | | +=v0032
|
||||
// b029 | +-+
|
||||
// | +=v0001
|
||||
// b004 +-+
|
||||
// | | +=v0012
|
||||
// b030 | | +-+
|
||||
// | | | | +=v0053
|
||||
// b067 | | | | +-+
|
||||
// | | | | | +=v0054
|
||||
// b046 | | | +-+
|
||||
// | | | +=v0026
|
||||
// b018 | | +-+
|
||||
// | | | | +=v0039
|
||||
// b068 | | | | +-+
|
||||
// | | | | | +=v0040
|
||||
// b047 | | | | +-+
|
||||
// | | | | | | +=v0041
|
||||
// b069 | | | | | +-+
|
||||
// | | | | | +=v0042
|
||||
// b031 | | | +-+
|
||||
// | | | | +=v0043
|
||||
// b070 | | | | +-+
|
||||
// | | | | | +=v0044
|
||||
// b048 | | | +-+
|
||||
// | | | +=v0021
|
||||
// b009 | +-+
|
||||
// | | +=v0028
|
||||
// b049 | | +-+
|
||||
// | | | | +=v0061
|
||||
// b071 | | | +-+
|
||||
// | | | +=v0062
|
||||
// b032 | | +-+
|
||||
// | | | | +=v0063
|
||||
// b072 | | | | +-+
|
||||
// | | | | | +=v0000
|
||||
// b050 | | | +-+
|
||||
// | | | | +=v0320
|
||||
// b073 | | | +-+
|
||||
// | | | +=v0384
|
||||
// b019 | +-+
|
||||
// | +=v0010
|
||||
// b002 +-+
|
||||
// | | +=v0011
|
||||
// b020 | | +-+
|
||||
// | | | | +=v0027
|
||||
// b051 | | | | +-+
|
||||
// | | | | | | +=v0059
|
||||
// b074 | | | | | +-+
|
||||
// | | | | | +=v0060
|
||||
// b033 | | | +-+
|
||||
// | | | | +=v1472
|
||||
// b086 | | | | +-+
|
||||
// | | | | | +=v1536
|
||||
// b075 | | | | +-+
|
||||
// | | | | | | +=v1600
|
||||
// b087 | | | | | +-+
|
||||
// | | | | | +=v1728
|
||||
// b052 | | | +-+
|
||||
// | | | +=v0018
|
||||
// b010 | | +-+
|
||||
// | | | | +=v0024
|
||||
// b053 | | | | +-+
|
||||
// | | | | | | +=v0049
|
||||
// b076 | | | | | +-+
|
||||
// | | | | | +=v0050
|
||||
// b034 | | | | +-+
|
||||
// | | | | | | +=v0051
|
||||
// b077 | | | | | | +-+
|
||||
// | | | | | | | +=v0052
|
||||
// b054 | | | | | +-+
|
||||
// | | | | | +=v0025
|
||||
// b021 | | | +-+
|
||||
// | | | | +=v0055
|
||||
// b078 | | | | +-+
|
||||
// | | | | | +=v0056
|
||||
// b055 | | | | +-+
|
||||
// | | | | | | +=v0057
|
||||
// b079 | | | | | +-+
|
||||
// | | | | | +=v0058
|
||||
// b035 | | | +-+
|
||||
// | | | +=v0192
|
||||
// b005 | +-+
|
||||
// | | +=v1664
|
||||
// b036 | | +-+
|
||||
// | | | | +=v0448
|
||||
// b080 | | | | +-+
|
||||
// | | | | | +=v0512
|
||||
// b056 | | | +-+
|
||||
// | | | | +=v0704
|
||||
// b088 | | | | +-+
|
||||
// | | | | | +=v0768
|
||||
// b081 | | | +-+
|
||||
// | | | +=v0640
|
||||
// b022 | | +-+
|
||||
// | | | | +=v0576
|
||||
// b082 | | | | +-+
|
||||
// | | | | | | +=v0832
|
||||
// b089 | | | | | +-+
|
||||
// | | | | | +=v0896
|
||||
// b057 | | | | +-+
|
||||
// | | | | | | +=v0960
|
||||
// b090 | | | | | | +-+
|
||||
// | | | | | | | +=v1024
|
||||
// b083 | | | | | +-+
|
||||
// | | | | | | +=v1088
|
||||
// b091 | | | | | +-+
|
||||
// | | | | | +=v1152
|
||||
// b037 | | | +-+
|
||||
// | | | | +=v1216
|
||||
// b092 | | | | +-+
|
||||
// | | | | | +=v1280
|
||||
// b084 | | | | +-+
|
||||
// | | | | | | +=v1344
|
||||
// b093 | | | | | +-+
|
||||
// | | | | | +=v1408
|
||||
// b058 | | | +-+
|
||||
// | | | +=v0256
|
||||
// b011 | +-+
|
||||
// | +=v0002
|
||||
// b001 +-+
|
||||
// | +=v0003
|
||||
// b012 | +-+
|
||||
// | | | +=v0128
|
||||
// b023 | | +-+
|
||||
// | | +=v0008
|
||||
// b006 | +-+
|
||||
// | | | +=v0009
|
||||
// b024 | | | +-+
|
||||
// | | | | | +=v0016
|
||||
// b038 | | | | +-+
|
||||
// | | | | +=v0017
|
||||
// b013 | | +-+
|
||||
// | | +=v0004
|
||||
// b003 +-+
|
||||
// | +=v0005
|
||||
// b014 | +-+
|
||||
// | | | +=v0014
|
||||
// b039 | | | +-+
|
||||
// | | | | +=v0015
|
||||
// b025 | | +-+
|
||||
// | | +=v0064
|
||||
// b007 +-+
|
||||
// | +=v0006
|
||||
// b015 +-+
|
||||
// +=v0007
|
||||
var whiteDecodeTable = [...][2]int16{
|
||||
0: {0, 0},
|
||||
1: {2, 3},
|
||||
2: {4, 5},
|
||||
3: {6, 7},
|
||||
4: {8, 9},
|
||||
5: {10, 11},
|
||||
6: {12, 13},
|
||||
7: {14, 15},
|
||||
8: {16, 17},
|
||||
9: {18, 19},
|
||||
10: {20, 21},
|
||||
11: {22, ^2},
|
||||
12: {^3, 23},
|
||||
13: {24, ^4},
|
||||
14: {^5, 25},
|
||||
15: {^6, ^7},
|
||||
16: {26, 27},
|
||||
17: {28, 29},
|
||||
18: {30, 31},
|
||||
19: {32, ^10},
|
||||
20: {^11, 33},
|
||||
21: {34, 35},
|
||||
22: {36, 37},
|
||||
23: {^128, ^8},
|
||||
24: {^9, 38},
|
||||
25: {39, ^64},
|
||||
26: {40, 41},
|
||||
27: {42, ^13},
|
||||
28: {43, 44},
|
||||
29: {45, ^1},
|
||||
30: {^12, 46},
|
||||
31: {47, 48},
|
||||
32: {49, 50},
|
||||
33: {51, 52},
|
||||
34: {53, 54},
|
||||
35: {55, ^192},
|
||||
36: {^1664, 56},
|
||||
37: {57, 58},
|
||||
38: {^16, ^17},
|
||||
39: {^14, ^15},
|
||||
40: {59, 60},
|
||||
41: {61, ^22},
|
||||
42: {^23, 62},
|
||||
43: {^20, 63},
|
||||
44: {64, 65},
|
||||
45: {^19, 66},
|
||||
46: {67, ^26},
|
||||
47: {68, 69},
|
||||
48: {70, ^21},
|
||||
49: {^28, 71},
|
||||
50: {72, 73},
|
||||
51: {^27, 74},
|
||||
52: {75, ^18},
|
||||
53: {^24, 76},
|
||||
54: {77, ^25},
|
||||
55: {78, 79},
|
||||
56: {80, 81},
|
||||
57: {82, 83},
|
||||
58: {84, ^256},
|
||||
59: {0, 85},
|
||||
60: {^29, ^30},
|
||||
61: {^45, ^46},
|
||||
62: {^47, ^48},
|
||||
63: {^33, ^34},
|
||||
64: {^35, ^36},
|
||||
65: {^37, ^38},
|
||||
66: {^31, ^32},
|
||||
67: {^53, ^54},
|
||||
68: {^39, ^40},
|
||||
69: {^41, ^42},
|
||||
70: {^43, ^44},
|
||||
71: {^61, ^62},
|
||||
72: {^63, ^0},
|
||||
73: {^320, ^384},
|
||||
74: {^59, ^60},
|
||||
75: {86, 87},
|
||||
76: {^49, ^50},
|
||||
77: {^51, ^52},
|
||||
78: {^55, ^56},
|
||||
79: {^57, ^58},
|
||||
80: {^448, ^512},
|
||||
81: {88, ^640},
|
||||
82: {^576, 89},
|
||||
83: {90, 91},
|
||||
84: {92, 93},
|
||||
85: {94, 95},
|
||||
86: {^1472, ^1536},
|
||||
87: {^1600, ^1728},
|
||||
88: {^704, ^768},
|
||||
89: {^832, ^896},
|
||||
90: {^960, ^1024},
|
||||
91: {^1088, ^1152},
|
||||
92: {^1216, ^1280},
|
||||
93: {^1344, ^1408},
|
||||
94: {96, 97},
|
||||
95: {98, 99},
|
||||
96: {^1792, 100},
|
||||
97: {101, 102},
|
||||
98: {^1856, ^1920},
|
||||
99: {103, 104},
|
||||
100: {^1984, ^2048},
|
||||
101: {^2112, ^2176},
|
||||
102: {^2240, ^2304},
|
||||
103: {^2368, ^2432},
|
||||
104: {^2496, ^2560},
|
||||
}
|
||||
|
||||
// blackDecodeTable represents Tables 2 and 3 for a black run.
|
||||
//
|
||||
// +=XXXXX
|
||||
// b017 +-+
|
||||
// | | +=v1792
|
||||
// b042 | | +-+
|
||||
// | | | | +=v1984
|
||||
// b063 | | | +-+
|
||||
// | | | +=v2048
|
||||
// b029 | | +-+
|
||||
// | | | | +=v2112
|
||||
// b064 | | | | +-+
|
||||
// | | | | | +=v2176
|
||||
// b043 | | | +-+
|
||||
// | | | | +=v2240
|
||||
// b065 | | | +-+
|
||||
// | | | +=v2304
|
||||
// b022 | +-+
|
||||
// | | +=v1856
|
||||
// b044 | | +-+
|
||||
// | | | +=v1920
|
||||
// b030 | +-+
|
||||
// | | +=v2368
|
||||
// b066 | | +-+
|
||||
// | | | +=v2432
|
||||
// b045 | +-+
|
||||
// | | +=v2496
|
||||
// b067 | +-+
|
||||
// | +=v2560
|
||||
// b013 +-+
|
||||
// | | +=v0018
|
||||
// b031 | | +-+
|
||||
// | | | | +=v0052
|
||||
// b068 | | | | +-+
|
||||
// | | | | | | +=v0640
|
||||
// b095 | | | | | +-+
|
||||
// | | | | | +=v0704
|
||||
// b046 | | | +-+
|
||||
// | | | | +=v0768
|
||||
// b096 | | | | +-+
|
||||
// | | | | | +=v0832
|
||||
// b069 | | | +-+
|
||||
// | | | +=v0055
|
||||
// b023 | | +-+
|
||||
// | | | | +=v0056
|
||||
// b070 | | | | +-+
|
||||
// | | | | | | +=v1280
|
||||
// b097 | | | | | +-+
|
||||
// | | | | | +=v1344
|
||||
// b047 | | | | +-+
|
||||
// | | | | | | +=v1408
|
||||
// b098 | | | | | | +-+
|
||||
// | | | | | | | +=v1472
|
||||
// b071 | | | | | +-+
|
||||
// | | | | | +=v0059
|
||||
// b032 | | | +-+
|
||||
// | | | | +=v0060
|
||||
// b072 | | | | +-+
|
||||
// | | | | | | +=v1536
|
||||
// b099 | | | | | +-+
|
||||
// | | | | | +=v1600
|
||||
// b048 | | | +-+
|
||||
// | | | +=v0024
|
||||
// b018 | +-+
|
||||
// | | +=v0025
|
||||
// b049 | | +-+
|
||||
// | | | | +=v1664
|
||||
// b100 | | | | +-+
|
||||
// | | | | | +=v1728
|
||||
// b073 | | | +-+
|
||||
// | | | +=v0320
|
||||
// b033 | | +-+
|
||||
// | | | | +=v0384
|
||||
// b074 | | | | +-+
|
||||
// | | | | | +=v0448
|
||||
// b050 | | | +-+
|
||||
// | | | | +=v0512
|
||||
// b101 | | | | +-+
|
||||
// | | | | | +=v0576
|
||||
// b075 | | | +-+
|
||||
// | | | +=v0053
|
||||
// b024 | +-+
|
||||
// | | +=v0054
|
||||
// b076 | | +-+
|
||||
// | | | | +=v0896
|
||||
// b102 | | | +-+
|
||||
// | | | +=v0960
|
||||
// b051 | | +-+
|
||||
// | | | | +=v1024
|
||||
// b103 | | | | +-+
|
||||
// | | | | | +=v1088
|
||||
// b077 | | | +-+
|
||||
// | | | | +=v1152
|
||||
// b104 | | | +-+
|
||||
// | | | +=v1216
|
||||
// b034 | +-+
|
||||
// | +=v0064
|
||||
// b010 +-+
|
||||
// | | +=v0013
|
||||
// b019 | | +-+
|
||||
// | | | | +=v0023
|
||||
// b052 | | | | +-+
|
||||
// | | | | | | +=v0050
|
||||
// b078 | | | | | +-+
|
||||
// | | | | | +=v0051
|
||||
// b035 | | | | +-+
|
||||
// | | | | | | +=v0044
|
||||
// b079 | | | | | | +-+
|
||||
// | | | | | | | +=v0045
|
||||
// b053 | | | | | +-+
|
||||
// | | | | | | +=v0046
|
||||
// b080 | | | | | +-+
|
||||
// | | | | | +=v0047
|
||||
// b025 | | | +-+
|
||||
// | | | | +=v0057
|
||||
// b081 | | | | +-+
|
||||
// | | | | | +=v0058
|
||||
// b054 | | | | +-+
|
||||
// | | | | | | +=v0061
|
||||
// b082 | | | | | +-+
|
||||
// | | | | | +=v0256
|
||||
// b036 | | | +-+
|
||||
// | | | +=v0016
|
||||
// b014 | +-+
|
||||
// | | +=v0017
|
||||
// b037 | | +-+
|
||||
// | | | | +=v0048
|
||||
// b083 | | | | +-+
|
||||
// | | | | | +=v0049
|
||||
// b055 | | | +-+
|
||||
// | | | | +=v0062
|
||||
// b084 | | | +-+
|
||||
// | | | +=v0063
|
||||
// b026 | | +-+
|
||||
// | | | | +=v0030
|
||||
// b085 | | | | +-+
|
||||
// | | | | | +=v0031
|
||||
// b056 | | | | +-+
|
||||
// | | | | | | +=v0032
|
||||
// b086 | | | | | +-+
|
||||
// | | | | | +=v0033
|
||||
// b038 | | | +-+
|
||||
// | | | | +=v0040
|
||||
// b087 | | | | +-+
|
||||
// | | | | | +=v0041
|
||||
// b057 | | | +-+
|
||||
// | | | +=v0022
|
||||
// b020 | +-+
|
||||
// | +=v0014
|
||||
// b008 +-+
|
||||
// | | +=v0010
|
||||
// b015 | | +-+
|
||||
// | | | +=v0011
|
||||
// b011 | +-+
|
||||
// | | +=v0015
|
||||
// b027 | | +-+
|
||||
// | | | | +=v0128
|
||||
// b088 | | | | +-+
|
||||
// | | | | | +=v0192
|
||||
// b058 | | | | +-+
|
||||
// | | | | | | +=v0026
|
||||
// b089 | | | | | +-+
|
||||
// | | | | | +=v0027
|
||||
// b039 | | | +-+
|
||||
// | | | | +=v0028
|
||||
// b090 | | | | +-+
|
||||
// | | | | | +=v0029
|
||||
// b059 | | | +-+
|
||||
// | | | +=v0019
|
||||
// b021 | | +-+
|
||||
// | | | | +=v0020
|
||||
// b060 | | | | +-+
|
||||
// | | | | | | +=v0034
|
||||
// b091 | | | | | +-+
|
||||
// | | | | | +=v0035
|
||||
// b040 | | | | +-+
|
||||
// | | | | | | +=v0036
|
||||
// b092 | | | | | | +-+
|
||||
// | | | | | | | +=v0037
|
||||
// b061 | | | | | +-+
|
||||
// | | | | | | +=v0038
|
||||
// b093 | | | | | +-+
|
||||
// | | | | | +=v0039
|
||||
// b028 | | | +-+
|
||||
// | | | | +=v0021
|
||||
// b062 | | | | +-+
|
||||
// | | | | | | +=v0042
|
||||
// b094 | | | | | +-+
|
||||
// | | | | | +=v0043
|
||||
// b041 | | | +-+
|
||||
// | | | +=v0000
|
||||
// b016 | +-+
|
||||
// | +=v0012
|
||||
// b006 +-+
|
||||
// | | +=v0009
|
||||
// b012 | | +-+
|
||||
// | | | +=v0008
|
||||
// b009 | +-+
|
||||
// | +=v0007
|
||||
// b004 +-+
|
||||
// | | +=v0006
|
||||
// b007 | +-+
|
||||
// | +=v0005
|
||||
// b002 +-+
|
||||
// | | +=v0001
|
||||
// b005 | +-+
|
||||
// | +=v0004
|
||||
// b001 +-+
|
||||
// | +=v0003
|
||||
// b003 +-+
|
||||
// +=v0002
|
||||
var blackDecodeTable = [...][2]int16{
|
||||
0: {0, 0},
|
||||
1: {2, 3},
|
||||
2: {4, 5},
|
||||
3: {^3, ^2},
|
||||
4: {6, 7},
|
||||
5: {^1, ^4},
|
||||
6: {8, 9},
|
||||
7: {^6, ^5},
|
||||
8: {10, 11},
|
||||
9: {12, ^7},
|
||||
10: {13, 14},
|
||||
11: {15, 16},
|
||||
12: {^9, ^8},
|
||||
13: {17, 18},
|
||||
14: {19, 20},
|
||||
15: {^10, ^11},
|
||||
16: {21, ^12},
|
||||
17: {0, 22},
|
||||
18: {23, 24},
|
||||
19: {^13, 25},
|
||||
20: {26, ^14},
|
||||
21: {27, 28},
|
||||
22: {29, 30},
|
||||
23: {31, 32},
|
||||
24: {33, 34},
|
||||
25: {35, 36},
|
||||
26: {37, 38},
|
||||
27: {^15, 39},
|
||||
28: {40, 41},
|
||||
29: {42, 43},
|
||||
30: {44, 45},
|
||||
31: {^18, 46},
|
||||
32: {47, 48},
|
||||
33: {49, 50},
|
||||
34: {51, ^64},
|
||||
35: {52, 53},
|
||||
36: {54, ^16},
|
||||
37: {^17, 55},
|
||||
38: {56, 57},
|
||||
39: {58, 59},
|
||||
40: {60, 61},
|
||||
41: {62, ^0},
|
||||
42: {^1792, 63},
|
||||
43: {64, 65},
|
||||
44: {^1856, ^1920},
|
||||
45: {66, 67},
|
||||
46: {68, 69},
|
||||
47: {70, 71},
|
||||
48: {72, ^24},
|
||||
49: {^25, 73},
|
||||
50: {74, 75},
|
||||
51: {76, 77},
|
||||
52: {^23, 78},
|
||||
53: {79, 80},
|
||||
54: {81, 82},
|
||||
55: {83, 84},
|
||||
56: {85, 86},
|
||||
57: {87, ^22},
|
||||
58: {88, 89},
|
||||
59: {90, ^19},
|
||||
60: {^20, 91},
|
||||
61: {92, 93},
|
||||
62: {^21, 94},
|
||||
63: {^1984, ^2048},
|
||||
64: {^2112, ^2176},
|
||||
65: {^2240, ^2304},
|
||||
66: {^2368, ^2432},
|
||||
67: {^2496, ^2560},
|
||||
68: {^52, 95},
|
||||
69: {96, ^55},
|
||||
70: {^56, 97},
|
||||
71: {98, ^59},
|
||||
72: {^60, 99},
|
||||
73: {100, ^320},
|
||||
74: {^384, ^448},
|
||||
75: {101, ^53},
|
||||
76: {^54, 102},
|
||||
77: {103, 104},
|
||||
78: {^50, ^51},
|
||||
79: {^44, ^45},
|
||||
80: {^46, ^47},
|
||||
81: {^57, ^58},
|
||||
82: {^61, ^256},
|
||||
83: {^48, ^49},
|
||||
84: {^62, ^63},
|
||||
85: {^30, ^31},
|
||||
86: {^32, ^33},
|
||||
87: {^40, ^41},
|
||||
88: {^128, ^192},
|
||||
89: {^26, ^27},
|
||||
90: {^28, ^29},
|
||||
91: {^34, ^35},
|
||||
92: {^36, ^37},
|
||||
93: {^38, ^39},
|
||||
94: {^42, ^43},
|
||||
95: {^640, ^704},
|
||||
96: {^768, ^832},
|
||||
97: {^1280, ^1344},
|
||||
98: {^1408, ^1472},
|
||||
99: {^1536, ^1600},
|
||||
100: {^1664, ^1728},
|
||||
101: {^512, ^576},
|
||||
102: {^896, ^960},
|
||||
103: {^1024, ^1088},
|
||||
104: {^1152, ^1216},
|
||||
}
|
||||
|
||||
const maxCodeLength = 13
|
||||
|
||||
// Each encodeTable is represented by an array of bitStrings.
|
||||
|
||||
// bitString is a pair of uint32 values representing a bit code.
|
||||
// The nBits low bits of bits make up the actual bit code.
|
||||
// Eg. bitString{0x0004, 8} represents the bitcode "00000100".
|
||||
type bitString struct {
|
||||
bits uint32
|
||||
nBits uint32
|
||||
}
|
||||
|
||||
// modeEncodeTable represents Table 1 and the End-of-Line code.
|
||||
var modeEncodeTable = [...]bitString{
|
||||
0: {0x0001, 4}, // "0001"
|
||||
1: {0x0001, 3}, // "001"
|
||||
2: {0x0001, 1}, // "1"
|
||||
3: {0x0003, 3}, // "011"
|
||||
4: {0x0003, 6}, // "000011"
|
||||
5: {0x0003, 7}, // "0000011"
|
||||
6: {0x0002, 3}, // "010"
|
||||
7: {0x0002, 6}, // "000010"
|
||||
8: {0x0002, 7}, // "0000010"
|
||||
9: {0x0001, 7}, // "0000001"
|
||||
10: {0x0001, 12}, // "000000000001"
|
||||
}
|
||||
|
||||
// whiteEncodeTable2 represents Table 2 for a white run.
|
||||
var whiteEncodeTable2 = [...]bitString{
|
||||
0: {0x0035, 8}, // "00110101"
|
||||
1: {0x0007, 6}, // "000111"
|
||||
2: {0x0007, 4}, // "0111"
|
||||
3: {0x0008, 4}, // "1000"
|
||||
4: {0x000b, 4}, // "1011"
|
||||
5: {0x000c, 4}, // "1100"
|
||||
6: {0x000e, 4}, // "1110"
|
||||
7: {0x000f, 4}, // "1111"
|
||||
8: {0x0013, 5}, // "10011"
|
||||
9: {0x0014, 5}, // "10100"
|
||||
10: {0x0007, 5}, // "00111"
|
||||
11: {0x0008, 5}, // "01000"
|
||||
12: {0x0008, 6}, // "001000"
|
||||
13: {0x0003, 6}, // "000011"
|
||||
14: {0x0034, 6}, // "110100"
|
||||
15: {0x0035, 6}, // "110101"
|
||||
16: {0x002a, 6}, // "101010"
|
||||
17: {0x002b, 6}, // "101011"
|
||||
18: {0x0027, 7}, // "0100111"
|
||||
19: {0x000c, 7}, // "0001100"
|
||||
20: {0x0008, 7}, // "0001000"
|
||||
21: {0x0017, 7}, // "0010111"
|
||||
22: {0x0003, 7}, // "0000011"
|
||||
23: {0x0004, 7}, // "0000100"
|
||||
24: {0x0028, 7}, // "0101000"
|
||||
25: {0x002b, 7}, // "0101011"
|
||||
26: {0x0013, 7}, // "0010011"
|
||||
27: {0x0024, 7}, // "0100100"
|
||||
28: {0x0018, 7}, // "0011000"
|
||||
29: {0x0002, 8}, // "00000010"
|
||||
30: {0x0003, 8}, // "00000011"
|
||||
31: {0x001a, 8}, // "00011010"
|
||||
32: {0x001b, 8}, // "00011011"
|
||||
33: {0x0012, 8}, // "00010010"
|
||||
34: {0x0013, 8}, // "00010011"
|
||||
35: {0x0014, 8}, // "00010100"
|
||||
36: {0x0015, 8}, // "00010101"
|
||||
37: {0x0016, 8}, // "00010110"
|
||||
38: {0x0017, 8}, // "00010111"
|
||||
39: {0x0028, 8}, // "00101000"
|
||||
40: {0x0029, 8}, // "00101001"
|
||||
41: {0x002a, 8}, // "00101010"
|
||||
42: {0x002b, 8}, // "00101011"
|
||||
43: {0x002c, 8}, // "00101100"
|
||||
44: {0x002d, 8}, // "00101101"
|
||||
45: {0x0004, 8}, // "00000100"
|
||||
46: {0x0005, 8}, // "00000101"
|
||||
47: {0x000a, 8}, // "00001010"
|
||||
48: {0x000b, 8}, // "00001011"
|
||||
49: {0x0052, 8}, // "01010010"
|
||||
50: {0x0053, 8}, // "01010011"
|
||||
51: {0x0054, 8}, // "01010100"
|
||||
52: {0x0055, 8}, // "01010101"
|
||||
53: {0x0024, 8}, // "00100100"
|
||||
54: {0x0025, 8}, // "00100101"
|
||||
55: {0x0058, 8}, // "01011000"
|
||||
56: {0x0059, 8}, // "01011001"
|
||||
57: {0x005a, 8}, // "01011010"
|
||||
58: {0x005b, 8}, // "01011011"
|
||||
59: {0x004a, 8}, // "01001010"
|
||||
60: {0x004b, 8}, // "01001011"
|
||||
61: {0x0032, 8}, // "00110010"
|
||||
62: {0x0033, 8}, // "00110011"
|
||||
63: {0x0034, 8}, // "00110100"
|
||||
}
|
||||
|
||||
// whiteEncodeTable3 represents Table 3 for a white run.
|
||||
var whiteEncodeTable3 = [...]bitString{
|
||||
0: {0x001b, 5}, // "11011"
|
||||
1: {0x0012, 5}, // "10010"
|
||||
2: {0x0017, 6}, // "010111"
|
||||
3: {0x0037, 7}, // "0110111"
|
||||
4: {0x0036, 8}, // "00110110"
|
||||
5: {0x0037, 8}, // "00110111"
|
||||
6: {0x0064, 8}, // "01100100"
|
||||
7: {0x0065, 8}, // "01100101"
|
||||
8: {0x0068, 8}, // "01101000"
|
||||
9: {0x0067, 8}, // "01100111"
|
||||
10: {0x00cc, 9}, // "011001100"
|
||||
11: {0x00cd, 9}, // "011001101"
|
||||
12: {0x00d2, 9}, // "011010010"
|
||||
13: {0x00d3, 9}, // "011010011"
|
||||
14: {0x00d4, 9}, // "011010100"
|
||||
15: {0x00d5, 9}, // "011010101"
|
||||
16: {0x00d6, 9}, // "011010110"
|
||||
17: {0x00d7, 9}, // "011010111"
|
||||
18: {0x00d8, 9}, // "011011000"
|
||||
19: {0x00d9, 9}, // "011011001"
|
||||
20: {0x00da, 9}, // "011011010"
|
||||
21: {0x00db, 9}, // "011011011"
|
||||
22: {0x0098, 9}, // "010011000"
|
||||
23: {0x0099, 9}, // "010011001"
|
||||
24: {0x009a, 9}, // "010011010"
|
||||
25: {0x0018, 6}, // "011000"
|
||||
26: {0x009b, 9}, // "010011011"
|
||||
27: {0x0008, 11}, // "00000001000"
|
||||
28: {0x000c, 11}, // "00000001100"
|
||||
29: {0x000d, 11}, // "00000001101"
|
||||
30: {0x0012, 12}, // "000000010010"
|
||||
31: {0x0013, 12}, // "000000010011"
|
||||
32: {0x0014, 12}, // "000000010100"
|
||||
33: {0x0015, 12}, // "000000010101"
|
||||
34: {0x0016, 12}, // "000000010110"
|
||||
35: {0x0017, 12}, // "000000010111"
|
||||
36: {0x001c, 12}, // "000000011100"
|
||||
37: {0x001d, 12}, // "000000011101"
|
||||
38: {0x001e, 12}, // "000000011110"
|
||||
39: {0x001f, 12}, // "000000011111"
|
||||
}
|
||||
|
||||
// blackEncodeTable2 represents Table 2 for a black run.
|
||||
var blackEncodeTable2 = [...]bitString{
|
||||
0: {0x0037, 10}, // "0000110111"
|
||||
1: {0x0002, 3}, // "010"
|
||||
2: {0x0003, 2}, // "11"
|
||||
3: {0x0002, 2}, // "10"
|
||||
4: {0x0003, 3}, // "011"
|
||||
5: {0x0003, 4}, // "0011"
|
||||
6: {0x0002, 4}, // "0010"
|
||||
7: {0x0003, 5}, // "00011"
|
||||
8: {0x0005, 6}, // "000101"
|
||||
9: {0x0004, 6}, // "000100"
|
||||
10: {0x0004, 7}, // "0000100"
|
||||
11: {0x0005, 7}, // "0000101"
|
||||
12: {0x0007, 7}, // "0000111"
|
||||
13: {0x0004, 8}, // "00000100"
|
||||
14: {0x0007, 8}, // "00000111"
|
||||
15: {0x0018, 9}, // "000011000"
|
||||
16: {0x0017, 10}, // "0000010111"
|
||||
17: {0x0018, 10}, // "0000011000"
|
||||
18: {0x0008, 10}, // "0000001000"
|
||||
19: {0x0067, 11}, // "00001100111"
|
||||
20: {0x0068, 11}, // "00001101000"
|
||||
21: {0x006c, 11}, // "00001101100"
|
||||
22: {0x0037, 11}, // "00000110111"
|
||||
23: {0x0028, 11}, // "00000101000"
|
||||
24: {0x0017, 11}, // "00000010111"
|
||||
25: {0x0018, 11}, // "00000011000"
|
||||
26: {0x00ca, 12}, // "000011001010"
|
||||
27: {0x00cb, 12}, // "000011001011"
|
||||
28: {0x00cc, 12}, // "000011001100"
|
||||
29: {0x00cd, 12}, // "000011001101"
|
||||
30: {0x0068, 12}, // "000001101000"
|
||||
31: {0x0069, 12}, // "000001101001"
|
||||
32: {0x006a, 12}, // "000001101010"
|
||||
33: {0x006b, 12}, // "000001101011"
|
||||
34: {0x00d2, 12}, // "000011010010"
|
||||
35: {0x00d3, 12}, // "000011010011"
|
||||
36: {0x00d4, 12}, // "000011010100"
|
||||
37: {0x00d5, 12}, // "000011010101"
|
||||
38: {0x00d6, 12}, // "000011010110"
|
||||
39: {0x00d7, 12}, // "000011010111"
|
||||
40: {0x006c, 12}, // "000001101100"
|
||||
41: {0x006d, 12}, // "000001101101"
|
||||
42: {0x00da, 12}, // "000011011010"
|
||||
43: {0x00db, 12}, // "000011011011"
|
||||
44: {0x0054, 12}, // "000001010100"
|
||||
45: {0x0055, 12}, // "000001010101"
|
||||
46: {0x0056, 12}, // "000001010110"
|
||||
47: {0x0057, 12}, // "000001010111"
|
||||
48: {0x0064, 12}, // "000001100100"
|
||||
49: {0x0065, 12}, // "000001100101"
|
||||
50: {0x0052, 12}, // "000001010010"
|
||||
51: {0x0053, 12}, // "000001010011"
|
||||
52: {0x0024, 12}, // "000000100100"
|
||||
53: {0x0037, 12}, // "000000110111"
|
||||
54: {0x0038, 12}, // "000000111000"
|
||||
55: {0x0027, 12}, // "000000100111"
|
||||
56: {0x0028, 12}, // "000000101000"
|
||||
57: {0x0058, 12}, // "000001011000"
|
||||
58: {0x0059, 12}, // "000001011001"
|
||||
59: {0x002b, 12}, // "000000101011"
|
||||
60: {0x002c, 12}, // "000000101100"
|
||||
61: {0x005a, 12}, // "000001011010"
|
||||
62: {0x0066, 12}, // "000001100110"
|
||||
63: {0x0067, 12}, // "000001100111"
|
||||
}
|
||||
|
||||
// blackEncodeTable3 represents Table 3 for a black run.
|
||||
var blackEncodeTable3 = [...]bitString{
|
||||
0: {0x000f, 10}, // "0000001111"
|
||||
1: {0x00c8, 12}, // "000011001000"
|
||||
2: {0x00c9, 12}, // "000011001001"
|
||||
3: {0x005b, 12}, // "000001011011"
|
||||
4: {0x0033, 12}, // "000000110011"
|
||||
5: {0x0034, 12}, // "000000110100"
|
||||
6: {0x0035, 12}, // "000000110101"
|
||||
7: {0x006c, 13}, // "0000001101100"
|
||||
8: {0x006d, 13}, // "0000001101101"
|
||||
9: {0x004a, 13}, // "0000001001010"
|
||||
10: {0x004b, 13}, // "0000001001011"
|
||||
11: {0x004c, 13}, // "0000001001100"
|
||||
12: {0x004d, 13}, // "0000001001101"
|
||||
13: {0x0072, 13}, // "0000001110010"
|
||||
14: {0x0073, 13}, // "0000001110011"
|
||||
15: {0x0074, 13}, // "0000001110100"
|
||||
16: {0x0075, 13}, // "0000001110101"
|
||||
17: {0x0076, 13}, // "0000001110110"
|
||||
18: {0x0077, 13}, // "0000001110111"
|
||||
19: {0x0052, 13}, // "0000001010010"
|
||||
20: {0x0053, 13}, // "0000001010011"
|
||||
21: {0x0054, 13}, // "0000001010100"
|
||||
22: {0x0055, 13}, // "0000001010101"
|
||||
23: {0x005a, 13}, // "0000001011010"
|
||||
24: {0x005b, 13}, // "0000001011011"
|
||||
25: {0x0064, 13}, // "0000001100100"
|
||||
26: {0x0065, 13}, // "0000001100101"
|
||||
27: {0x0008, 11}, // "00000001000"
|
||||
28: {0x000c, 11}, // "00000001100"
|
||||
29: {0x000d, 11}, // "00000001101"
|
||||
30: {0x0012, 12}, // "000000010010"
|
||||
31: {0x0013, 12}, // "000000010011"
|
||||
32: {0x0014, 12}, // "000000010100"
|
||||
33: {0x0015, 12}, // "000000010101"
|
||||
34: {0x0016, 12}, // "000000010110"
|
||||
35: {0x0017, 12}, // "000000010111"
|
||||
36: {0x001c, 12}, // "000000011100"
|
||||
37: {0x001d, 12}, // "000000011101"
|
||||
38: {0x001e, 12}, // "000000011110"
|
||||
39: {0x001f, 12}, // "000000011111"
|
||||
}
|
||||
|
||||
// COPY PASTE table.go BEGIN
|
||||
|
||||
const (
|
||||
modePass = iota // Pass
|
||||
modeH // Horizontal
|
||||
modeV0 // Vertical-0
|
||||
modeVR1 // Vertical-Right-1
|
||||
modeVR2 // Vertical-Right-2
|
||||
modeVR3 // Vertical-Right-3
|
||||
modeVL1 // Vertical-Left-1
|
||||
modeVL2 // Vertical-Left-2
|
||||
modeVL3 // Vertical-Left-3
|
||||
modeExt // Extension
|
||||
modeEOL // End-of-Line
|
||||
)
|
||||
|
||||
// COPY PASTE table.go END
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// 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
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
// 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),
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
// 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]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
// 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
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +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
|
||||
}
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
// 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 accomodate 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
|
||||
}
|
||||
+706
@@ -0,0 +1,706 @@
|
||||
// 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 (
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"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")
|
||||
|
||||
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 = make([]byte, datalen)
|
||||
_, err = d.r.ReadAt(raw, 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)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
for x := xmin; x < rMaxX; x++ {
|
||||
v, ok := d.readBits(d.bpp)
|
||||
if !ok {
|
||||
return errNoPixels
|
||||
}
|
||||
img.SetColorIndex(x, y, uint8(v))
|
||||
}
|
||||
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 {
|
||||
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.
|
||||
p = make([]byte, ifdLen*numItems)
|
||||
if _, err := d.r.ReadAt(p, ifdOffset+2); 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")
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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 = make([]byte, n)
|
||||
_, err = d.r.ReadAt(d.buf, 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 = ioutil.ReadAll(r)
|
||||
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 = ioutil.ReadAll(r)
|
||||
case cLZW:
|
||||
r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
|
||||
d.buf, err = ioutil.ReadAll(r)
|
||||
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 = ioutil.ReadAll(r)
|
||||
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 init() {
|
||||
image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
|
||||
image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
|
||||
}
|
||||
+438
@@ -0,0 +1,438 @@
|
||||
// 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"
|
||||
"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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
||||
+732
@@ -0,0 +1,732 @@
|
||||
// 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 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 http://www.unicode.org/reports/tr46.
|
||||
// See http://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 most 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 = true }
|
||||
}
|
||||
|
||||
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
|
||||
// are longer than allowed by the RFC.
|
||||
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.
|
||||
//
|
||||
// This is the behavior suggested by the UTS #46 and is adopted by some
|
||||
// browsers.
|
||||
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.
|
||||
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.validateLabels = enable
|
||||
o.fromPuny = validateFromPunycode
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// 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 option in UTS #46.
|
||||
func StrictDomainName(use bool) Option {
|
||||
return func(o *options) {
|
||||
o.trie = trie
|
||||
o.useSTD3Rules = use
|
||||
o.fromPuny = validateFromPunycode
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
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
|
||||
validateLabels 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.validateLabels {
|
||||
s += ":ValidateLabels"
|
||||
}
|
||||
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: true,
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
}}
|
||||
display = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
trie: trie,
|
||||
fromPuny: validateFromPunycode,
|
||||
mapping: validateAndMap,
|
||||
bidirule: bidirule.ValidString,
|
||||
}}
|
||||
registration = &Profile{options{
|
||||
useSTD3Rules: true,
|
||||
validateLabels: true,
|
||||
verifyDNSLength: 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 http://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.validateLabels {
|
||||
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.validateLabels {
|
||||
return nil
|
||||
}
|
||||
trie := p.trie // p.validateLabels is only set if trie is set.
|
||||
if len(s) > 4 && s[2] == '-' && s[3] == '-' {
|
||||
return &labelError{s, "V2"}
|
||||
}
|
||||
if s[0] == '-' || s[len(s)-1] == '-' {
|
||||
return &labelError{s, "V3"}
|
||||
}
|
||||
// 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
|
||||
}
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
// 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
|
||||
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 += digit * w
|
||||
if i < 0 {
|
||||
return "", punyError(encoded)
|
||||
}
|
||||
t := k - bias
|
||||
if t < tmin {
|
||||
t = tmin
|
||||
} else if t > tmax {
|
||||
t = tmax
|
||||
}
|
||||
if digit < t {
|
||||
break
|
||||
}
|
||||
w *= base - t
|
||||
if w >= math.MaxInt32/base {
|
||||
return "", punyError(encoded)
|
||||
}
|
||||
}
|
||||
x := int32(len(output) + 1)
|
||||
bias = adapt(i-oldI, x, oldI == 0)
|
||||
n += i / x
|
||||
i %= x
|
||||
if n > utf8.MaxRune || len(output) >= 1024 {
|
||||
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, '-')
|
||||
}
|
||||
for remaining != 0 {
|
||||
m := int32(0x7fffffff)
|
||||
for _, r := range s {
|
||||
if m > r && r >= n {
|
||||
m = r
|
||||
}
|
||||
}
|
||||
delta += (m - n) * (h + 1)
|
||||
if delta < 0 {
|
||||
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 t < tmin {
|
||||
t = tmin
|
||||
} else if t > 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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
+4557
File diff suppressed because it is too large
Load Diff
+72
@@ -0,0 +1,72 @@
|
||||
// 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
|
||||
|
||||
// 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 {
|
||||
s := mappings[index:]
|
||||
return append(b, s[1:s[0]+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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
// 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
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
||||
@@ -0,0 +1,2 @@
|
||||
_obj/
|
||||
unix.test
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
# Building `sys/unix`
|
||||
|
||||
The sys/unix package provides access to the raw system call interface of the
|
||||
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
|
||||
|
||||
Porting Go to a new architecture/OS combination or adding syscalls, types, or
|
||||
constants to an existing architecture/OS pair requires some manual effort;
|
||||
however, there are tools that automate much of the process.
|
||||
|
||||
## Build Systems
|
||||
|
||||
There are currently two ways we generate the necessary files. We are currently
|
||||
migrating the build system to use containers so the builds are reproducible.
|
||||
This is being done on an OS-by-OS basis. Please update this documentation as
|
||||
components of the build system change.
|
||||
|
||||
### Old Build System (currently for `GOOS != "linux"`)
|
||||
|
||||
The old build system generates the Go files based on the C header files
|
||||
present on your system. This means that files
|
||||
for a given GOOS/GOARCH pair must be generated on a system with that OS and
|
||||
architecture. This also means that the generated code can differ from system
|
||||
to system, based on differences in the header files.
|
||||
|
||||
To avoid this, if you are using the old build system, only generate the Go
|
||||
files on an installation with unmodified header files. It is also important to
|
||||
keep track of which version of the OS the files were generated from (ex.
|
||||
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
|
||||
and have each OS upgrade correspond to a single change.
|
||||
|
||||
To build the files for your current OS and architecture, make sure GOOS and
|
||||
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
|
||||
your specific system. Running `mkall.sh -n` shows the commands that will be run.
|
||||
|
||||
Requirements: bash, go
|
||||
|
||||
### New Build System (currently for `GOOS == "linux"`)
|
||||
|
||||
The new build system uses a Docker container to generate the go files directly
|
||||
from source checkouts of the kernel and various system libraries. This means
|
||||
that on any platform that supports Docker, all the files using the new build
|
||||
system can be generated at once, and generated files will not change based on
|
||||
what the person running the scripts has installed on their computer.
|
||||
|
||||
The OS specific files for the new build system are located in the `${GOOS}`
|
||||
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
|
||||
the kernel or system library updates, modify the Dockerfile at
|
||||
`${GOOS}/Dockerfile` to checkout the new release of the source.
|
||||
|
||||
To build all the files under the new build system, you must be on an amd64/Linux
|
||||
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
|
||||
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
|
||||
system. Running `mkall.sh -n` shows the commands that will be run.
|
||||
|
||||
Requirements: bash, go, docker
|
||||
|
||||
## Component files
|
||||
|
||||
This section describes the various files used in the code generation process.
|
||||
It also contains instructions on how to modify these files to add a new
|
||||
architecture/OS or to add additional syscalls, types, or constants. Note that
|
||||
if you are using the new build system, the scripts/programs cannot be called normally.
|
||||
They must be called from within the docker container.
|
||||
|
||||
### asm files
|
||||
|
||||
The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
|
||||
call dispatch. There are three entry points:
|
||||
```
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
||||
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
|
||||
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
|
||||
```
|
||||
The first and second are the standard ones; they differ only in how many
|
||||
arguments can be passed to the kernel. The third is for low-level use by the
|
||||
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
|
||||
let it know that a system call is running.
|
||||
|
||||
When porting Go to an new architecture/OS, this file must be implemented for
|
||||
each GOOS/GOARCH pair.
|
||||
|
||||
### mksysnum
|
||||
|
||||
Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
|
||||
for the old system). This program takes in a list of header files containing the
|
||||
syscall number declarations and parses them to produce the corresponding list of
|
||||
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
|
||||
constants.
|
||||
|
||||
Adding new syscall numbers is mostly done by running the build on a sufficiently
|
||||
new installation of the target OS (or updating the source checkouts for the
|
||||
new build system). However, depending on the OS, you make need to update the
|
||||
parsing in mksysnum.
|
||||
|
||||
### mksyscall.go
|
||||
|
||||
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
|
||||
hand-written Go files which implement system calls (for unix, the specific OS,
|
||||
or the specific OS/Architecture pair respectively) that need special handling
|
||||
and list `//sys` comments giving prototypes for ones that can be generated.
|
||||
|
||||
The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
|
||||
them into syscalls. This requires the name of the prototype in the comment to
|
||||
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
|
||||
prototype can be exported (capitalized) or not.
|
||||
|
||||
Adding a new syscall often just requires adding a new `//sys` function prototype
|
||||
with the desired arguments and a capitalized name so it is exported. However, if
|
||||
you want the interface to the syscall to be different, often one will make an
|
||||
unexported `//sys` prototype, an then write a custom wrapper in
|
||||
`syscall_${GOOS}.go`.
|
||||
|
||||
### types files
|
||||
|
||||
For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
|
||||
`types_${GOOS}.go` on the old system). This file includes standard C headers and
|
||||
creates Go type aliases to the corresponding C types. The file is then fed
|
||||
through godef to get the Go compatible definitions. Finally, the generated code
|
||||
is fed though mkpost.go to format the code correctly and remove any hidden or
|
||||
private identifiers. This cleaned-up code is written to
|
||||
`ztypes_${GOOS}_${GOARCH}.go`.
|
||||
|
||||
The hardest part about preparing this file is figuring out which headers to
|
||||
include and which symbols need to be `#define`d to get the actual data
|
||||
structures that pass through to the kernel system calls. Some C libraries
|
||||
preset alternate versions for binary compatibility and translate them on the
|
||||
way in and out of system calls, but there is almost always a `#define` that can
|
||||
get the real ones.
|
||||
See `types_darwin.go` and `linux/types.go` for examples.
|
||||
|
||||
To add a new type, add in the necessary include statement at the top of the
|
||||
file (if it is not already there) and add in a type alias line. Note that if
|
||||
your type is significantly different on different architectures, you may need
|
||||
some `#if/#elif` macros in your include statements.
|
||||
|
||||
### mkerrors.sh
|
||||
|
||||
This script is used to generate the system's various constants. This doesn't
|
||||
just include the error numbers and error strings, but also the signal numbers
|
||||
an a wide variety of miscellaneous constants. The constants come from the list
|
||||
of include files in the `includes_${uname}` variable. A regex then picks out
|
||||
the desired `#define` statements, and generates the corresponding Go constants.
|
||||
The error numbers and strings are generated from `#include <errno.h>`, and the
|
||||
signal numbers and strings are generated from `#include <signal.h>`. All of
|
||||
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
|
||||
`_errors.c`, which prints out all the constants.
|
||||
|
||||
To add a constant, add the header that includes it to the appropriate variable.
|
||||
Then, edit the regex (if necessary) to match the desired constant. Avoid making
|
||||
the regex too broad to avoid matching unintended constants.
|
||||
|
||||
|
||||
## Generated files
|
||||
|
||||
### `zerror_${GOOS}_${GOARCH}.go`
|
||||
|
||||
A file containing all of the system's generated error numbers, error strings,
|
||||
signal numbers, and constants. Generated by `mkerrors.sh` (see above).
|
||||
|
||||
### `zsyscall_${GOOS}_${GOARCH}.go`
|
||||
|
||||
A file containing all the generated syscalls for a specific GOOS and GOARCH.
|
||||
Generated by `mksyscall.go` (see above).
|
||||
|
||||
### `zsysnum_${GOOS}_${GOARCH}.go`
|
||||
|
||||
A list of numeric constants for all the syscall number of the specific GOOS
|
||||
and GOARCH. Generated by mksysnum (see above).
|
||||
|
||||
### `ztypes_${GOOS}_${GOARCH}.go`
|
||||
|
||||
A file containing Go types for passing into (or returning from) syscalls.
|
||||
Generated by godefs and the types file (see above).
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
// 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.
|
||||
|
||||
// CPU affinity functions
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
|
||||
|
||||
// CPUSet represents a CPU affinity mask.
|
||||
type CPUSet [cpuSetSize]cpuMask
|
||||
|
||||
func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
|
||||
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
|
||||
if e != 0 {
|
||||
return errnoErr(e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
|
||||
// If pid is 0 the calling thread is used.
|
||||
func SchedGetaffinity(pid int, set *CPUSet) error {
|
||||
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
|
||||
}
|
||||
|
||||
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
|
||||
// If pid is 0 the calling thread is used.
|
||||
func SchedSetaffinity(pid int, set *CPUSet) error {
|
||||
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
|
||||
}
|
||||
|
||||
// Zero clears the set s, so that it contains no CPUs.
|
||||
func (s *CPUSet) Zero() {
|
||||
for i := range s {
|
||||
s[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func cpuBitsIndex(cpu int) int {
|
||||
return cpu / _NCPUBITS
|
||||
}
|
||||
|
||||
func cpuBitsMask(cpu int) cpuMask {
|
||||
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
|
||||
}
|
||||
|
||||
// Set adds cpu to the set s.
|
||||
func (s *CPUSet) Set(cpu int) {
|
||||
i := cpuBitsIndex(cpu)
|
||||
if i < len(s) {
|
||||
s[i] |= cpuBitsMask(cpu)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear removes cpu from the set s.
|
||||
func (s *CPUSet) Clear(cpu int) {
|
||||
i := cpuBitsIndex(cpu)
|
||||
if i < len(s) {
|
||||
s[i] &^= cpuBitsMask(cpu)
|
||||
}
|
||||
}
|
||||
|
||||
// IsSet reports whether cpu is in the set s.
|
||||
func (s *CPUSet) IsSet(cpu int) bool {
|
||||
i := cpuBitsIndex(cpu)
|
||||
if i < len(s) {
|
||||
return s[i]&cpuBitsMask(cpu) != 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Count returns the number of CPUs in the set s.
|
||||
func (s *CPUSet) Count() int {
|
||||
c := 0
|
||||
for _, b := range s {
|
||||
c += onesCount64(uint64(b))
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
|
||||
// Once this package can require Go 1.9, we can delete this
|
||||
// and update the caller to use bits.OnesCount64.
|
||||
func onesCount64(x uint64) int {
|
||||
const m0 = 0x5555555555555555 // 01010101 ...
|
||||
const m1 = 0x3333333333333333 // 00110011 ...
|
||||
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
|
||||
|
||||
// Unused in this function, but definitions preserved for
|
||||
// documentation purposes:
|
||||
//
|
||||
// const m3 = 0x00ff00ff00ff00ff // etc.
|
||||
// const m4 = 0x0000ffff0000ffff
|
||||
//
|
||||
// Implementation: Parallel summing of adjacent bits.
|
||||
// See "Hacker's Delight", Chap. 5: Counting Bits.
|
||||
// The following pattern shows the general approach:
|
||||
//
|
||||
// x = x>>1&(m0&m) + x&(m0&m)
|
||||
// x = x>>2&(m1&m) + x&(m1&m)
|
||||
// x = x>>4&(m2&m) + x&(m2&m)
|
||||
// x = x>>8&(m3&m) + x&(m3&m)
|
||||
// x = x>>16&(m4&m) + x&(m4&m)
|
||||
// x = x>>32&(m5&m) + x&(m5&m)
|
||||
// return int(x)
|
||||
//
|
||||
// Masking (& operations) can be left away when there's no
|
||||
// danger that a field's sum will carry over into the next
|
||||
// field: Since the result cannot be > 64, 8 bits is enough
|
||||
// and we can ignore the masks for the shifts by 8 and up.
|
||||
// Per "Hacker's Delight", the first line can be simplified
|
||||
// more, but it saves at best one instruction, so we leave
|
||||
// it alone for clarity.
|
||||
const m = 1<<64 - 1
|
||||
x = x>>1&(m0&m) + x&(m0&m)
|
||||
x = x>>2&(m1&m) + x&(m1&m)
|
||||
x = (x>>4 + x) & (m2 & m)
|
||||
x += x >> 8
|
||||
x += x >> 16
|
||||
x += x >> 32
|
||||
return int(x) & (1<<7 - 1)
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
// +build go1.9
|
||||
|
||||
package unix
|
||||
|
||||
import "syscall"
|
||||
|
||||
type Signal = syscall.Signal
|
||||
type Errno = syscall.Errno
|
||||
type SysProcAttr = syscall.SysProcAttr
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
|
||||
//
|
||||
|
||||
TEXT ·syscall6(SB),NOSPLIT,$0-88
|
||||
JMP syscall·syscall6(SB)
|
||||
|
||||
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
|
||||
JMP syscall·rawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, Darwin
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, Darwin
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo
|
||||
// +build arm,darwin
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for ARM, Darwin
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
B syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
B syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
B syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·RawSyscall6(SB)
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo
|
||||
// +build arm64,darwin
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, Darwin
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
B syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
B syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
B syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
B syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
B syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, DragonFly
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, FreeBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, FreeBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for ARM, FreeBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
B syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
B syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
B syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for ARM64, FreeBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for 386, Linux
|
||||
//
|
||||
|
||||
// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
|
||||
// instead of the glibc-specific "CALL 0x10(GS)".
|
||||
#define INVOKE_SYSCALL INT $0x80
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVL trap+0(FP), AX // syscall entry
|
||||
MOVL a1+4(FP), BX
|
||||
MOVL a2+8(FP), CX
|
||||
MOVL a3+12(FP), DX
|
||||
MOVL $0, SI
|
||||
MOVL $0, DI
|
||||
INVOKE_SYSCALL
|
||||
MOVL AX, r1+16(FP)
|
||||
MOVL DX, r2+20(FP)
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
||||
MOVL trap+0(FP), AX // syscall entry
|
||||
MOVL a1+4(FP), BX
|
||||
MOVL a2+8(FP), CX
|
||||
MOVL a3+12(FP), DX
|
||||
MOVL $0, SI
|
||||
MOVL $0, DI
|
||||
INVOKE_SYSCALL
|
||||
MOVL AX, r1+16(FP)
|
||||
MOVL DX, r2+20(FP)
|
||||
RET
|
||||
|
||||
TEXT ·socketcall(SB),NOSPLIT,$0-36
|
||||
JMP syscall·socketcall(SB)
|
||||
|
||||
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
|
||||
JMP syscall·rawsocketcall(SB)
|
||||
|
||||
TEXT ·seek(SB),NOSPLIT,$0-28
|
||||
JMP syscall·seek(SB)
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for AMD64, Linux
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOVQ a1+8(FP), DI
|
||||
MOVQ a2+16(FP), SI
|
||||
MOVQ a3+24(FP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ trap+0(FP), AX // syscall entry
|
||||
SYSCALL
|
||||
MOVQ AX, r1+32(FP)
|
||||
MOVQ DX, r2+40(FP)
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||
MOVQ a1+8(FP), DI
|
||||
MOVQ a2+16(FP), SI
|
||||
MOVQ a3+24(FP), DX
|
||||
MOVQ $0, R10
|
||||
MOVQ $0, R8
|
||||
MOVQ $0, R9
|
||||
MOVQ trap+0(FP), AX // syscall entry
|
||||
SYSCALL
|
||||
MOVQ AX, r1+32(FP)
|
||||
MOVQ DX, r2+40(FP)
|
||||
RET
|
||||
|
||||
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
|
||||
JMP syscall·gettimeofday(SB)
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for arm, Linux
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
B syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVW trap+0(FP), R7
|
||||
MOVW a1+4(FP), R0
|
||||
MOVW a2+8(FP), R1
|
||||
MOVW a3+12(FP), R2
|
||||
MOVW $0, R3
|
||||
MOVW $0, R4
|
||||
MOVW $0, R5
|
||||
SWI $0
|
||||
MOVW R0, r1+16(FP)
|
||||
MOVW $0, R0
|
||||
MOVW R0, r2+20(FP)
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
B syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·RawSyscall6(SB)
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
||||
MOVW trap+0(FP), R7 // syscall entry
|
||||
MOVW a1+4(FP), R0
|
||||
MOVW a2+8(FP), R1
|
||||
MOVW a3+12(FP), R2
|
||||
SWI $0
|
||||
MOVW R0, r1+16(FP)
|
||||
MOVW $0, R0
|
||||
MOVW R0, r2+20(FP)
|
||||
RET
|
||||
|
||||
TEXT ·seek(SB),NOSPLIT,$0-28
|
||||
B syscall·seek(SB)
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
// +build arm64
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
B syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
B syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVD a1+8(FP), R0
|
||||
MOVD a2+16(FP), R1
|
||||
MOVD a3+24(FP), R2
|
||||
MOVD $0, R3
|
||||
MOVD $0, R4
|
||||
MOVD $0, R5
|
||||
MOVD trap+0(FP), R8 // syscall entry
|
||||
SVC
|
||||
MOVD R0, r1+32(FP) // r1
|
||||
MOVD R1, r2+40(FP) // r2
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
B syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
B syscall·RawSyscall6(SB)
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||
MOVD a1+8(FP), R0
|
||||
MOVD a2+16(FP), R1
|
||||
MOVD a3+24(FP), R2
|
||||
MOVD $0, R3
|
||||
MOVD $0, R4
|
||||
MOVD $0, R5
|
||||
MOVD trap+0(FP), R8 // syscall entry
|
||||
SVC
|
||||
MOVD R0, r1+32(FP)
|
||||
MOVD R1, r2+40(FP)
|
||||
RET
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
// +build mips64 mips64le
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for mips64, Linux
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||
JAL runtime·entersyscall(SB)
|
||||
MOVV a1+8(FP), R4
|
||||
MOVV a2+16(FP), R5
|
||||
MOVV a3+24(FP), R6
|
||||
MOVV R0, R7
|
||||
MOVV R0, R8
|
||||
MOVV R0, R9
|
||||
MOVV trap+0(FP), R2 // syscall entry
|
||||
SYSCALL
|
||||
MOVV R2, r1+32(FP)
|
||||
MOVV R3, r2+40(FP)
|
||||
JAL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||
MOVV a1+8(FP), R4
|
||||
MOVV a2+16(FP), R5
|
||||
MOVV a3+24(FP), R6
|
||||
MOVV R0, R7
|
||||
MOVV R0, R8
|
||||
MOVV R0, R9
|
||||
MOVV trap+0(FP), R2 // syscall entry
|
||||
SYSCALL
|
||||
MOVV R2, r1+32(FP)
|
||||
MOVV R3, r2+40(FP)
|
||||
RET
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux
|
||||
// +build mips mipsle
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for mips, Linux
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
|
||||
JAL runtime·entersyscall(SB)
|
||||
MOVW a1+4(FP), R4
|
||||
MOVW a2+8(FP), R5
|
||||
MOVW a3+12(FP), R6
|
||||
MOVW R0, R7
|
||||
MOVW trap+0(FP), R2 // syscall entry
|
||||
SYSCALL
|
||||
MOVW R2, r1+16(FP) // r1
|
||||
MOVW R3, r2+20(FP) // r2
|
||||
JAL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
|
||||
MOVW a1+4(FP), R4
|
||||
MOVW a2+8(FP), R5
|
||||
MOVW a3+12(FP), R6
|
||||
MOVW trap+0(FP), R2 // syscall entry
|
||||
SYSCALL
|
||||
MOVW R2, r1+16(FP)
|
||||
MOVW R3, r2+20(FP)
|
||||
RET
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// 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.
|
||||
|
||||
// +build linux
|
||||
// +build ppc64 ppc64le
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for ppc64, Linux
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVD a1+8(FP), R3
|
||||
MOVD a2+16(FP), R4
|
||||
MOVD a3+24(FP), R5
|
||||
MOVD R0, R6
|
||||
MOVD R0, R7
|
||||
MOVD R0, R8
|
||||
MOVD trap+0(FP), R9 // syscall entry
|
||||
SYSCALL R9
|
||||
MOVD R3, r1+32(FP)
|
||||
MOVD R4, r2+40(FP)
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||
MOVD a1+8(FP), R3
|
||||
MOVD a2+16(FP), R4
|
||||
MOVD a3+24(FP), R5
|
||||
MOVD R0, R6
|
||||
MOVD R0, R7
|
||||
MOVD R0, R8
|
||||
MOVD trap+0(FP), R9 // syscall entry
|
||||
SYSCALL R9
|
||||
MOVD R3, r1+32(FP)
|
||||
MOVD R4, r2+40(FP)
|
||||
RET
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// 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.
|
||||
|
||||
// +build riscv64,!gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for linux/riscv64.
|
||||
//
|
||||
// Where available, just jump to package syscall's implementation of
|
||||
// these functions.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||
CALL runtime·entersyscall(SB)
|
||||
MOV a1+8(FP), A0
|
||||
MOV a2+16(FP), A1
|
||||
MOV a3+24(FP), A2
|
||||
MOV $0, A3
|
||||
MOV $0, A4
|
||||
MOV $0, A5
|
||||
MOV $0, A6
|
||||
MOV trap+0(FP), A7 // syscall entry
|
||||
ECALL
|
||||
MOV A0, r1+32(FP) // r1
|
||||
MOV A1, r2+40(FP) // r2
|
||||
CALL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||
MOV a1+8(FP), A0
|
||||
MOV a2+16(FP), A1
|
||||
MOV a3+24(FP), A2
|
||||
MOV ZERO, A3
|
||||
MOV ZERO, A4
|
||||
MOV ZERO, A5
|
||||
MOV trap+0(FP), A7 // syscall entry
|
||||
ECALL
|
||||
MOV A0, r1+32(FP)
|
||||
MOV A1, r2+40(FP)
|
||||
RET
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build s390x
|
||||
// +build linux
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for s390x, Linux
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
BR syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
BR syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVD a1+8(FP), R2
|
||||
MOVD a2+16(FP), R3
|
||||
MOVD a3+24(FP), R4
|
||||
MOVD $0, R5
|
||||
MOVD $0, R6
|
||||
MOVD $0, R7
|
||||
MOVD trap+0(FP), R1 // syscall entry
|
||||
SYSCALL
|
||||
MOVD R2, r1+32(FP)
|
||||
MOVD R3, r2+40(FP)
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
BR syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
BR syscall·RawSyscall6(SB)
|
||||
|
||||
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
|
||||
MOVD a1+8(FP), R2
|
||||
MOVD a2+16(FP), R3
|
||||
MOVD a3+24(FP), R4
|
||||
MOVD $0, R5
|
||||
MOVD $0, R6
|
||||
MOVD $0, R7
|
||||
MOVD trap+0(FP), R1 // syscall entry
|
||||
SYSCALL
|
||||
MOVD R2, r1+32(FP)
|
||||
MOVD R3, r2+40(FP)
|
||||
RET
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, NetBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, NetBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for ARM, NetBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
B syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
B syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
B syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for ARM64, NetBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
B syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
B syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
B syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
B syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
B syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for 386, OpenBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for AMD64, OpenBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for ARM, OpenBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-28
|
||||
B syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-52
|
||||
B syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
|
||||
B syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
|
||||
B syscall·RawSyscall6(SB)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System call support for arm64, OpenBSD
|
||||
//
|
||||
|
||||
// Just jump to package syscall's implementation for all these functions.
|
||||
// The runtime may know about them.
|
||||
|
||||
TEXT ·Syscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·Syscall(SB)
|
||||
|
||||
TEXT ·Syscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·Syscall6(SB)
|
||||
|
||||
TEXT ·Syscall9(SB),NOSPLIT,$0-104
|
||||
JMP syscall·Syscall9(SB)
|
||||
|
||||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
|
||||
JMP syscall·RawSyscall(SB)
|
||||
|
||||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
|
||||
JMP syscall·RawSyscall6(SB)
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go
|
||||
//
|
||||
|
||||
TEXT ·sysvicall6(SB),NOSPLIT,$0-88
|
||||
JMP syscall·sysvicall6(SB)
|
||||
|
||||
TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88
|
||||
JMP syscall·rawSysvicall6(SB)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// 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.
|
||||
|
||||
// Bluetooth sockets and messages
|
||||
|
||||
package unix
|
||||
|
||||
// Bluetooth Protocols
|
||||
const (
|
||||
BTPROTO_L2CAP = 0
|
||||
BTPROTO_HCI = 1
|
||||
BTPROTO_SCO = 2
|
||||
BTPROTO_RFCOMM = 3
|
||||
BTPROTO_BNEP = 4
|
||||
BTPROTO_CMTP = 5
|
||||
BTPROTO_HIDP = 6
|
||||
BTPROTO_AVDTP = 7
|
||||
)
|
||||
|
||||
const (
|
||||
HCI_CHANNEL_RAW = 0
|
||||
HCI_CHANNEL_USER = 1
|
||||
HCI_CHANNEL_MONITOR = 2
|
||||
HCI_CHANNEL_CONTROL = 3
|
||||
)
|
||||
|
||||
// Socketoption Level
|
||||
const (
|
||||
SOL_BLUETOOTH = 0x112
|
||||
SOL_HCI = 0x0
|
||||
SOL_L2CAP = 0x6
|
||||
SOL_RFCOMM = 0x12
|
||||
SOL_SCO = 0x11
|
||||
)
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build freebsd
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
|
||||
|
||||
const (
|
||||
// This is the version of CapRights this package understands. See C implementation for parallels.
|
||||
capRightsGoVersion = CAP_RIGHTS_VERSION_00
|
||||
capArSizeMin = CAP_RIGHTS_VERSION_00 + 2
|
||||
capArSizeMax = capRightsGoVersion + 2
|
||||
)
|
||||
|
||||
var (
|
||||
bit2idx = []int{
|
||||
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
|
||||
4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
}
|
||||
)
|
||||
|
||||
func capidxbit(right uint64) int {
|
||||
return int((right >> 57) & 0x1f)
|
||||
}
|
||||
|
||||
func rightToIndex(right uint64) (int, error) {
|
||||
idx := capidxbit(right)
|
||||
if idx < 0 || idx >= len(bit2idx) {
|
||||
return -2, fmt.Errorf("index for right 0x%x out of range", right)
|
||||
}
|
||||
return bit2idx[idx], nil
|
||||
}
|
||||
|
||||
func caprver(right uint64) int {
|
||||
return int(right >> 62)
|
||||
}
|
||||
|
||||
func capver(rights *CapRights) int {
|
||||
return caprver(rights.Rights[0])
|
||||
}
|
||||
|
||||
func caparsize(rights *CapRights) int {
|
||||
return capver(rights) + 2
|
||||
}
|
||||
|
||||
// CapRightsSet sets the permissions in setrights in rights.
|
||||
func CapRightsSet(rights *CapRights, setrights []uint64) error {
|
||||
// This is essentially a copy of cap_rights_vset()
|
||||
if capver(rights) != CAP_RIGHTS_VERSION_00 {
|
||||
return fmt.Errorf("bad rights version %d", capver(rights))
|
||||
}
|
||||
|
||||
n := caparsize(rights)
|
||||
if n < capArSizeMin || n > capArSizeMax {
|
||||
return errors.New("bad rights size")
|
||||
}
|
||||
|
||||
for _, right := range setrights {
|
||||
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||
return errors.New("bad right version")
|
||||
}
|
||||
i, err := rightToIndex(right)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i >= n {
|
||||
return errors.New("index overflow")
|
||||
}
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return errors.New("index mismatch")
|
||||
}
|
||||
rights.Rights[i] |= right
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return errors.New("index mismatch (after assign)")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CapRightsClear clears the permissions in clearrights from rights.
|
||||
func CapRightsClear(rights *CapRights, clearrights []uint64) error {
|
||||
// This is essentially a copy of cap_rights_vclear()
|
||||
if capver(rights) != CAP_RIGHTS_VERSION_00 {
|
||||
return fmt.Errorf("bad rights version %d", capver(rights))
|
||||
}
|
||||
|
||||
n := caparsize(rights)
|
||||
if n < capArSizeMin || n > capArSizeMax {
|
||||
return errors.New("bad rights size")
|
||||
}
|
||||
|
||||
for _, right := range clearrights {
|
||||
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||
return errors.New("bad right version")
|
||||
}
|
||||
i, err := rightToIndex(right)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i >= n {
|
||||
return errors.New("index overflow")
|
||||
}
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return errors.New("index mismatch")
|
||||
}
|
||||
rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return errors.New("index mismatch (after assign)")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
|
||||
func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
|
||||
// This is essentially a copy of cap_rights_is_vset()
|
||||
if capver(rights) != CAP_RIGHTS_VERSION_00 {
|
||||
return false, fmt.Errorf("bad rights version %d", capver(rights))
|
||||
}
|
||||
|
||||
n := caparsize(rights)
|
||||
if n < capArSizeMin || n > capArSizeMax {
|
||||
return false, errors.New("bad rights size")
|
||||
}
|
||||
|
||||
for _, right := range setrights {
|
||||
if caprver(right) != CAP_RIGHTS_VERSION_00 {
|
||||
return false, errors.New("bad right version")
|
||||
}
|
||||
i, err := rightToIndex(right)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if i >= n {
|
||||
return false, errors.New("index overflow")
|
||||
}
|
||||
if capidxbit(rights.Rights[i]) != capidxbit(right) {
|
||||
return false, errors.New("index mismatch")
|
||||
}
|
||||
if (rights.Rights[i] & right) != right {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func capright(idx uint64, bit uint64) uint64 {
|
||||
return ((1 << (57 + idx)) | bit)
|
||||
}
|
||||
|
||||
// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
|
||||
// See man cap_rights_init(3) and rights(4).
|
||||
func CapRightsInit(rights []uint64) (*CapRights, error) {
|
||||
var r CapRights
|
||||
r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
|
||||
r.Rights[1] = capright(1, 0)
|
||||
|
||||
err := CapRightsSet(&r, rights)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
|
||||
// The capability rights on fd can never be increased by CapRightsLimit.
|
||||
// See man cap_rights_limit(2) and rights(4).
|
||||
func CapRightsLimit(fd uintptr, rights *CapRights) error {
|
||||
return capRightsLimit(int(fd), rights)
|
||||
}
|
||||
|
||||
// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
|
||||
// See man cap_rights_get(3) and rights(4).
|
||||
func CapRightsGet(fd uintptr) (*CapRights, error) {
|
||||
r, err := CapRightsInit(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = capRightsGet(capRightsGoVersion, int(fd), r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
package unix
|
||||
|
||||
const (
|
||||
R_OK = 0x4
|
||||
W_OK = 0x2
|
||||
X_OK = 0x1
|
||||
)
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// 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.
|
||||
|
||||
// +build aix
|
||||
// +build ppc
|
||||
|
||||
// Functions to access/create device major and minor numbers matching the
|
||||
// encoding used by AIX.
|
||||
|
||||
package unix
|
||||
|
||||
// Major returns the major component of a Linux device number.
|
||||
func Major(dev uint64) uint32 {
|
||||
return uint32((dev >> 16) & 0xffff)
|
||||
}
|
||||
|
||||
// Minor returns the minor component of a Linux device number.
|
||||
func Minor(dev uint64) uint32 {
|
||||
return uint32(dev & 0xffff)
|
||||
}
|
||||
|
||||
// Mkdev returns a Linux device number generated from the given major and minor
|
||||
// components.
|
||||
func Mkdev(major, minor uint32) uint64 {
|
||||
return uint64(((major) << 16) | (minor))
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// +build aix
|
||||
// +build ppc64
|
||||
|
||||
// Functions to access/create device major and minor numbers matching the
|
||||
// encoding used AIX.
|
||||
|
||||
package unix
|
||||
|
||||
// Major returns the major component of a Linux device number.
|
||||
func Major(dev uint64) uint32 {
|
||||
return uint32((dev & 0x3fffffff00000000) >> 32)
|
||||
}
|
||||
|
||||
// Minor returns the minor component of a Linux device number.
|
||||
func Minor(dev uint64) uint32 {
|
||||
return uint32((dev & 0x00000000ffffffff) >> 0)
|
||||
}
|
||||
|
||||
// Mkdev returns a Linux device number generated from the given major and minor
|
||||
// components.
|
||||
func Mkdev(major, minor uint32) uint64 {
|
||||
var DEVNO64 uint64
|
||||
DEVNO64 = 0x8000000000000000
|
||||
return ((uint64(major) << 32) | (uint64(minor) & 0x00000000FFFFFFFF) | DEVNO64)
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// 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.
|
||||
|
||||
// Functions to access/create device major and minor numbers matching the
|
||||
// encoding used in Darwin's sys/types.h header.
|
||||
|
||||
package unix
|
||||
|
||||
// Major returns the major component of a Darwin device number.
|
||||
func Major(dev uint64) uint32 {
|
||||
return uint32((dev >> 24) & 0xff)
|
||||
}
|
||||
|
||||
// Minor returns the minor component of a Darwin device number.
|
||||
func Minor(dev uint64) uint32 {
|
||||
return uint32(dev & 0xffffff)
|
||||
}
|
||||
|
||||
// Mkdev returns a Darwin device number generated from the given major and minor
|
||||
// components.
|
||||
func Mkdev(major, minor uint32) uint64 {
|
||||
return (uint64(major) << 24) | uint64(minor)
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
|
||||
// Functions to access/create device major and minor numbers matching the
|
||||
// encoding used in Dragonfly's sys/types.h header.
|
||||
//
|
||||
// The information below is extracted and adapted from sys/types.h:
|
||||
//
|
||||
// Minor gives a cookie instead of an index since in order to avoid changing the
|
||||
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
|
||||
// devices that don't use them.
|
||||
|
||||
package unix
|
||||
|
||||
// Major returns the major component of a DragonFlyBSD device number.
|
||||
func Major(dev uint64) uint32 {
|
||||
return uint32((dev >> 8) & 0xff)
|
||||
}
|
||||
|
||||
// Minor returns the minor component of a DragonFlyBSD device number.
|
||||
func Minor(dev uint64) uint32 {
|
||||
return uint32(dev & 0xffff00ff)
|
||||
}
|
||||
|
||||
// Mkdev returns a DragonFlyBSD device number generated from the given major and
|
||||
// minor components.
|
||||
func Mkdev(major, minor uint32) uint64 {
|
||||
return (uint64(major) << 8) | uint64(minor)
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
|
||||
// Functions to access/create device major and minor numbers matching the
|
||||
// encoding used in FreeBSD's sys/types.h header.
|
||||
//
|
||||
// The information below is extracted and adapted from sys/types.h:
|
||||
//
|
||||
// Minor gives a cookie instead of an index since in order to avoid changing the
|
||||
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
|
||||
// devices that don't use them.
|
||||
|
||||
package unix
|
||||
|
||||
// Major returns the major component of a FreeBSD device number.
|
||||
func Major(dev uint64) uint32 {
|
||||
return uint32((dev >> 8) & 0xff)
|
||||
}
|
||||
|
||||
// Minor returns the minor component of a FreeBSD device number.
|
||||
func Minor(dev uint64) uint32 {
|
||||
return uint32(dev & 0xffff00ff)
|
||||
}
|
||||
|
||||
// Mkdev returns a FreeBSD device number generated from the given major and
|
||||
// minor components.
|
||||
func Mkdev(major, minor uint32) uint64 {
|
||||
return (uint64(major) << 8) | uint64(minor)
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// 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.
|
||||
|
||||
// Functions to access/create device major and minor numbers matching the
|
||||
// encoding used by the Linux kernel and glibc.
|
||||
//
|
||||
// The information below is extracted and adapted from bits/sysmacros.h in the
|
||||
// glibc sources:
|
||||
//
|
||||
// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
|
||||
// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
|
||||
// number and m is a hex digit of the minor number. This is backward compatible
|
||||
// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
|
||||
// backward compatible with the Linux kernel, which for some architectures uses
|
||||
// 32-bit dev_t, encoded as mmmM MMmm.
|
||||
|
||||
package unix
|
||||
|
||||
// Major returns the major component of a Linux device number.
|
||||
func Major(dev uint64) uint32 {
|
||||
major := uint32((dev & 0x00000000000fff00) >> 8)
|
||||
major |= uint32((dev & 0xfffff00000000000) >> 32)
|
||||
return major
|
||||
}
|
||||
|
||||
// Minor returns the minor component of a Linux device number.
|
||||
func Minor(dev uint64) uint32 {
|
||||
minor := uint32((dev & 0x00000000000000ff) >> 0)
|
||||
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
|
||||
return minor
|
||||
}
|
||||
|
||||
// Mkdev returns a Linux device number generated from the given major and minor
|
||||
// components.
|
||||
func Mkdev(major, minor uint32) uint64 {
|
||||
dev := (uint64(major) & 0x00000fff) << 8
|
||||
dev |= (uint64(major) & 0xfffff000) << 32
|
||||
dev |= (uint64(minor) & 0x000000ff) << 0
|
||||
dev |= (uint64(minor) & 0xffffff00) << 12
|
||||
return dev
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// Functions to access/create device major and minor numbers matching the
|
||||
// encoding used in NetBSD's sys/types.h header.
|
||||
|
||||
package unix
|
||||
|
||||
// Major returns the major component of a NetBSD device number.
|
||||
func Major(dev uint64) uint32 {
|
||||
return uint32((dev & 0x000fff00) >> 8)
|
||||
}
|
||||
|
||||
// Minor returns the minor component of a NetBSD device number.
|
||||
func Minor(dev uint64) uint32 {
|
||||
minor := uint32((dev & 0x000000ff) >> 0)
|
||||
minor |= uint32((dev & 0xfff00000) >> 12)
|
||||
return minor
|
||||
}
|
||||
|
||||
// Mkdev returns a NetBSD device number generated from the given major and minor
|
||||
// components.
|
||||
func Mkdev(major, minor uint32) uint64 {
|
||||
dev := (uint64(major) << 8) & 0x000fff00
|
||||
dev |= (uint64(minor) << 12) & 0xfff00000
|
||||
dev |= (uint64(minor) << 0) & 0x000000ff
|
||||
return dev
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// Functions to access/create device major and minor numbers matching the
|
||||
// encoding used in OpenBSD's sys/types.h header.
|
||||
|
||||
package unix
|
||||
|
||||
// Major returns the major component of an OpenBSD device number.
|
||||
func Major(dev uint64) uint32 {
|
||||
return uint32((dev & 0x0000ff00) >> 8)
|
||||
}
|
||||
|
||||
// Minor returns the minor component of an OpenBSD device number.
|
||||
func Minor(dev uint64) uint32 {
|
||||
minor := uint32((dev & 0x000000ff) >> 0)
|
||||
minor |= uint32((dev & 0xffff0000) >> 8)
|
||||
return minor
|
||||
}
|
||||
|
||||
// Mkdev returns an OpenBSD device number generated from the given major and minor
|
||||
// components.
|
||||
func Mkdev(major, minor uint32) uint64 {
|
||||
dev := (uint64(major) << 8) & 0x0000ff00
|
||||
dev |= (uint64(minor) << 8) & 0xffff0000
|
||||
dev |= (uint64(minor) << 0) & 0x000000ff
|
||||
return dev
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
|
||||
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
|
||||
if len(b) < int(off+size) {
|
||||
return 0, false
|
||||
}
|
||||
if isBigEndian {
|
||||
return readIntBE(b[off:], size), true
|
||||
}
|
||||
return readIntLE(b[off:], size), true
|
||||
}
|
||||
|
||||
func readIntBE(b []byte, size uintptr) uint64 {
|
||||
switch size {
|
||||
case 1:
|
||||
return uint64(b[0])
|
||||
case 2:
|
||||
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[1]) | uint64(b[0])<<8
|
||||
case 4:
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
|
||||
case 8:
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
|
||||
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
|
||||
default:
|
||||
panic("syscall: readInt with unsupported size")
|
||||
}
|
||||
}
|
||||
|
||||
func readIntLE(b []byte, size uintptr) uint64 {
|
||||
switch size {
|
||||
case 1:
|
||||
return uint64(b[0])
|
||||
case 2:
|
||||
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[0]) | uint64(b[1])<<8
|
||||
case 4:
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
|
||||
case 8:
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
|
||||
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
|
||||
default:
|
||||
panic("syscall: readInt with unsupported size")
|
||||
}
|
||||
}
|
||||
|
||||
// ParseDirent parses up to max directory entries in buf,
|
||||
// appending the names to names. It returns the number of
|
||||
// bytes consumed from buf, the number of entries added
|
||||
// to names, and the new names slice.
|
||||
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
|
||||
origlen := len(buf)
|
||||
count = 0
|
||||
for max != 0 && len(buf) > 0 {
|
||||
reclen, ok := direntReclen(buf)
|
||||
if !ok || reclen > uint64(len(buf)) {
|
||||
return origlen, count, names
|
||||
}
|
||||
rec := buf[:reclen]
|
||||
buf = buf[reclen:]
|
||||
ino, ok := direntIno(rec)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
if ino == 0 { // File absent in directory.
|
||||
continue
|
||||
}
|
||||
const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
|
||||
namlen, ok := direntNamlen(rec)
|
||||
if !ok || namoff+namlen > uint64(len(rec)) {
|
||||
break
|
||||
}
|
||||
name := rec[namoff : namoff+namlen]
|
||||
for i, c := range name {
|
||||
if c == 0 {
|
||||
name = name[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
// Check for useless names before allocating a string.
|
||||
if string(name) == "." || string(name) == ".." {
|
||||
continue
|
||||
}
|
||||
max--
|
||||
count++
|
||||
names = append(names, string(name))
|
||||
}
|
||||
return origlen - len(buf), count, names
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// +build ppc64 s390x mips mips64
|
||||
|
||||
package unix
|
||||
|
||||
const isBigEndian = true
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le riscv64
|
||||
|
||||
package unix
|
||||
|
||||
const isBigEndian = false
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
// 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.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
// Unix environment variables.
|
||||
|
||||
package unix
|
||||
|
||||
import "syscall"
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
return syscall.Getenv(key)
|
||||
}
|
||||
|
||||
func Setenv(key, value string) error {
|
||||
return syscall.Setenv(key, value)
|
||||
}
|
||||
|
||||
func Clearenv() {
|
||||
syscall.Clearenv()
|
||||
}
|
||||
|
||||
func Environ() []string {
|
||||
return syscall.Environ()
|
||||
}
|
||||
|
||||
func Unsetenv(key string) error {
|
||||
return syscall.Unsetenv(key)
|
||||
}
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
// 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.
|
||||
|
||||
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
|
||||
// them here for backwards compatibility.
|
||||
|
||||
package unix
|
||||
|
||||
const (
|
||||
IFF_SMART = 0x20
|
||||
IFT_1822 = 0x2
|
||||
IFT_A12MPPSWITCH = 0x82
|
||||
IFT_AAL2 = 0xbb
|
||||
IFT_AAL5 = 0x31
|
||||
IFT_ADSL = 0x5e
|
||||
IFT_AFLANE8023 = 0x3b
|
||||
IFT_AFLANE8025 = 0x3c
|
||||
IFT_ARAP = 0x58
|
||||
IFT_ARCNET = 0x23
|
||||
IFT_ARCNETPLUS = 0x24
|
||||
IFT_ASYNC = 0x54
|
||||
IFT_ATM = 0x25
|
||||
IFT_ATMDXI = 0x69
|
||||
IFT_ATMFUNI = 0x6a
|
||||
IFT_ATMIMA = 0x6b
|
||||
IFT_ATMLOGICAL = 0x50
|
||||
IFT_ATMRADIO = 0xbd
|
||||
IFT_ATMSUBINTERFACE = 0x86
|
||||
IFT_ATMVCIENDPT = 0xc2
|
||||
IFT_ATMVIRTUAL = 0x95
|
||||
IFT_BGPPOLICYACCOUNTING = 0xa2
|
||||
IFT_BSC = 0x53
|
||||
IFT_CCTEMUL = 0x3d
|
||||
IFT_CEPT = 0x13
|
||||
IFT_CES = 0x85
|
||||
IFT_CHANNEL = 0x46
|
||||
IFT_CNR = 0x55
|
||||
IFT_COFFEE = 0x84
|
||||
IFT_COMPOSITELINK = 0x9b
|
||||
IFT_DCN = 0x8d
|
||||
IFT_DIGITALPOWERLINE = 0x8a
|
||||
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
|
||||
IFT_DLSW = 0x4a
|
||||
IFT_DOCSCABLEDOWNSTREAM = 0x80
|
||||
IFT_DOCSCABLEMACLAYER = 0x7f
|
||||
IFT_DOCSCABLEUPSTREAM = 0x81
|
||||
IFT_DS0 = 0x51
|
||||
IFT_DS0BUNDLE = 0x52
|
||||
IFT_DS1FDL = 0xaa
|
||||
IFT_DS3 = 0x1e
|
||||
IFT_DTM = 0x8c
|
||||
IFT_DVBASILN = 0xac
|
||||
IFT_DVBASIOUT = 0xad
|
||||
IFT_DVBRCCDOWNSTREAM = 0x93
|
||||
IFT_DVBRCCMACLAYER = 0x92
|
||||
IFT_DVBRCCUPSTREAM = 0x94
|
||||
IFT_ENC = 0xf4
|
||||
IFT_EON = 0x19
|
||||
IFT_EPLRS = 0x57
|
||||
IFT_ESCON = 0x49
|
||||
IFT_ETHER = 0x6
|
||||
IFT_FAITH = 0xf2
|
||||
IFT_FAST = 0x7d
|
||||
IFT_FASTETHER = 0x3e
|
||||
IFT_FASTETHERFX = 0x45
|
||||
IFT_FDDI = 0xf
|
||||
IFT_FIBRECHANNEL = 0x38
|
||||
IFT_FRAMERELAYINTERCONNECT = 0x3a
|
||||
IFT_FRAMERELAYMPI = 0x5c
|
||||
IFT_FRDLCIENDPT = 0xc1
|
||||
IFT_FRELAY = 0x20
|
||||
IFT_FRELAYDCE = 0x2c
|
||||
IFT_FRF16MFRBUNDLE = 0xa3
|
||||
IFT_FRFORWARD = 0x9e
|
||||
IFT_G703AT2MB = 0x43
|
||||
IFT_G703AT64K = 0x42
|
||||
IFT_GIF = 0xf0
|
||||
IFT_GIGABITETHERNET = 0x75
|
||||
IFT_GR303IDT = 0xb2
|
||||
IFT_GR303RDT = 0xb1
|
||||
IFT_H323GATEKEEPER = 0xa4
|
||||
IFT_H323PROXY = 0xa5
|
||||
IFT_HDH1822 = 0x3
|
||||
IFT_HDLC = 0x76
|
||||
IFT_HDSL2 = 0xa8
|
||||
IFT_HIPERLAN2 = 0xb7
|
||||
IFT_HIPPI = 0x2f
|
||||
IFT_HIPPIINTERFACE = 0x39
|
||||
IFT_HOSTPAD = 0x5a
|
||||
IFT_HSSI = 0x2e
|
||||
IFT_HY = 0xe
|
||||
IFT_IBM370PARCHAN = 0x48
|
||||
IFT_IDSL = 0x9a
|
||||
IFT_IEEE80211 = 0x47
|
||||
IFT_IEEE80212 = 0x37
|
||||
IFT_IEEE8023ADLAG = 0xa1
|
||||
IFT_IFGSN = 0x91
|
||||
IFT_IMT = 0xbe
|
||||
IFT_INTERLEAVE = 0x7c
|
||||
IFT_IP = 0x7e
|
||||
IFT_IPFORWARD = 0x8e
|
||||
IFT_IPOVERATM = 0x72
|
||||
IFT_IPOVERCDLC = 0x6d
|
||||
IFT_IPOVERCLAW = 0x6e
|
||||
IFT_IPSWITCH = 0x4e
|
||||
IFT_IPXIP = 0xf9
|
||||
IFT_ISDN = 0x3f
|
||||
IFT_ISDNBASIC = 0x14
|
||||
IFT_ISDNPRIMARY = 0x15
|
||||
IFT_ISDNS = 0x4b
|
||||
IFT_ISDNU = 0x4c
|
||||
IFT_ISO88022LLC = 0x29
|
||||
IFT_ISO88023 = 0x7
|
||||
IFT_ISO88024 = 0x8
|
||||
IFT_ISO88025 = 0x9
|
||||
IFT_ISO88025CRFPINT = 0x62
|
||||
IFT_ISO88025DTR = 0x56
|
||||
IFT_ISO88025FIBER = 0x73
|
||||
IFT_ISO88026 = 0xa
|
||||
IFT_ISUP = 0xb3
|
||||
IFT_L3IPXVLAN = 0x89
|
||||
IFT_LAPB = 0x10
|
||||
IFT_LAPD = 0x4d
|
||||
IFT_LAPF = 0x77
|
||||
IFT_LOCALTALK = 0x2a
|
||||
IFT_LOOP = 0x18
|
||||
IFT_MEDIAMAILOVERIP = 0x8b
|
||||
IFT_MFSIGLINK = 0xa7
|
||||
IFT_MIOX25 = 0x26
|
||||
IFT_MODEM = 0x30
|
||||
IFT_MPC = 0x71
|
||||
IFT_MPLS = 0xa6
|
||||
IFT_MPLSTUNNEL = 0x96
|
||||
IFT_MSDSL = 0x8f
|
||||
IFT_MVL = 0xbf
|
||||
IFT_MYRINET = 0x63
|
||||
IFT_NFAS = 0xaf
|
||||
IFT_NSIP = 0x1b
|
||||
IFT_OPTICALCHANNEL = 0xc3
|
||||
IFT_OPTICALTRANSPORT = 0xc4
|
||||
IFT_OTHER = 0x1
|
||||
IFT_P10 = 0xc
|
||||
IFT_P80 = 0xd
|
||||
IFT_PARA = 0x22
|
||||
IFT_PFLOG = 0xf6
|
||||
IFT_PFSYNC = 0xf7
|
||||
IFT_PLC = 0xae
|
||||
IFT_POS = 0xab
|
||||
IFT_PPPMULTILINKBUNDLE = 0x6c
|
||||
IFT_PROPBWAP2MP = 0xb8
|
||||
IFT_PROPCNLS = 0x59
|
||||
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
|
||||
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
|
||||
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
|
||||
IFT_PROPMUX = 0x36
|
||||
IFT_PROPWIRELESSP2P = 0x9d
|
||||
IFT_PTPSERIAL = 0x16
|
||||
IFT_PVC = 0xf1
|
||||
IFT_QLLC = 0x44
|
||||
IFT_RADIOMAC = 0xbc
|
||||
IFT_RADSL = 0x5f
|
||||
IFT_REACHDSL = 0xc0
|
||||
IFT_RFC1483 = 0x9f
|
||||
IFT_RS232 = 0x21
|
||||
IFT_RSRB = 0x4f
|
||||
IFT_SDLC = 0x11
|
||||
IFT_SDSL = 0x60
|
||||
IFT_SHDSL = 0xa9
|
||||
IFT_SIP = 0x1f
|
||||
IFT_SLIP = 0x1c
|
||||
IFT_SMDSDXI = 0x2b
|
||||
IFT_SMDSICIP = 0x34
|
||||
IFT_SONET = 0x27
|
||||
IFT_SONETOVERHEADCHANNEL = 0xb9
|
||||
IFT_SONETPATH = 0x32
|
||||
IFT_SONETVT = 0x33
|
||||
IFT_SRP = 0x97
|
||||
IFT_SS7SIGLINK = 0x9c
|
||||
IFT_STACKTOSTACK = 0x6f
|
||||
IFT_STARLAN = 0xb
|
||||
IFT_STF = 0xd7
|
||||
IFT_T1 = 0x12
|
||||
IFT_TDLC = 0x74
|
||||
IFT_TERMPAD = 0x5b
|
||||
IFT_TR008 = 0xb0
|
||||
IFT_TRANSPHDLC = 0x7b
|
||||
IFT_TUNNEL = 0x83
|
||||
IFT_ULTRA = 0x1d
|
||||
IFT_USB = 0xa0
|
||||
IFT_V11 = 0x40
|
||||
IFT_V35 = 0x2d
|
||||
IFT_V36 = 0x41
|
||||
IFT_V37 = 0x78
|
||||
IFT_VDSL = 0x61
|
||||
IFT_VIRTUALIPADDRESS = 0x70
|
||||
IFT_VOICEEM = 0x64
|
||||
IFT_VOICEENCAP = 0x67
|
||||
IFT_VOICEFXO = 0x65
|
||||
IFT_VOICEFXS = 0x66
|
||||
IFT_VOICEOVERATM = 0x98
|
||||
IFT_VOICEOVERFRAMERELAY = 0x99
|
||||
IFT_VOICEOVERIP = 0x68
|
||||
IFT_X213 = 0x5d
|
||||
IFT_X25 = 0x5
|
||||
IFT_X25DDN = 0x4
|
||||
IFT_X25HUNTGROUP = 0x7a
|
||||
IFT_X25MLP = 0x79
|
||||
IFT_X25PLE = 0x28
|
||||
IFT_XETHER = 0x1a
|
||||
IPPROTO_MAXID = 0x34
|
||||
IPV6_FAITH = 0x1d
|
||||
IP_FAITH = 0x16
|
||||
MAP_NORESERVE = 0x40
|
||||
MAP_RENAME = 0x20
|
||||
NET_RT_MAXID = 0x6
|
||||
RTF_PRCLONING = 0x10000
|
||||
RTM_OLDADD = 0x9
|
||||
RTM_OLDDEL = 0xa
|
||||
SIOCADDRT = 0x8030720a
|
||||
SIOCALIFADDR = 0x8118691b
|
||||
SIOCDELRT = 0x8030720b
|
||||
SIOCDLIFADDR = 0x8118691d
|
||||
SIOCGLIFADDR = 0xc118691c
|
||||
SIOCGLIFPHYADDR = 0xc118694b
|
||||
SIOCSLIFPHYADDR = 0x8118694a
|
||||
)
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
// 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.
|
||||
|
||||
// Constants that were deprecated or moved to enums in the FreeBSD headers. Keep
|
||||
// them here for backwards compatibility.
|
||||
|
||||
package unix
|
||||
|
||||
const (
|
||||
IFF_SMART = 0x20
|
||||
IFT_1822 = 0x2
|
||||
IFT_A12MPPSWITCH = 0x82
|
||||
IFT_AAL2 = 0xbb
|
||||
IFT_AAL5 = 0x31
|
||||
IFT_ADSL = 0x5e
|
||||
IFT_AFLANE8023 = 0x3b
|
||||
IFT_AFLANE8025 = 0x3c
|
||||
IFT_ARAP = 0x58
|
||||
IFT_ARCNET = 0x23
|
||||
IFT_ARCNETPLUS = 0x24
|
||||
IFT_ASYNC = 0x54
|
||||
IFT_ATM = 0x25
|
||||
IFT_ATMDXI = 0x69
|
||||
IFT_ATMFUNI = 0x6a
|
||||
IFT_ATMIMA = 0x6b
|
||||
IFT_ATMLOGICAL = 0x50
|
||||
IFT_ATMRADIO = 0xbd
|
||||
IFT_ATMSUBINTERFACE = 0x86
|
||||
IFT_ATMVCIENDPT = 0xc2
|
||||
IFT_ATMVIRTUAL = 0x95
|
||||
IFT_BGPPOLICYACCOUNTING = 0xa2
|
||||
IFT_BSC = 0x53
|
||||
IFT_CCTEMUL = 0x3d
|
||||
IFT_CEPT = 0x13
|
||||
IFT_CES = 0x85
|
||||
IFT_CHANNEL = 0x46
|
||||
IFT_CNR = 0x55
|
||||
IFT_COFFEE = 0x84
|
||||
IFT_COMPOSITELINK = 0x9b
|
||||
IFT_DCN = 0x8d
|
||||
IFT_DIGITALPOWERLINE = 0x8a
|
||||
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
|
||||
IFT_DLSW = 0x4a
|
||||
IFT_DOCSCABLEDOWNSTREAM = 0x80
|
||||
IFT_DOCSCABLEMACLAYER = 0x7f
|
||||
IFT_DOCSCABLEUPSTREAM = 0x81
|
||||
IFT_DS0 = 0x51
|
||||
IFT_DS0BUNDLE = 0x52
|
||||
IFT_DS1FDL = 0xaa
|
||||
IFT_DS3 = 0x1e
|
||||
IFT_DTM = 0x8c
|
||||
IFT_DVBASILN = 0xac
|
||||
IFT_DVBASIOUT = 0xad
|
||||
IFT_DVBRCCDOWNSTREAM = 0x93
|
||||
IFT_DVBRCCMACLAYER = 0x92
|
||||
IFT_DVBRCCUPSTREAM = 0x94
|
||||
IFT_ENC = 0xf4
|
||||
IFT_EON = 0x19
|
||||
IFT_EPLRS = 0x57
|
||||
IFT_ESCON = 0x49
|
||||
IFT_ETHER = 0x6
|
||||
IFT_FAITH = 0xf2
|
||||
IFT_FAST = 0x7d
|
||||
IFT_FASTETHER = 0x3e
|
||||
IFT_FASTETHERFX = 0x45
|
||||
IFT_FDDI = 0xf
|
||||
IFT_FIBRECHANNEL = 0x38
|
||||
IFT_FRAMERELAYINTERCONNECT = 0x3a
|
||||
IFT_FRAMERELAYMPI = 0x5c
|
||||
IFT_FRDLCIENDPT = 0xc1
|
||||
IFT_FRELAY = 0x20
|
||||
IFT_FRELAYDCE = 0x2c
|
||||
IFT_FRF16MFRBUNDLE = 0xa3
|
||||
IFT_FRFORWARD = 0x9e
|
||||
IFT_G703AT2MB = 0x43
|
||||
IFT_G703AT64K = 0x42
|
||||
IFT_GIF = 0xf0
|
||||
IFT_GIGABITETHERNET = 0x75
|
||||
IFT_GR303IDT = 0xb2
|
||||
IFT_GR303RDT = 0xb1
|
||||
IFT_H323GATEKEEPER = 0xa4
|
||||
IFT_H323PROXY = 0xa5
|
||||
IFT_HDH1822 = 0x3
|
||||
IFT_HDLC = 0x76
|
||||
IFT_HDSL2 = 0xa8
|
||||
IFT_HIPERLAN2 = 0xb7
|
||||
IFT_HIPPI = 0x2f
|
||||
IFT_HIPPIINTERFACE = 0x39
|
||||
IFT_HOSTPAD = 0x5a
|
||||
IFT_HSSI = 0x2e
|
||||
IFT_HY = 0xe
|
||||
IFT_IBM370PARCHAN = 0x48
|
||||
IFT_IDSL = 0x9a
|
||||
IFT_IEEE80211 = 0x47
|
||||
IFT_IEEE80212 = 0x37
|
||||
IFT_IEEE8023ADLAG = 0xa1
|
||||
IFT_IFGSN = 0x91
|
||||
IFT_IMT = 0xbe
|
||||
IFT_INTERLEAVE = 0x7c
|
||||
IFT_IP = 0x7e
|
||||
IFT_IPFORWARD = 0x8e
|
||||
IFT_IPOVERATM = 0x72
|
||||
IFT_IPOVERCDLC = 0x6d
|
||||
IFT_IPOVERCLAW = 0x6e
|
||||
IFT_IPSWITCH = 0x4e
|
||||
IFT_IPXIP = 0xf9
|
||||
IFT_ISDN = 0x3f
|
||||
IFT_ISDNBASIC = 0x14
|
||||
IFT_ISDNPRIMARY = 0x15
|
||||
IFT_ISDNS = 0x4b
|
||||
IFT_ISDNU = 0x4c
|
||||
IFT_ISO88022LLC = 0x29
|
||||
IFT_ISO88023 = 0x7
|
||||
IFT_ISO88024 = 0x8
|
||||
IFT_ISO88025 = 0x9
|
||||
IFT_ISO88025CRFPINT = 0x62
|
||||
IFT_ISO88025DTR = 0x56
|
||||
IFT_ISO88025FIBER = 0x73
|
||||
IFT_ISO88026 = 0xa
|
||||
IFT_ISUP = 0xb3
|
||||
IFT_L3IPXVLAN = 0x89
|
||||
IFT_LAPB = 0x10
|
||||
IFT_LAPD = 0x4d
|
||||
IFT_LAPF = 0x77
|
||||
IFT_LOCALTALK = 0x2a
|
||||
IFT_LOOP = 0x18
|
||||
IFT_MEDIAMAILOVERIP = 0x8b
|
||||
IFT_MFSIGLINK = 0xa7
|
||||
IFT_MIOX25 = 0x26
|
||||
IFT_MODEM = 0x30
|
||||
IFT_MPC = 0x71
|
||||
IFT_MPLS = 0xa6
|
||||
IFT_MPLSTUNNEL = 0x96
|
||||
IFT_MSDSL = 0x8f
|
||||
IFT_MVL = 0xbf
|
||||
IFT_MYRINET = 0x63
|
||||
IFT_NFAS = 0xaf
|
||||
IFT_NSIP = 0x1b
|
||||
IFT_OPTICALCHANNEL = 0xc3
|
||||
IFT_OPTICALTRANSPORT = 0xc4
|
||||
IFT_OTHER = 0x1
|
||||
IFT_P10 = 0xc
|
||||
IFT_P80 = 0xd
|
||||
IFT_PARA = 0x22
|
||||
IFT_PFLOG = 0xf6
|
||||
IFT_PFSYNC = 0xf7
|
||||
IFT_PLC = 0xae
|
||||
IFT_POS = 0xab
|
||||
IFT_PPPMULTILINKBUNDLE = 0x6c
|
||||
IFT_PROPBWAP2MP = 0xb8
|
||||
IFT_PROPCNLS = 0x59
|
||||
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
|
||||
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
|
||||
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
|
||||
IFT_PROPMUX = 0x36
|
||||
IFT_PROPWIRELESSP2P = 0x9d
|
||||
IFT_PTPSERIAL = 0x16
|
||||
IFT_PVC = 0xf1
|
||||
IFT_QLLC = 0x44
|
||||
IFT_RADIOMAC = 0xbc
|
||||
IFT_RADSL = 0x5f
|
||||
IFT_REACHDSL = 0xc0
|
||||
IFT_RFC1483 = 0x9f
|
||||
IFT_RS232 = 0x21
|
||||
IFT_RSRB = 0x4f
|
||||
IFT_SDLC = 0x11
|
||||
IFT_SDSL = 0x60
|
||||
IFT_SHDSL = 0xa9
|
||||
IFT_SIP = 0x1f
|
||||
IFT_SLIP = 0x1c
|
||||
IFT_SMDSDXI = 0x2b
|
||||
IFT_SMDSICIP = 0x34
|
||||
IFT_SONET = 0x27
|
||||
IFT_SONETOVERHEADCHANNEL = 0xb9
|
||||
IFT_SONETPATH = 0x32
|
||||
IFT_SONETVT = 0x33
|
||||
IFT_SRP = 0x97
|
||||
IFT_SS7SIGLINK = 0x9c
|
||||
IFT_STACKTOSTACK = 0x6f
|
||||
IFT_STARLAN = 0xb
|
||||
IFT_STF = 0xd7
|
||||
IFT_T1 = 0x12
|
||||
IFT_TDLC = 0x74
|
||||
IFT_TERMPAD = 0x5b
|
||||
IFT_TR008 = 0xb0
|
||||
IFT_TRANSPHDLC = 0x7b
|
||||
IFT_TUNNEL = 0x83
|
||||
IFT_ULTRA = 0x1d
|
||||
IFT_USB = 0xa0
|
||||
IFT_V11 = 0x40
|
||||
IFT_V35 = 0x2d
|
||||
IFT_V36 = 0x41
|
||||
IFT_V37 = 0x78
|
||||
IFT_VDSL = 0x61
|
||||
IFT_VIRTUALIPADDRESS = 0x70
|
||||
IFT_VOICEEM = 0x64
|
||||
IFT_VOICEENCAP = 0x67
|
||||
IFT_VOICEFXO = 0x65
|
||||
IFT_VOICEFXS = 0x66
|
||||
IFT_VOICEOVERATM = 0x98
|
||||
IFT_VOICEOVERFRAMERELAY = 0x99
|
||||
IFT_VOICEOVERIP = 0x68
|
||||
IFT_X213 = 0x5d
|
||||
IFT_X25 = 0x5
|
||||
IFT_X25DDN = 0x4
|
||||
IFT_X25HUNTGROUP = 0x7a
|
||||
IFT_X25MLP = 0x79
|
||||
IFT_X25PLE = 0x28
|
||||
IFT_XETHER = 0x1a
|
||||
IPPROTO_MAXID = 0x34
|
||||
IPV6_FAITH = 0x1d
|
||||
IP_FAITH = 0x16
|
||||
MAP_NORESERVE = 0x40
|
||||
MAP_RENAME = 0x20
|
||||
NET_RT_MAXID = 0x6
|
||||
RTF_PRCLONING = 0x10000
|
||||
RTM_OLDADD = 0x9
|
||||
RTM_OLDDEL = 0xa
|
||||
SIOCADDRT = 0x8040720a
|
||||
SIOCALIFADDR = 0x8118691b
|
||||
SIOCDELRT = 0x8040720b
|
||||
SIOCDLIFADDR = 0x8118691d
|
||||
SIOCGLIFADDR = 0xc118691c
|
||||
SIOCGLIFPHYADDR = 0xc118694b
|
||||
SIOCSLIFPHYADDR = 0x8118694a
|
||||
)
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
// 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 unix
|
||||
|
||||
const (
|
||||
IFT_1822 = 0x2
|
||||
IFT_A12MPPSWITCH = 0x82
|
||||
IFT_AAL2 = 0xbb
|
||||
IFT_AAL5 = 0x31
|
||||
IFT_ADSL = 0x5e
|
||||
IFT_AFLANE8023 = 0x3b
|
||||
IFT_AFLANE8025 = 0x3c
|
||||
IFT_ARAP = 0x58
|
||||
IFT_ARCNET = 0x23
|
||||
IFT_ARCNETPLUS = 0x24
|
||||
IFT_ASYNC = 0x54
|
||||
IFT_ATM = 0x25
|
||||
IFT_ATMDXI = 0x69
|
||||
IFT_ATMFUNI = 0x6a
|
||||
IFT_ATMIMA = 0x6b
|
||||
IFT_ATMLOGICAL = 0x50
|
||||
IFT_ATMRADIO = 0xbd
|
||||
IFT_ATMSUBINTERFACE = 0x86
|
||||
IFT_ATMVCIENDPT = 0xc2
|
||||
IFT_ATMVIRTUAL = 0x95
|
||||
IFT_BGPPOLICYACCOUNTING = 0xa2
|
||||
IFT_BSC = 0x53
|
||||
IFT_CCTEMUL = 0x3d
|
||||
IFT_CEPT = 0x13
|
||||
IFT_CES = 0x85
|
||||
IFT_CHANNEL = 0x46
|
||||
IFT_CNR = 0x55
|
||||
IFT_COFFEE = 0x84
|
||||
IFT_COMPOSITELINK = 0x9b
|
||||
IFT_DCN = 0x8d
|
||||
IFT_DIGITALPOWERLINE = 0x8a
|
||||
IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
|
||||
IFT_DLSW = 0x4a
|
||||
IFT_DOCSCABLEDOWNSTREAM = 0x80
|
||||
IFT_DOCSCABLEMACLAYER = 0x7f
|
||||
IFT_DOCSCABLEUPSTREAM = 0x81
|
||||
IFT_DS0 = 0x51
|
||||
IFT_DS0BUNDLE = 0x52
|
||||
IFT_DS1FDL = 0xaa
|
||||
IFT_DS3 = 0x1e
|
||||
IFT_DTM = 0x8c
|
||||
IFT_DVBASILN = 0xac
|
||||
IFT_DVBASIOUT = 0xad
|
||||
IFT_DVBRCCDOWNSTREAM = 0x93
|
||||
IFT_DVBRCCMACLAYER = 0x92
|
||||
IFT_DVBRCCUPSTREAM = 0x94
|
||||
IFT_ENC = 0xf4
|
||||
IFT_EON = 0x19
|
||||
IFT_EPLRS = 0x57
|
||||
IFT_ESCON = 0x49
|
||||
IFT_ETHER = 0x6
|
||||
IFT_FAST = 0x7d
|
||||
IFT_FASTETHER = 0x3e
|
||||
IFT_FASTETHERFX = 0x45
|
||||
IFT_FDDI = 0xf
|
||||
IFT_FIBRECHANNEL = 0x38
|
||||
IFT_FRAMERELAYINTERCONNECT = 0x3a
|
||||
IFT_FRAMERELAYMPI = 0x5c
|
||||
IFT_FRDLCIENDPT = 0xc1
|
||||
IFT_FRELAY = 0x20
|
||||
IFT_FRELAYDCE = 0x2c
|
||||
IFT_FRF16MFRBUNDLE = 0xa3
|
||||
IFT_FRFORWARD = 0x9e
|
||||
IFT_G703AT2MB = 0x43
|
||||
IFT_G703AT64K = 0x42
|
||||
IFT_GIF = 0xf0
|
||||
IFT_GIGABITETHERNET = 0x75
|
||||
IFT_GR303IDT = 0xb2
|
||||
IFT_GR303RDT = 0xb1
|
||||
IFT_H323GATEKEEPER = 0xa4
|
||||
IFT_H323PROXY = 0xa5
|
||||
IFT_HDH1822 = 0x3
|
||||
IFT_HDLC = 0x76
|
||||
IFT_HDSL2 = 0xa8
|
||||
IFT_HIPERLAN2 = 0xb7
|
||||
IFT_HIPPI = 0x2f
|
||||
IFT_HIPPIINTERFACE = 0x39
|
||||
IFT_HOSTPAD = 0x5a
|
||||
IFT_HSSI = 0x2e
|
||||
IFT_HY = 0xe
|
||||
IFT_IBM370PARCHAN = 0x48
|
||||
IFT_IDSL = 0x9a
|
||||
IFT_IEEE80211 = 0x47
|
||||
IFT_IEEE80212 = 0x37
|
||||
IFT_IEEE8023ADLAG = 0xa1
|
||||
IFT_IFGSN = 0x91
|
||||
IFT_IMT = 0xbe
|
||||
IFT_INTERLEAVE = 0x7c
|
||||
IFT_IP = 0x7e
|
||||
IFT_IPFORWARD = 0x8e
|
||||
IFT_IPOVERATM = 0x72
|
||||
IFT_IPOVERCDLC = 0x6d
|
||||
IFT_IPOVERCLAW = 0x6e
|
||||
IFT_IPSWITCH = 0x4e
|
||||
IFT_ISDN = 0x3f
|
||||
IFT_ISDNBASIC = 0x14
|
||||
IFT_ISDNPRIMARY = 0x15
|
||||
IFT_ISDNS = 0x4b
|
||||
IFT_ISDNU = 0x4c
|
||||
IFT_ISO88022LLC = 0x29
|
||||
IFT_ISO88023 = 0x7
|
||||
IFT_ISO88024 = 0x8
|
||||
IFT_ISO88025 = 0x9
|
||||
IFT_ISO88025CRFPINT = 0x62
|
||||
IFT_ISO88025DTR = 0x56
|
||||
IFT_ISO88025FIBER = 0x73
|
||||
IFT_ISO88026 = 0xa
|
||||
IFT_ISUP = 0xb3
|
||||
IFT_L3IPXVLAN = 0x89
|
||||
IFT_LAPB = 0x10
|
||||
IFT_LAPD = 0x4d
|
||||
IFT_LAPF = 0x77
|
||||
IFT_LOCALTALK = 0x2a
|
||||
IFT_LOOP = 0x18
|
||||
IFT_MEDIAMAILOVERIP = 0x8b
|
||||
IFT_MFSIGLINK = 0xa7
|
||||
IFT_MIOX25 = 0x26
|
||||
IFT_MODEM = 0x30
|
||||
IFT_MPC = 0x71
|
||||
IFT_MPLS = 0xa6
|
||||
IFT_MPLSTUNNEL = 0x96
|
||||
IFT_MSDSL = 0x8f
|
||||
IFT_MVL = 0xbf
|
||||
IFT_MYRINET = 0x63
|
||||
IFT_NFAS = 0xaf
|
||||
IFT_NSIP = 0x1b
|
||||
IFT_OPTICALCHANNEL = 0xc3
|
||||
IFT_OPTICALTRANSPORT = 0xc4
|
||||
IFT_OTHER = 0x1
|
||||
IFT_P10 = 0xc
|
||||
IFT_P80 = 0xd
|
||||
IFT_PARA = 0x22
|
||||
IFT_PFLOG = 0xf6
|
||||
IFT_PFSYNC = 0xf7
|
||||
IFT_PLC = 0xae
|
||||
IFT_POS = 0xab
|
||||
IFT_PPPMULTILINKBUNDLE = 0x6c
|
||||
IFT_PROPBWAP2MP = 0xb8
|
||||
IFT_PROPCNLS = 0x59
|
||||
IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
|
||||
IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
|
||||
IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
|
||||
IFT_PROPMUX = 0x36
|
||||
IFT_PROPWIRELESSP2P = 0x9d
|
||||
IFT_PTPSERIAL = 0x16
|
||||
IFT_PVC = 0xf1
|
||||
IFT_QLLC = 0x44
|
||||
IFT_RADIOMAC = 0xbc
|
||||
IFT_RADSL = 0x5f
|
||||
IFT_REACHDSL = 0xc0
|
||||
IFT_RFC1483 = 0x9f
|
||||
IFT_RS232 = 0x21
|
||||
IFT_RSRB = 0x4f
|
||||
IFT_SDLC = 0x11
|
||||
IFT_SDSL = 0x60
|
||||
IFT_SHDSL = 0xa9
|
||||
IFT_SIP = 0x1f
|
||||
IFT_SLIP = 0x1c
|
||||
IFT_SMDSDXI = 0x2b
|
||||
IFT_SMDSICIP = 0x34
|
||||
IFT_SONET = 0x27
|
||||
IFT_SONETOVERHEADCHANNEL = 0xb9
|
||||
IFT_SONETPATH = 0x32
|
||||
IFT_SONETVT = 0x33
|
||||
IFT_SRP = 0x97
|
||||
IFT_SS7SIGLINK = 0x9c
|
||||
IFT_STACKTOSTACK = 0x6f
|
||||
IFT_STARLAN = 0xb
|
||||
IFT_STF = 0xd7
|
||||
IFT_T1 = 0x12
|
||||
IFT_TDLC = 0x74
|
||||
IFT_TERMPAD = 0x5b
|
||||
IFT_TR008 = 0xb0
|
||||
IFT_TRANSPHDLC = 0x7b
|
||||
IFT_TUNNEL = 0x83
|
||||
IFT_ULTRA = 0x1d
|
||||
IFT_USB = 0xa0
|
||||
IFT_V11 = 0x40
|
||||
IFT_V35 = 0x2d
|
||||
IFT_V36 = 0x41
|
||||
IFT_V37 = 0x78
|
||||
IFT_VDSL = 0x61
|
||||
IFT_VIRTUALIPADDRESS = 0x70
|
||||
IFT_VOICEEM = 0x64
|
||||
IFT_VOICEENCAP = 0x67
|
||||
IFT_VOICEFXO = 0x65
|
||||
IFT_VOICEFXS = 0x66
|
||||
IFT_VOICEOVERATM = 0x98
|
||||
IFT_VOICEOVERFRAMERELAY = 0x99
|
||||
IFT_VOICEOVERIP = 0x68
|
||||
IFT_X213 = 0x5d
|
||||
IFT_X25 = 0x5
|
||||
IFT_X25DDN = 0x4
|
||||
IFT_X25HUNTGROUP = 0x7a
|
||||
IFT_X25MLP = 0x79
|
||||
IFT_X25PLE = 0x28
|
||||
IFT_XETHER = 0x1a
|
||||
|
||||
// missing constants on FreeBSD-11.1-RELEASE, copied from old values in ztypes_freebsd_arm.go
|
||||
IFF_SMART = 0x20
|
||||
IFT_FAITH = 0xf2
|
||||
IFT_IPXIP = 0xf9
|
||||
IPPROTO_MAXID = 0x34
|
||||
IPV6_FAITH = 0x1d
|
||||
IP_FAITH = 0x16
|
||||
MAP_NORESERVE = 0x40
|
||||
MAP_RENAME = 0x20
|
||||
NET_RT_MAXID = 0x6
|
||||
RTF_PRCLONING = 0x10000
|
||||
RTM_OLDADD = 0x9
|
||||
RTM_OLDDEL = 0xa
|
||||
SIOCADDRT = 0x8030720a
|
||||
SIOCALIFADDR = 0x8118691b
|
||||
SIOCDELRT = 0x8030720b
|
||||
SIOCDLIFADDR = 0x8118691d
|
||||
SIOCGLIFADDR = 0xc118691c
|
||||
SIOCGLIFPHYADDR = 0xc118694b
|
||||
SIOCSLIFPHYADDR = 0x8118694a
|
||||
)
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// 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.
|
||||
|
||||
// +build dragonfly freebsd linux netbsd openbsd
|
||||
|
||||
package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
|
||||
// systems by flock_linux_32bit.go to be SYS_FCNTL64.
|
||||
var fcntl64Syscall uintptr = SYS_FCNTL
|
||||
|
||||
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
|
||||
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
||||
valptr, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(arg))
|
||||
var err error
|
||||
if errno != 0 {
|
||||
err = errno
|
||||
}
|
||||
return int(valptr), err
|
||||
}
|
||||
|
||||
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
|
||||
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
|
||||
_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
|
||||
if errno == 0 {
|
||||
return nil
|
||||
}
|
||||
return errno
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// 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 unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
|
||||
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
||||
return fcntl(int(fd), cmd, arg)
|
||||
}
|
||||
|
||||
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
|
||||
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
|
||||
_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk))))
|
||||
return err
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// +build linux,386 linux,arm linux,mips linux,mipsle
|
||||
|
||||
// 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 unix
|
||||
|
||||
func init() {
|
||||
// On 32-bit Linux systems, the fcntl syscall that matches Go's
|
||||
// Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
|
||||
fcntl64Syscall = SYS_FCNTL64
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build gccgo
|
||||
// +build !aix
|
||||
|
||||
package unix
|
||||
|
||||
import "syscall"
|
||||
|
||||
// We can't use the gc-syntax .s files for gccgo. On the plus side
|
||||
// much of the functionality can be written directly in Go.
|
||||
|
||||
//extern gccgoRealSyscallNoError
|
||||
func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr)
|
||||
|
||||
//extern gccgoRealSyscall
|
||||
func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr)
|
||||
|
||||
func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
|
||||
syscall.Entersyscall()
|
||||
r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
|
||||
syscall.Exitsyscall()
|
||||
return r, 0
|
||||
}
|
||||
|
||||
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
syscall.Entersyscall()
|
||||
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
|
||||
syscall.Exitsyscall()
|
||||
return r, 0, syscall.Errno(errno)
|
||||
}
|
||||
|
||||
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
syscall.Entersyscall()
|
||||
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
|
||||
syscall.Exitsyscall()
|
||||
return r, 0, syscall.Errno(errno)
|
||||
}
|
||||
|
||||
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
syscall.Entersyscall()
|
||||
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9)
|
||||
syscall.Exitsyscall()
|
||||
return r, 0, syscall.Errno(errno)
|
||||
}
|
||||
|
||||
func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
|
||||
r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
|
||||
return r, 0
|
||||
}
|
||||
|
||||
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
|
||||
return r, 0, syscall.Errno(errno)
|
||||
}
|
||||
|
||||
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
|
||||
return r, 0, syscall.Errno(errno)
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build gccgo
|
||||
// +build !aix
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define _STRINGIFY2_(x) #x
|
||||
#define _STRINGIFY_(x) _STRINGIFY2_(x)
|
||||
#define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__)
|
||||
|
||||
// Call syscall from C code because the gccgo support for calling from
|
||||
// Go to C does not support varargs functions.
|
||||
|
||||
struct ret {
|
||||
uintptr_t r;
|
||||
uintptr_t err;
|
||||
};
|
||||
|
||||
struct ret
|
||||
gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
|
||||
{
|
||||
struct ret r;
|
||||
|
||||
errno = 0;
|
||||
r.r = syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
r.err = errno;
|
||||
return r;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
|
||||
{
|
||||
return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build gccgo,linux,amd64
|
||||
|
||||
package unix
|
||||
|
||||
import "syscall"
|
||||
|
||||
//extern gettimeofday
|
||||
func realGettimeofday(*Timeval, *byte) int32
|
||||
|
||||
func gettimeofday(tv *Timeval) (err syscall.Errno) {
|
||||
r := realGettimeofday(tv, nil)
|
||||
if r < 0 {
|
||||
return syscall.GetErrno()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// 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.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
package unix
|
||||
|
||||
import "runtime"
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
//
|
||||
// To change fd's window size, the req argument should be TIOCSWINSZ.
|
||||
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
|
||||
// TODO: if we get the chance, remove the req parameter and
|
||||
// hardcode TIOCSWINSZ.
|
||||
err := ioctlSetWinsize(fd, req, value)
|
||||
runtime.KeepAlive(value)
|
||||
return err
|
||||
}
|
||||
|
||||
// IoctlSetTermios performs an ioctl on fd with a *Termios.
|
||||
//
|
||||
// The req value will usually be TCSETA or TIOCSETA.
|
||||
func IoctlSetTermios(fd int, req uint, value *Termios) error {
|
||||
// TODO: if we get the chance, remove the req parameter.
|
||||
err := ioctlSetTermios(fd, req, value)
|
||||
runtime.KeepAlive(value)
|
||||
return err
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user