github.com/gogf/gf/v2@v2.7.4/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/v2/encoding/gbase64" 16 "github.com/gogf/gf/v2/encoding/gcompress" 17 "github.com/gogf/gf/v2/errors/gerror" 18 "github.com/gogf/gf/v2/os/gfile" 19 "github.com/gogf/gf/v2/text/gstr" 20 ) 21 22 const ( 23 packedGoSourceTemplate = ` 24 package %s 25 26 import "github.com/gogf/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 }