github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/lib/encoder/filename/decode.go (about) 1 package filename 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "encoding/binary" 7 "errors" 8 "sync" 9 10 "github.com/dop251/scsu" 11 "github.com/klauspost/compress/huff0" 12 ) 13 14 // ErrCorrupted is returned if a provided encoded filename cannot be decoded. 15 var ErrCorrupted = errors.New("file name corrupt") 16 17 // ErrUnsupported is returned if a provided encoding may come from a future version or the file name is corrupt. 18 var ErrUnsupported = errors.New("file name possibly generated by future version of rclone") 19 20 // Custom decoder for tableCustom types. Stateful, so must have lock. 21 var customDec huff0.Scratch 22 var customDecMu sync.Mutex 23 24 // Decode an encoded string. 25 func Decode(s string) (string, error) { 26 initCoders() 27 if len(s) < 1 { 28 return "", ErrCorrupted 29 } 30 table := decodeMap[s[0]] 31 if table == 0 { 32 return "", ErrCorrupted 33 } 34 table-- 35 s = s[1:] 36 data := make([]byte, base64.URLEncoding.DecodedLen(len(s))) 37 n, err := base64.URLEncoding.Decode(data, ([]byte)(s)) 38 if err != nil || n < 0 { 39 return "", ErrCorrupted 40 } 41 data = data[:n] 42 return DecodeBytes(table, data) 43 } 44 45 // DecodeBytes will decode raw id and data values. 46 func DecodeBytes(table byte, data []byte) (string, error) { 47 initCoders() 48 switch table { 49 case tableUncompressed: 50 return string(data), nil 51 case tableReserved: 52 return "", ErrUnsupported 53 case tableSCSUPlain: 54 return scsu.Decode(data) 55 case tableRLE: 56 if len(data) < 2 { 57 return "", ErrCorrupted 58 } 59 n, used := binary.Uvarint(data[:len(data)-1]) 60 if used <= 0 || n > maxLength { 61 return "", ErrCorrupted 62 } 63 return string(bytes.Repeat(data[len(data)-1:], int(n))), nil 64 case tableCustom: 65 customDecMu.Lock() 66 defer customDecMu.Unlock() 67 _, data, err := huff0.ReadTable(data, &customDec) 68 if err != nil { 69 return "", ErrCorrupted 70 } 71 customDec.MaxDecodedSize = maxLength 72 decoded, err := customDec.Decompress1X(data) 73 if err != nil { 74 return "", ErrCorrupted 75 } 76 return string(decoded), nil 77 default: 78 if table >= byte(len(decTables)) { 79 return "", ErrCorrupted 80 } 81 dec := decTables[table] 82 if dec == nil { 83 return "", ErrUnsupported 84 } 85 var dst [maxLength]byte 86 name, err := dec.Decompress1X(dst[:0], data) 87 if err != nil { 88 return "", ErrCorrupted 89 } 90 if table == tableSCSU { 91 return scsu.Decode(name) 92 } 93 return string(name), nil 94 } 95 }