github.com/wangyougui/gf/v2@v2.6.5/os/gres/gres_func.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/wangyougui/gf.
     6  
     7  package gres
     8  
     9  import (
    10  	"archive/zip"
    11  	"bytes"
    12  	"encoding/hex"
    13  	"fmt"
    14  
    15  	"github.com/wangyougui/gf/v2/encoding/gbase64"
    16  	"github.com/wangyougui/gf/v2/encoding/gcompress"
    17  	"github.com/wangyougui/gf/v2/errors/gerror"
    18  	"github.com/wangyougui/gf/v2/os/gfile"
    19  	"github.com/wangyougui/gf/v2/text/gstr"
    20  )
    21  
    22  const (
    23  	packedGoSourceTemplate = `
    24  package %s
    25  
    26  import "github.com/wangyougui/gf/v2/os/gres"
    27  
    28  func init() {
    29  	if err := gres.Add("%s"); err != nil {
    30  		panic("add binary content to resource manager failed: " + err.Error())
    31  	}
    32  }
    33  `
    34  )
    35  
    36  // Option contains the extra options for Pack functions.
    37  type Option struct {
    38  	Prefix   string // The file path prefix for each file item in resource manager.
    39  	KeepPath bool   // Keep the passed path when packing, usually for relative path.
    40  }
    41  
    42  // Pack packs the path specified by `srcPaths` into bytes.
    43  // The unnecessary parameter `keyPrefix` indicates the prefix for each file
    44  // packed into the result bytes.
    45  //
    46  // Note that parameter `srcPaths` supports multiple paths join with ','.
    47  //
    48  // Deprecated: use PackWithOption instead.
    49  func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
    50  	option := Option{}
    51  	if len(keyPrefix) > 0 && keyPrefix[0] != "" {
    52  		option.Prefix = keyPrefix[0]
    53  	}
    54  	return PackWithOption(srcPaths, option)
    55  }
    56  
    57  // PackWithOption packs the path specified by `srcPaths` into bytes.
    58  //
    59  // Note that parameter `srcPaths` supports multiple paths join with ','.
    60  func PackWithOption(srcPaths string, option Option) ([]byte, error) {
    61  	var buffer = bytes.NewBuffer(nil)
    62  	err := zipPathWriter(srcPaths, buffer, option)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	// Gzip the data bytes to reduce the size.
    67  	return gcompress.Gzip(buffer.Bytes(), 9)
    68  }
    69  
    70  // PackToFile packs the path specified by `srcPaths` to target file `dstPath`.
    71  // The unnecessary parameter `keyPrefix` indicates the prefix for each file
    72  // packed into the result bytes.
    73  //
    74  // Note that parameter `srcPaths` supports multiple paths join with ','.
    75  //
    76  // Deprecated: use PackToFileWithOption instead.
    77  func PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {
    78  	data, err := Pack(srcPaths, keyPrefix...)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	return gfile.PutBytes(dstPath, data)
    83  }
    84  
    85  // PackToFileWithOption packs the path specified by `srcPaths` to target file `dstPath`.
    86  //
    87  // Note that parameter `srcPaths` supports multiple paths join with ','.
    88  func PackToFileWithOption(srcPaths, dstPath string, option Option) error {
    89  	data, err := PackWithOption(srcPaths, option)
    90  	if err != nil {
    91  		return err
    92  	}
    93  	return gfile.PutBytes(dstPath, data)
    94  }
    95  
    96  // PackToGoFile packs the path specified by `srcPaths` to target go file `goFilePath`
    97  // with given package name `pkgName`.
    98  //
    99  // The unnecessary parameter `keyPrefix` indicates the prefix for each file
   100  // packed into the result bytes.
   101  //
   102  // Note that parameter `srcPaths` supports multiple paths join with ','.
   103  //
   104  // Deprecated: use PackToGoFileWithOption instead.
   105  func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) error {
   106  	data, err := Pack(srcPath, keyPrefix...)
   107  	if err != nil {
   108  		return err
   109  	}
   110  	return gfile.PutContents(
   111  		goFilePath,
   112  		fmt.Sprintf(gstr.TrimLeft(packedGoSourceTemplate), pkgName, gbase64.EncodeToString(data)),
   113  	)
   114  }
   115  
   116  // PackToGoFileWithOption packs the path specified by `srcPaths` to target go file `goFilePath`
   117  // with given package name `pkgName`.
   118  //
   119  // Note that parameter `srcPaths` supports multiple paths join with ','.
   120  func PackToGoFileWithOption(srcPath, goFilePath, pkgName string, option Option) error {
   121  	data, err := PackWithOption(srcPath, option)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	return gfile.PutContents(
   126  		goFilePath,
   127  		fmt.Sprintf(gstr.TrimLeft(packedGoSourceTemplate), pkgName, gbase64.EncodeToString(data)),
   128  	)
   129  }
   130  
   131  // Unpack unpacks the content specified by `path` to []*File.
   132  func Unpack(path string) ([]*File, error) {
   133  	realPath, err := gfile.Search(path)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	return UnpackContent(gfile.GetContents(realPath))
   138  }
   139  
   140  // UnpackContent unpacks the content to []*File.
   141  func UnpackContent(content string) ([]*File, error) {
   142  	var (
   143  		err  error
   144  		data []byte
   145  	)
   146  	if isHexStr(content) {
   147  		// It here keeps compatible with old version packing string using hex string.
   148  		// TODO remove this support in the future.
   149  		data, err = gcompress.UnGzip(hexStrToBytes(content))
   150  		if err != nil {
   151  			return nil, err
   152  		}
   153  	} else if isBase64(content) {
   154  		// New version packing string using base64.
   155  		b, err := gbase64.DecodeString(content)
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  		data, err = gcompress.UnGzip(b)
   160  		if err != nil {
   161  			return nil, err
   162  		}
   163  	} else {
   164  		data, err = gcompress.UnGzip([]byte(content))
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  	}
   169  	reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
   170  	if err != nil {
   171  		err = gerror.Wrapf(err, `create zip reader failed`)
   172  		return nil, err
   173  	}
   174  	array := make([]*File, len(reader.File))
   175  	for i, file := range reader.File {
   176  		array[i] = &File{file: file}
   177  	}
   178  	return array, nil
   179  }
   180  
   181  // isBase64 checks and returns whether given content `s` is base64 string.
   182  // It returns true if `s` is base64 string, or false if not.
   183  func isBase64(s string) bool {
   184  	var r bool
   185  	for i := 0; i < len(s); i++ {
   186  		r = (s[i] >= '0' && s[i] <= '9') ||
   187  			(s[i] >= 'a' && s[i] <= 'z') ||
   188  			(s[i] >= 'A' && s[i] <= 'Z') ||
   189  			(s[i] == '+' || s[i] == '-') ||
   190  			(s[i] == '_' || s[i] == '/') || s[i] == '='
   191  		if !r {
   192  			return false
   193  		}
   194  	}
   195  	return true
   196  }
   197  
   198  // isHexStr checks and returns whether given content `s` is hex string.
   199  // It returns true if `s` is hex string, or false if not.
   200  func isHexStr(s string) bool {
   201  	var r bool
   202  	for i := 0; i < len(s); i++ {
   203  		r = (s[i] >= '0' && s[i] <= '9') ||
   204  			(s[i] >= 'a' && s[i] <= 'f') ||
   205  			(s[i] >= 'A' && s[i] <= 'F')
   206  		if !r {
   207  			return false
   208  		}
   209  	}
   210  	return true
   211  }
   212  
   213  // hexStrToBytes converts hex string content to []byte.
   214  func hexStrToBytes(s string) []byte {
   215  	src := []byte(s)
   216  	dst := make([]byte, hex.DecodedLen(len(src)))
   217  	_, _ = hex.Decode(dst, src)
   218  	return dst
   219  }