2021-01-16 20:20:30 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2019-08-13 13:45:01 +08:00
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
|
|
|
|
package gres
|
|
|
|
|
|
|
|
import (
|
|
|
|
"archive/zip"
|
|
|
|
"bytes"
|
2020-05-03 22:08:08 +08:00
|
|
|
"encoding/hex"
|
2019-08-13 13:45:01 +08:00
|
|
|
"fmt"
|
2021-11-15 20:49:02 +08:00
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/encoding/gbase64"
|
|
|
|
"github.com/gogf/gf/v2/encoding/gcompress"
|
2021-12-23 00:09:00 +08:00
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/os/gfile"
|
|
|
|
"github.com/gogf/gf/v2/text/gstr"
|
2019-08-13 13:45:01 +08:00
|
|
|
)
|
|
|
|
|
2019-08-30 20:29:12 +08:00
|
|
|
const (
|
2021-12-23 00:09:00 +08:00
|
|
|
packedGoSourceTemplate = `
|
2020-05-01 02:16:42 +08:00
|
|
|
package %s
|
2019-08-30 20:29:12 +08:00
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
import "github.com/gogf/gf/v2/os/gres"
|
2019-08-30 20:29:12 +08:00
|
|
|
|
|
|
|
func init() {
|
2020-01-15 00:15:56 +08:00
|
|
|
if err := gres.Add("%s"); err != nil {
|
2020-05-01 02:16:42 +08:00
|
|
|
panic("add binary content to resource manager failed: " + err.Error())
|
2019-08-30 20:29:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
`
|
|
|
|
)
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// Pack packs the path specified by `srcPaths` into bytes.
|
|
|
|
// The unnecessary parameter `keyPrefix` indicates the prefix for each file
|
2019-08-13 21:06:11 +08:00
|
|
|
// packed into the result bytes.
|
2019-09-03 23:18:54 +08:00
|
|
|
//
|
2021-10-21 18:22:47 +08:00
|
|
|
// Note that parameter `srcPaths` supports multiple paths join with ','.
|
2019-09-03 23:18:54 +08:00
|
|
|
func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
|
2021-01-16 20:20:30 +08:00
|
|
|
var (
|
|
|
|
buffer = bytes.NewBuffer(nil)
|
|
|
|
headerPrefix = ""
|
|
|
|
)
|
2019-09-03 23:18:54 +08:00
|
|
|
if len(keyPrefix) > 0 && keyPrefix[0] != "" {
|
|
|
|
headerPrefix = keyPrefix[0]
|
|
|
|
}
|
2020-05-01 00:18:45 +08:00
|
|
|
err := zipPathWriter(srcPaths, buffer, headerPrefix)
|
2019-08-13 13:45:01 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-15 00:15:56 +08:00
|
|
|
// Gzip the data bytes to reduce the size.
|
|
|
|
return gcompress.Gzip(buffer.Bytes(), 9)
|
2019-08-13 13:45:01 +08:00
|
|
|
}
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// PackToFile packs the path specified by `srcPaths` to target file `dstPath`.
|
|
|
|
// The unnecessary parameter `keyPrefix` indicates the prefix for each file
|
2019-08-13 21:06:11 +08:00
|
|
|
// packed into the result bytes.
|
2019-09-03 23:18:54 +08:00
|
|
|
//
|
2021-10-21 18:22:47 +08:00
|
|
|
// Note that parameter `srcPaths` supports multiple paths join with ','.
|
2019-09-03 23:18:54 +08:00
|
|
|
func PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {
|
|
|
|
data, err := Pack(srcPaths, keyPrefix...)
|
2019-08-13 13:45:01 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return gfile.PutBytes(dstPath, data)
|
|
|
|
}
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// PackToGoFile packs the path specified by `srcPaths` to target go file `goFilePath`
|
|
|
|
// with given package name `pkgName`.
|
2019-08-13 21:06:11 +08:00
|
|
|
//
|
2021-10-21 18:22:47 +08:00
|
|
|
// The unnecessary parameter `keyPrefix` indicates the prefix for each file
|
2019-08-13 21:06:11 +08:00
|
|
|
// packed into the result bytes.
|
2019-09-03 23:18:54 +08:00
|
|
|
//
|
2021-10-21 18:22:47 +08:00
|
|
|
// Note that parameter `srcPaths` supports multiple paths join with ','.
|
2019-08-13 13:45:01 +08:00
|
|
|
func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) error {
|
|
|
|
data, err := Pack(srcPath, keyPrefix...)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return gfile.PutContents(
|
2020-01-15 00:15:56 +08:00
|
|
|
goFilePath,
|
2021-12-23 00:09:00 +08:00
|
|
|
fmt.Sprintf(gstr.TrimLeft(packedGoSourceTemplate), pkgName, gbase64.EncodeToString(data)),
|
2019-08-13 13:45:01 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// Unpack unpacks the content specified by `path` to []*File.
|
2019-08-13 13:45:01 +08:00
|
|
|
func Unpack(path string) ([]*File, error) {
|
|
|
|
realPath, err := gfile.Search(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-15 00:15:56 +08:00
|
|
|
return UnpackContent(gfile.GetContents(realPath))
|
2019-08-13 13:45:01 +08:00
|
|
|
}
|
|
|
|
|
2019-08-13 21:06:11 +08:00
|
|
|
// UnpackContent unpacks the content to []*File.
|
2020-01-15 00:15:56 +08:00
|
|
|
func UnpackContent(content string) ([]*File, error) {
|
2021-12-23 00:09:00 +08:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
data []byte
|
|
|
|
)
|
2020-05-03 22:08:08 +08:00
|
|
|
if isHexStr(content) {
|
2020-05-03 22:16:12 +08:00
|
|
|
// It here keeps compatible with old version packing string using hex string.
|
2020-05-03 22:08:08 +08:00
|
|
|
// TODO remove this support in the future.
|
|
|
|
data, err = gcompress.UnGzip(hexStrToBytes(content))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else if isBase64(content) {
|
|
|
|
// New version packing string using base64.
|
2020-05-01 02:16:42 +08:00
|
|
|
b, err := gbase64.DecodeString(content)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
data, err = gcompress.UnGzip(b)
|
2020-02-04 17:09:18 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
2021-09-14 19:30:20 +08:00
|
|
|
data, err = gcompress.UnGzip([]byte(content))
|
2020-02-04 17:09:18 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-15 00:15:56 +08:00
|
|
|
}
|
|
|
|
reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
|
2019-08-13 13:45:01 +08:00
|
|
|
if err != nil {
|
2021-12-23 00:09:00 +08:00
|
|
|
err = gerror.Wrapf(err, `create zip reader failed`)
|
2019-08-13 13:45:01 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
array := make([]*File, len(reader.File))
|
|
|
|
for i, file := range reader.File {
|
2019-08-14 22:03:52 +08:00
|
|
|
array[i] = &File{file: file}
|
2019-08-13 13:45:01 +08:00
|
|
|
}
|
|
|
|
return array, nil
|
|
|
|
}
|
2020-01-15 00:15:56 +08:00
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// isBase64 checks and returns whether given content `s` is base64 string.
|
|
|
|
// It returns true if `s` is base64 string, or false if not.
|
2020-05-01 02:16:42 +08:00
|
|
|
func isBase64(s string) bool {
|
2020-02-04 17:09:18 +08:00
|
|
|
var r bool
|
|
|
|
for i := 0; i < len(s); i++ {
|
|
|
|
r = (s[i] >= '0' && s[i] <= '9') ||
|
2020-05-01 02:16:42 +08:00
|
|
|
(s[i] >= 'a' && s[i] <= 'z') ||
|
|
|
|
(s[i] >= 'A' && s[i] <= 'Z') ||
|
|
|
|
(s[i] == '+' || s[i] == '-') ||
|
|
|
|
(s[i] == '_' || s[i] == '/') || s[i] == '='
|
2020-02-04 17:09:18 +08:00
|
|
|
if !r {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2020-05-03 22:08:08 +08:00
|
|
|
|
2021-10-21 18:22:47 +08:00
|
|
|
// isHexStr checks and returns whether given content `s` is hex string.
|
|
|
|
// It returns true if `s` is hex string, or false if not.
|
2020-05-03 22:08:08 +08:00
|
|
|
func isHexStr(s string) bool {
|
|
|
|
var r bool
|
|
|
|
for i := 0; i < len(s); i++ {
|
|
|
|
r = (s[i] >= '0' && s[i] <= '9') ||
|
|
|
|
(s[i] >= 'a' && s[i] <= 'f') ||
|
|
|
|
(s[i] >= 'A' && s[i] <= 'F')
|
|
|
|
if !r {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// hexStrToBytes converts hex string content to []byte.
|
|
|
|
func hexStrToBytes(s string) []byte {
|
2021-09-14 19:30:20 +08:00
|
|
|
src := []byte(s)
|
2020-05-03 22:08:08 +08:00
|
|
|
dst := make([]byte, hex.DecodedLen(len(src)))
|
2021-12-23 00:09:00 +08:00
|
|
|
_, _ = hex.Decode(dst, src)
|
2020-05-03 22:08:08 +08:00
|
|
|
return dst
|
|
|
|
}
|