mirror of
https://github.com/rclone/rclone.git
synced 2025-08-15 00:02:35 +02:00
encoder/filename: Add SCSU as tables
Instead of only adding SCSU, add it as an existing table. Allow direct SCSU and add a, perhaps, reasonable table as well. Add byte interfaces that doesn't base64 encode the URL as well with `EncodeBytes` and `DecodeBytes`. Fuzz tested and decode tests added.
This commit is contained in:
committed by
Nick Craig-Wood
parent
47b69d6300
commit
424aaac2e1
@ -4,6 +4,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/dop251/scsu"
|
||||
"github.com/klauspost/compress/huff0"
|
||||
)
|
||||
|
||||
@ -11,21 +12,45 @@ import (
|
||||
// Calling Decode with the returned string should always succeed.
|
||||
// It is not a requirement that the input string is valid utf-8.
|
||||
func Encode(s string) string {
|
||||
table, payload := EncodeBytes(s)
|
||||
return string(encodeURL[table]) + base64.URLEncoding.EncodeToString(payload)
|
||||
}
|
||||
|
||||
// EncodeBytes will compress the given string and return a table identifier and a payload.
|
||||
func EncodeBytes(s string) (table byte, payload []byte) {
|
||||
initCoders()
|
||||
bestSize := len(s)
|
||||
bestTable := tableUncompressed
|
||||
bestTable := byte(tableUncompressed)
|
||||
org := []byte(s)
|
||||
bestOut := []byte(s)
|
||||
|
||||
// Try all tables and choose the best
|
||||
for i, enc := range encTables[:] {
|
||||
org := org
|
||||
if len(org) <= 1 || len(org) > maxLength {
|
||||
// Use the uncompressed
|
||||
break
|
||||
}
|
||||
|
||||
if enc == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if i == tableSCSU {
|
||||
var err error
|
||||
olen := len(org)
|
||||
org, err = scsu.EncodeStrict(s, make([]byte, 0, len(org)))
|
||||
if err != nil || olen <= len(org) {
|
||||
continue
|
||||
}
|
||||
if len(org) < bestSize {
|
||||
// This is already better, store so we can use if the table cannot.
|
||||
bestOut = bestOut[:len(org)]
|
||||
bestTable = tableSCSUPlain
|
||||
bestSize = len(org)
|
||||
copy(bestOut, org)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to encode using table.
|
||||
err := func() error {
|
||||
encTableLocks[i].Lock()
|
||||
@ -36,14 +61,14 @@ func Encode(s string) string {
|
||||
}
|
||||
if len(out) < bestSize {
|
||||
bestOut = bestOut[:len(out)]
|
||||
bestTable = i
|
||||
bestTable = byte(i)
|
||||
bestSize = len(out)
|
||||
copy(bestOut, out)
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
// If input is a single byte repeated store as RLE or save uncompressed.
|
||||
if err == huff0.ErrUseRLE {
|
||||
if err == huff0.ErrUseRLE && i != tableSCSU {
|
||||
if len(org) > 2 {
|
||||
// Encode as one byte repeated since it will be smaller than uncompressed.
|
||||
n := binary.PutUvarint(bestOut, uint64(len(org)))
|
||||
@ -56,5 +81,5 @@ func Encode(s string) string {
|
||||
}
|
||||
}
|
||||
|
||||
return string(encodeURL[bestTable]) + base64.URLEncoding.EncodeToString(bestOut)
|
||||
return bestTable, bestOut
|
||||
}
|
||||
|
Reference in New Issue
Block a user