Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / godoc / vfs / zipfs / zipfs.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/godoc/vfs/zipfs/zipfs.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/godoc/vfs/zipfs/zipfs.go
new file mode 100644 (file)
index 0000000..a82febe
--- /dev/null
@@ -0,0 +1,291 @@
+// 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 zipfs file provides an implementation of the FileSystem
+// interface based on the contents of a .zip file.
+//
+// Assumptions:
+//
+//  - The file paths stored in the zip file must use a slash ('/') as path
+//    separator; and they must be relative (i.e., they must not start with
+//    a '/' - this is usually the case if the file was created w/o special
+//    options).
+//  - The zip file system treats the file paths found in the zip internally
+//    like absolute paths w/o a leading '/'; i.e., the paths are considered
+//    relative to the root of the file system.
+//  - All path arguments to file system methods must be absolute paths.
+package zipfs // import "golang.org/x/tools/godoc/vfs/zipfs"
+
+import (
+       "archive/zip"
+       "fmt"
+       "go/build"
+       "io"
+       "os"
+       "path"
+       "path/filepath"
+       "sort"
+       "strings"
+       "time"
+
+       "golang.org/x/tools/godoc/vfs"
+)
+
+// zipFI is the zip-file based implementation of FileInfo
+type zipFI struct {
+       name string    // directory-local name
+       file *zip.File // nil for a directory
+}
+
+func (fi zipFI) Name() string {
+       return fi.name
+}
+
+func (fi zipFI) Size() int64 {
+       if f := fi.file; f != nil {
+               return int64(f.UncompressedSize)
+       }
+       return 0 // directory
+}
+
+func (fi zipFI) ModTime() time.Time {
+       if f := fi.file; f != nil {
+               return f.ModTime()
+       }
+       return time.Time{} // directory has no modified time entry
+}
+
+func (fi zipFI) Mode() os.FileMode {
+       if fi.file == nil {
+               // Unix directories typically are executable, hence 555.
+               return os.ModeDir | 0555
+       }
+       return 0444
+}
+
+func (fi zipFI) IsDir() bool {
+       return fi.file == nil
+}
+
+func (fi zipFI) Sys() interface{} {
+       return nil
+}
+
+// zipFS is the zip-file based implementation of FileSystem
+type zipFS struct {
+       *zip.ReadCloser
+       list zipList
+       name string
+}
+
+func (fs *zipFS) String() string {
+       return "zip(" + fs.name + ")"
+}
+
+func (fs *zipFS) RootType(abspath string) vfs.RootType {
+       var t vfs.RootType
+       switch {
+       case exists(path.Join(vfs.GOROOT, abspath)):
+               t = vfs.RootTypeGoRoot
+       case isGoPath(abspath):
+               t = vfs.RootTypeGoPath
+       }
+       return t
+}
+
+func isGoPath(abspath string) bool {
+       for _, p := range filepath.SplitList(build.Default.GOPATH) {
+               if exists(path.Join(p, abspath)) {
+                       return true
+               }
+       }
+       return false
+}
+
+func exists(path string) bool {
+       _, err := os.Stat(path)
+       return err == nil
+}
+
+func (fs *zipFS) Close() error {
+       fs.list = nil
+       return fs.ReadCloser.Close()
+}
+
+func zipPath(name string) (string, error) {
+       name = path.Clean(name)
+       if !path.IsAbs(name) {
+               return "", fmt.Errorf("stat: not an absolute path: %s", name)
+       }
+       return name[1:], nil // strip leading '/'
+}
+
+func isRoot(abspath string) bool {
+       return path.Clean(abspath) == "/"
+}
+
+func (fs *zipFS) stat(abspath string) (int, zipFI, error) {
+       if isRoot(abspath) {
+               return 0, zipFI{
+                       name: "",
+                       file: nil,
+               }, nil
+       }
+       zippath, err := zipPath(abspath)
+       if err != nil {
+               return 0, zipFI{}, err
+       }
+       i, exact := fs.list.lookup(zippath)
+       if i < 0 {
+               // zippath has leading '/' stripped - print it explicitly
+               return -1, zipFI{}, &os.PathError{Path: "/" + zippath, Err: os.ErrNotExist}
+       }
+       _, name := path.Split(zippath)
+       var file *zip.File
+       if exact {
+               file = fs.list[i] // exact match found - must be a file
+       }
+       return i, zipFI{name, file}, nil
+}
+
+func (fs *zipFS) Open(abspath string) (vfs.ReadSeekCloser, error) {
+       _, fi, err := fs.stat(abspath)
+       if err != nil {
+               return nil, err
+       }
+       if fi.IsDir() {
+               return nil, fmt.Errorf("Open: %s is a directory", abspath)
+       }
+       r, err := fi.file.Open()
+       if err != nil {
+               return nil, err
+       }
+       return &zipSeek{fi.file, r}, nil
+}
+
+type zipSeek struct {
+       file *zip.File
+       io.ReadCloser
+}
+
+func (f *zipSeek) Seek(offset int64, whence int) (int64, error) {
+       if whence == 0 && offset == 0 {
+               r, err := f.file.Open()
+               if err != nil {
+                       return 0, err
+               }
+               f.Close()
+               f.ReadCloser = r
+               return 0, nil
+       }
+       return 0, fmt.Errorf("unsupported Seek in %s", f.file.Name)
+}
+
+func (fs *zipFS) Lstat(abspath string) (os.FileInfo, error) {
+       _, fi, err := fs.stat(abspath)
+       return fi, err
+}
+
+func (fs *zipFS) Stat(abspath string) (os.FileInfo, error) {
+       _, fi, err := fs.stat(abspath)
+       return fi, err
+}
+
+func (fs *zipFS) ReadDir(abspath string) ([]os.FileInfo, error) {
+       i, fi, err := fs.stat(abspath)
+       if err != nil {
+               return nil, err
+       }
+       if !fi.IsDir() {
+               return nil, fmt.Errorf("ReadDir: %s is not a directory", abspath)
+       }
+
+       var list []os.FileInfo
+
+       // make dirname the prefix that file names must start with to be considered
+       // in this directory. we must special case the root directory because, per
+       // the spec of this package, zip file entries MUST NOT start with /, so we
+       // should not append /, as we would in every other case.
+       var dirname string
+       if isRoot(abspath) {
+               dirname = ""
+       } else {
+               zippath, err := zipPath(abspath)
+               if err != nil {
+                       return nil, err
+               }
+               dirname = zippath + "/"
+       }
+       prevname := ""
+       for _, e := range fs.list[i:] {
+               if !strings.HasPrefix(e.Name, dirname) {
+                       break // not in the same directory anymore
+               }
+               name := e.Name[len(dirname):] // local name
+               file := e
+               if i := strings.IndexRune(name, '/'); i >= 0 {
+                       // We infer directories from files in subdirectories.
+                       // If we have x/y, return a directory entry for x.
+                       name = name[0:i] // keep local directory name only
+                       file = nil
+               }
+               // If we have x/y and x/z, don't return two directory entries for x.
+               // TODO(gri): It should be possible to do this more efficiently
+               // by determining the (fs.list) range of local directory entries
+               // (via two binary searches).
+               if name != prevname {
+                       list = append(list, zipFI{name, file})
+                       prevname = name
+               }
+       }
+
+       return list, nil
+}
+
+func New(rc *zip.ReadCloser, name string) vfs.FileSystem {
+       list := make(zipList, len(rc.File))
+       copy(list, rc.File) // sort a copy of rc.File
+       sort.Sort(list)
+       return &zipFS{rc, list, name}
+}
+
+type zipList []*zip.File
+
+// zipList implements sort.Interface
+func (z zipList) Len() int           { return len(z) }
+func (z zipList) Less(i, j int) bool { return z[i].Name < z[j].Name }
+func (z zipList) Swap(i, j int)      { z[i], z[j] = z[j], z[i] }
+
+// lookup returns the smallest index of an entry with an exact match
+// for name, or an inexact match starting with name/. If there is no
+// such entry, the result is -1, false.
+func (z zipList) lookup(name string) (index int, exact bool) {
+       // look for exact match first (name comes before name/ in z)
+       i := sort.Search(len(z), func(i int) bool {
+               return name <= z[i].Name
+       })
+       if i >= len(z) {
+               return -1, false
+       }
+       // 0 <= i < len(z)
+       if z[i].Name == name {
+               return i, true
+       }
+
+       // look for inexact match (must be in z[i:], if present)
+       z = z[i:]
+       name += "/"
+       j := sort.Search(len(z), func(i int) bool {
+               return name <= z[i].Name
+       })
+       if j >= len(z) {
+               return -1, false
+       }
+       // 0 <= j < len(z)
+       if strings.HasPrefix(z[j].Name, name) {
+               return i + j, false
+       }
+
+       return -1, false
+}