mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-01-23 18:46:11 +00:00
134 lines
2.7 KiB
Go
134 lines
2.7 KiB
Go
package zip
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/giongto35/cloud-game/v3/pkg/logger"
|
|
)
|
|
|
|
const Ext = ".zip"
|
|
|
|
var (
|
|
ErrorNotFound = errors.New("not found")
|
|
ErrorInvalidName = errors.New("invalid name")
|
|
)
|
|
|
|
type Extractor struct {
|
|
log *logger.Logger
|
|
}
|
|
|
|
func New(log *logger.Logger) Extractor {
|
|
return Extractor{
|
|
log: log,
|
|
}
|
|
}
|
|
|
|
// Compress compresses the bytes (a single file) with a name specified into a ZIP file (as bytes).
|
|
func Compress(data []byte, name string) ([]byte, error) {
|
|
buf := new(bytes.Buffer)
|
|
w := zip.NewWriter(buf)
|
|
|
|
//w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
|
|
// return flate.NewWriter(out, flate.BestCompression)
|
|
//})
|
|
|
|
z, err := w.Create(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_, err = z.Write(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = w.Close()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
// Read reads a single ZIP file from the bytes array.
|
|
// It will return un-compressed data and the name of that file.
|
|
func Read(zd []byte) ([]byte, string, error) {
|
|
r, err := zip.NewReader(bytes.NewReader(zd), int64(len(zd)))
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
for _, f := range r.File {
|
|
if f.FileInfo().IsDir() {
|
|
continue
|
|
}
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
b, err := io.ReadAll(rc)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
if err := rc.Close(); err != nil {
|
|
return nil, "", err
|
|
}
|
|
return b, f.FileInfo().Name(), nil
|
|
}
|
|
return nil, "", ErrorNotFound
|
|
}
|
|
|
|
func (e Extractor) Extract(src string, dest string) (files []string, err error) {
|
|
r, err := zip.OpenReader(src)
|
|
if err != nil {
|
|
return files, err
|
|
}
|
|
defer r.Close()
|
|
|
|
for _, f := range r.File {
|
|
path := filepath.Join(dest, f.Name)
|
|
|
|
// negate ZipSlip vulnerability (http://bit.ly/2MsjAWE)
|
|
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
|
|
e.log.Warn().Msgf("%s is illegal path", path)
|
|
continue
|
|
}
|
|
// remake directory
|
|
if f.FileInfo().IsDir() {
|
|
if err := os.MkdirAll(path, os.ModePerm); err != nil {
|
|
e.log.Error().Err(err)
|
|
}
|
|
continue
|
|
}
|
|
// make file
|
|
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
|
e.log.Error().Err(err)
|
|
continue
|
|
}
|
|
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
|
if err != nil {
|
|
e.log.Error().Err(err)
|
|
continue
|
|
}
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
e.log.Error().Err(err)
|
|
continue
|
|
}
|
|
|
|
if _, err = io.Copy(out, rc); err != nil {
|
|
e.log.Error().Err(err)
|
|
_ = out.Close()
|
|
_ = rc.Close()
|
|
continue
|
|
}
|
|
|
|
_ = out.Close()
|
|
_ = rc.Close()
|
|
|
|
files = append(files, path)
|
|
}
|
|
return files, nil
|
|
}
|