--- /dev/null
+// 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 mapfs file provides an implementation of the FileSystem
+// interface based on the contents of a map[string]string.
+package mapfs // import "golang.org/x/tools/godoc/vfs/mapfs"
+
+import (
+ "fmt"
+ "io"
+ "os"
+ pathpkg "path"
+ "sort"
+ "strings"
+ "time"
+
+ "golang.org/x/tools/godoc/vfs"
+)
+
+// New returns a new FileSystem from the provided map.
+// Map keys must be forward slash-separated paths with
+// no leading slash, such as "file1.txt" or "dir/file2.txt".
+// New panics if any of the paths contain a leading slash.
+func New(m map[string]string) vfs.FileSystem {
+ // Verify all provided paths are relative before proceeding.
+ var pathsWithLeadingSlash []string
+ for p := range m {
+ if strings.HasPrefix(p, "/") {
+ pathsWithLeadingSlash = append(pathsWithLeadingSlash, p)
+ }
+ }
+ if len(pathsWithLeadingSlash) > 0 {
+ panic(fmt.Errorf("mapfs.New: invalid paths with a leading slash: %q", pathsWithLeadingSlash))
+ }
+
+ return mapFS(m)
+}
+
+// mapFS is the map based implementation of FileSystem
+type mapFS map[string]string
+
+func (fs mapFS) String() string { return "mapfs" }
+
+func (fs mapFS) RootType(p string) vfs.RootType {
+ return ""
+}
+
+func (fs mapFS) Close() error { return nil }
+
+func filename(p string) string {
+ return strings.TrimPrefix(p, "/")
+}
+
+func (fs mapFS) Open(p string) (vfs.ReadSeekCloser, error) {
+ b, ok := fs[filename(p)]
+ if !ok {
+ return nil, os.ErrNotExist
+ }
+ return nopCloser{strings.NewReader(b)}, nil
+}
+
+func fileInfo(name, contents string) os.FileInfo {
+ return mapFI{name: pathpkg.Base(name), size: len(contents)}
+}
+
+func dirInfo(name string) os.FileInfo {
+ return mapFI{name: pathpkg.Base(name), dir: true}
+}
+
+func (fs mapFS) Lstat(p string) (os.FileInfo, error) {
+ b, ok := fs[filename(p)]
+ if ok {
+ return fileInfo(p, b), nil
+ }
+ ents, _ := fs.ReadDir(p)
+ if len(ents) > 0 {
+ return dirInfo(p), nil
+ }
+ return nil, os.ErrNotExist
+}
+
+func (fs mapFS) Stat(p string) (os.FileInfo, error) {
+ return fs.Lstat(p)
+}
+
+// slashdir returns path.Dir(p), but special-cases paths not beginning
+// with a slash to be in the root.
+func slashdir(p string) string {
+ d := pathpkg.Dir(p)
+ if d == "." {
+ return "/"
+ }
+ if strings.HasPrefix(p, "/") {
+ return d
+ }
+ return "/" + d
+}
+
+func (fs mapFS) ReadDir(p string) ([]os.FileInfo, error) {
+ p = pathpkg.Clean(p)
+ var ents []string
+ fim := make(map[string]os.FileInfo) // base -> fi
+ for fn, b := range fs {
+ dir := slashdir(fn)
+ isFile := true
+ var lastBase string
+ for {
+ if dir == p {
+ base := lastBase
+ if isFile {
+ base = pathpkg.Base(fn)
+ }
+ if fim[base] == nil {
+ var fi os.FileInfo
+ if isFile {
+ fi = fileInfo(fn, b)
+ } else {
+ fi = dirInfo(base)
+ }
+ ents = append(ents, base)
+ fim[base] = fi
+ }
+ }
+ if dir == "/" {
+ break
+ } else {
+ isFile = false
+ lastBase = pathpkg.Base(dir)
+ dir = pathpkg.Dir(dir)
+ }
+ }
+ }
+ if len(ents) == 0 {
+ return nil, os.ErrNotExist
+ }
+
+ sort.Strings(ents)
+ var list []os.FileInfo
+ for _, dir := range ents {
+ list = append(list, fim[dir])
+ }
+ return list, nil
+}
+
+// mapFI is the map-based implementation of FileInfo.
+type mapFI struct {
+ name string
+ size int
+ dir bool
+}
+
+func (fi mapFI) IsDir() bool { return fi.dir }
+func (fi mapFI) ModTime() time.Time { return time.Time{} }
+func (fi mapFI) Mode() os.FileMode {
+ if fi.IsDir() {
+ return 0755 | os.ModeDir
+ }
+ return 0444
+}
+func (fi mapFI) Name() string { return pathpkg.Base(fi.name) }
+func (fi mapFI) Size() int64 { return int64(fi.size) }
+func (fi mapFI) Sys() interface{} { return nil }
+
+type nopCloser struct {
+ io.ReadSeeker
+}
+
+func (nc nopCloser) Close() error { return nil }