github.com/gogf/gf@v1.16.9/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/gogf/gf.
     6  
     7  package gres
     8  
     9  import (
    10  	"archive/zip"
    11  	"bytes"
    12  	"encoding/hex"
    13  	"fmt"
    14  
    15  	"github.com/gogf/gf/encoding/gbase64"
    16  	"github.com/gogf/gf/encoding/gcompress"
    17  	"github.com/gogf/gf/text/gstr"
    18  
    19  	"github.com/gogf/gf/os/gfile"
    20  )
    21  
    22  const (
    23  	packedGoSouceTemplate = `
    24  package %s
    25  
    26  import "github.com/gogf/gf/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  // Pack packs the path specified by <srcPaths> into bytes.
    37  // The unnecessary parameter <keyPrefix> indicates the prefix for each file
    38  // packed into the result bytes.
    39  //
    40  // Note that parameter <srcPaths> supports multiple paths join with ','.
    41  func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
    42  	var (
    43  		buffer       = bytes.NewBuffer(nil)
    44  		headerPrefix = ""
    45  	)
    46  	if len(keyPrefix) > 0 && keyPrefix[0] != "" {
    47  		headerPrefix = keyPrefix[0]
    48  	}
    49  	err := zipPathWriter(srcPaths, buffer, headerPrefix)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	// Gzip the data bytes to reduce the size.
    54  	return gcompress.Gzip(buffer.Bytes(), 9)
    55  }
    56  
    57  // PackToFile packs the path specified by <srcPaths> to target file <dstPath>.
    58  // The unnecessary parameter <keyPrefix> indicates the prefix for each file
    59  // packed into the result bytes.
    60  //
    61  // Note that parameter <srcPaths> supports multiple paths join with ','.
    62  func PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {
    63  	data, err := Pack(srcPaths, keyPrefix...)
    64  	if err != nil {
    65  		return err
    66  	}
    67  	return gfile.PutBytes(dstPath, data)
    68  }
    69  
    70  // PackToGoFile packs the path specified by <srcPaths> to target go file <goFilePath>
    71  // with given package name <pkgName>.
    72  //
    73  // The unnecessary parameter <keyPrefix> indicates the prefix for each file
    74  // packed into the result bytes.
    75  //
    76  // Note that parameter <srcPaths> supports multiple paths join with ','.
    77  func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) error {
    78  	data, err := Pack(srcPath, keyPrefix...)
    79  	if err != nil {
    80  		return err
    81  	}
    82  	return gfile.PutContents(
    83  		goFilePath,
    84  		fmt.Sprintf(gstr.TrimLeft(packedGoSouceTemplate), pkgName, gbase64.EncodeToString(data)),
    85  	)
    86  }
    87  
    88  // Unpack unpacks the content specified by <path> to []*File.
    89  func Unpack(path string) ([]*File, error) {
    90  	realPath, err := gfile.Search(path)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	return UnpackContent(gfile.GetContents(realPath))
    95  }
    96  
    97  // UnpackContent unpacks the content to []*File.
    98  func UnpackContent(content string) ([]*File, error) {
    99  	var data []byte
   100  	var err error
   101  	if isHexStr(content) {
   102  		// It here keeps compatible with old version packing string using hex string.
   103  		// TODO remove this support in the future.
   104  		data, err = gcompress.UnGzip(hexStrToBytes(content))
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  	} else if isBase64(content) {
   109  		// New version packing string using base64.
   110  		b, err := gbase64.DecodeString(content)
   111  		if err != nil {
   112  			return nil, err
   113  		}
   114  		data, err = gcompress.UnGzip(b)
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  	} else {
   119  		data, err = gcompress.UnGzip([]byte(content))
   120  		if err != nil {
   121  			return nil, err
   122  		}
   123  	}
   124  	reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	array := make([]*File, len(reader.File))
   129  	for i, file := range reader.File {
   130  		array[i] = &File{file: file}
   131  	}
   132  	return array, nil
   133  }
   134  
   135  // isBase64 checks and returns whether given content <s> is base64 string.
   136  // It returns true if <s> is base64 string, or false if not.
   137  func isBase64(s string) bool {
   138  	var r bool
   139  	for i := 0; i < len(s); i++ {
   140  		r = (s[i] >= '0' && s[i] <= '9') ||
   141  			(s[i] >= 'a' && s[i] <= 'z') ||
   142  			(s[i] >= 'A' && s[i] <= 'Z') ||
   143  			(s[i] == '+' || s[i] == '-') ||
   144  			(s[i] == '_' || s[i] == '/') || s[i] == '='
   145  		if !r {
   146  			return false
   147  		}
   148  	}
   149  	return true
   150  }
   151  
   152  // isHexStr checks and returns whether given content <s> is hex string.
   153  // It returns true if <s> is hex string, or false if not.
   154  func isHexStr(s string) bool {
   155  	var r bool
   156  	for i := 0; i < len(s); i++ {
   157  		r = (s[i] >= '0' && s[i] <= '9') ||
   158  			(s[i] >= 'a' && s[i] <= 'f') ||
   159  			(s[i] >= 'A' && s[i] <= 'F')
   160  		if !r {
   161  			return false
   162  		}
   163  	}
   164  	return true
   165  }
   166  
   167  // hexStrToBytes converts hex string content to []byte.
   168  func hexStrToBytes(s string) []byte {
   169  	src := []byte(s)
   170  	dst := make([]byte, hex.DecodedLen(len(src)))
   171  	hex.Decode(dst, src)
   172  	return dst
   173  }