mirror of https://github.com/Xhofe/alist
157 lines
3.6 KiB
Go
157 lines
3.6 KiB
Go
package zip
|
|
|
|
import (
|
|
"bytes"
|
|
"github.com/alist-org/alist/v3/internal/errs"
|
|
"github.com/alist-org/alist/v3/internal/model"
|
|
"github.com/alist-org/alist/v3/internal/stream"
|
|
"github.com/saintfish/chardet"
|
|
"github.com/yeka/zip"
|
|
"golang.org/x/text/encoding"
|
|
"golang.org/x/text/encoding/charmap"
|
|
"golang.org/x/text/encoding/japanese"
|
|
"golang.org/x/text/encoding/korean"
|
|
"golang.org/x/text/encoding/simplifiedchinese"
|
|
"golang.org/x/text/encoding/traditionalchinese"
|
|
"golang.org/x/text/encoding/unicode"
|
|
"golang.org/x/text/encoding/unicode/utf32"
|
|
"golang.org/x/text/transform"
|
|
"io"
|
|
"os"
|
|
stdpath "path"
|
|
"strings"
|
|
)
|
|
|
|
func toModelObj(file os.FileInfo) *model.Object {
|
|
return &model.Object{
|
|
Name: decodeName(file.Name()),
|
|
Size: file.Size(),
|
|
Modified: file.ModTime(),
|
|
IsFolder: file.IsDir(),
|
|
}
|
|
}
|
|
|
|
func decompress(file *zip.File, filePath, outputPath, password string) error {
|
|
targetPath := outputPath
|
|
dir, base := stdpath.Split(filePath)
|
|
if dir != "" {
|
|
targetPath = stdpath.Join(targetPath, dir)
|
|
err := os.MkdirAll(targetPath, 0700)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if base != "" {
|
|
err := _decompress(file, targetPath, password, func(_ float64) {})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func _decompress(file *zip.File, targetPath, password string, up model.UpdateProgress) error {
|
|
if file.IsEncrypted() {
|
|
file.SetPassword(password)
|
|
}
|
|
rc, err := file.Open()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer rc.Close()
|
|
f, err := os.OpenFile(stdpath.Join(targetPath, file.FileInfo().Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
_, err = io.Copy(f, &stream.ReaderUpdatingProgress{
|
|
Reader: &stream.SimpleReaderWithSize{
|
|
Reader: rc,
|
|
Size: file.FileInfo().Size(),
|
|
},
|
|
UpdateProgress: up,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func filterPassword(err error) error {
|
|
if err != nil && strings.Contains(err.Error(), "password") {
|
|
return errs.WrongArchivePassword
|
|
}
|
|
return err
|
|
}
|
|
|
|
func decodeName(name string) string {
|
|
b := []byte(name)
|
|
detector := chardet.NewTextDetector()
|
|
result, err := detector.DetectBest(b)
|
|
if err != nil {
|
|
return name
|
|
}
|
|
enc := getEncoding(result.Charset)
|
|
if enc == nil {
|
|
return name
|
|
}
|
|
i := bytes.NewReader(b)
|
|
decoder := transform.NewReader(i, enc.NewDecoder())
|
|
content, _ := io.ReadAll(decoder)
|
|
return string(content)
|
|
}
|
|
|
|
func getEncoding(name string) (enc encoding.Encoding) {
|
|
switch name {
|
|
case "UTF-16BE":
|
|
enc = unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
|
|
case "UTF-16LE":
|
|
enc = unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
|
|
case "UTF-32BE":
|
|
enc = utf32.UTF32(utf32.BigEndian, utf32.IgnoreBOM)
|
|
case "UTF-32LE":
|
|
enc = utf32.UTF32(utf32.LittleEndian, utf32.IgnoreBOM)
|
|
case "ISO-8859-1":
|
|
enc = charmap.ISO8859_1
|
|
case "ISO-8859-2":
|
|
enc = charmap.ISO8859_2
|
|
case "ISO-8859-3":
|
|
enc = charmap.ISO8859_3
|
|
case "ISO-8859-4":
|
|
enc = charmap.ISO8859_4
|
|
case "ISO-8859-5":
|
|
enc = charmap.ISO8859_5
|
|
case "ISO-8859-6":
|
|
enc = charmap.ISO8859_6
|
|
case "ISO-8859-7":
|
|
enc = charmap.ISO8859_7
|
|
case "ISO-8859-8":
|
|
enc = charmap.ISO8859_8
|
|
case "ISO-8859-8-I":
|
|
enc = charmap.ISO8859_8I
|
|
case "ISO-8859-9":
|
|
enc = charmap.ISO8859_9
|
|
case "windows-1251":
|
|
enc = charmap.Windows1251
|
|
case "windows-1256":
|
|
enc = charmap.Windows1256
|
|
case "KOI8-R":
|
|
enc = charmap.KOI8R
|
|
case "Shift_JIS":
|
|
enc = japanese.ShiftJIS
|
|
case "GB-18030":
|
|
enc = simplifiedchinese.GB18030
|
|
case "EUC-JP":
|
|
enc = japanese.EUCJP
|
|
case "EUC-KR":
|
|
enc = korean.EUCKR
|
|
case "Big5":
|
|
enc = traditionalchinese.Big5
|
|
case "ISO-2022-JP":
|
|
enc = japanese.ISO2022JP
|
|
default:
|
|
enc = nil
|
|
}
|
|
return
|
|
}
|