1 package main 2 3 import ( 4 "archive/zip" 5 "io" 6 "io/fs" 7 "path" 8 "strings" 9 ) 10 11 type zipFS struct { 12 *zip.Reader 13 base string 14 } 15 16 func (z *zipFS) OpenFile(name string) (io.ReadCloser, error) { 17 return z.Open(path.Join(z.base, name)) 18 } 19 20 func (z *zipFS) ReadDir(name string) ([]fs.FileInfo, error) { 21 f, err := z.Open(path.Join(z.base, name)) 22 if err != nil { 23 return nil, err 24 } 25 26 d, ok := f.(fs.ReadDirFile) 27 if !ok { 28 return nil, fs.ErrInvalid 29 } 30 31 entries, err := d.ReadDir(-1) 32 if err != nil { 33 return nil, err 34 } 35 36 fis := make([]fs.FileInfo, len(entries)) 37 38 for n, entry := range entries { 39 fis[n] = entry.(fs.FileInfo) 40 } 41 42 return fis, nil 43 } 44 45 func (z *zipFS) ReadFile(name string) ([]byte, error) { 46 f, err := z.Open(path.Join(z.base, name)) 47 if err != nil { 48 return nil, err 49 } 50 51 s, _ := f.Stat() 52 53 buf := make([]byte, s.Size()) 54 55 if _, err := io.ReadFull(f, buf); err != nil { 56 return nil, err 57 } 58 59 return buf, nil 60 } 61 62 func (z *zipFS) IsDir(dir string) bool { 63 dir = path.Join(z.base, dir) 64 pathWithSlash := dir 65 66 if !strings.HasSuffix(dir, "/") { 67 pathWithSlash += "/" 68 } 69 70 for _, f := range z.File { 71 if f.Name == dir { 72 return false 73 } else if strings.HasPrefix(f.Name, pathWithSlash) { 74 return true 75 } 76 } 77 78 return false 79 } 80