Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2026-01-12 20:12:19 +08:00
commit 0e3a56826d

View file

@ -17,7 +17,6 @@
package util
import (
"bytes"
"io"
"io/fs"
"mime"
@ -247,23 +246,103 @@ func FilterUploadFileName(name string) string {
}
func TruncateLenFileName(name string) (ret string) {
// 插入资源文件时文件名长度最大限制 189 字节 https://github.com/siyuan-note/siyuan/issues/7099
// 插入资源文件时文件名长度最大限制 189 字节
const maxTotal = 189
ext := filepath.Ext(name)
var byteCount int
truncated := false
buf := bytes.Buffer{}
for _, r := range name {
byteCount += utf8.RuneLen(r)
if 189-len(ext) < byteCount {
truncated = true
base := name[:len(name)-len(ext)]
id := ast.NewNodeID()
// 预留 "-" + id + "-" 的字节数
reservedForID := len(id) + 2
available := maxTotal - len(ext) - reservedForID
if available <= 0 {
// 空间不足以保留 base退回到 "-id-" + ext若仍超限则只返回扩展名
candidate := "-" + id + "-" + ext
if len(candidate) <= maxTotal {
return candidate
}
if len(ext) <= maxTotal {
return ext
}
return ext
}
// 若 base 整体在可用字节内,直接返回原名
if len(base) <= available {
return name
}
runes := []rune(base)
n := len(runes)
if n == 0 {
candidate := "-" + id + "-" + ext
if len(candidate) <= maxTotal {
return candidate
}
if len(ext) <= maxTotal {
return ext
}
return ext
}
// 计算每个 rune 的字节长度
runeBytes := make([]int, n)
for i, r := range runes {
runeBytes[i] = utf8.RuneLen(r)
}
// 从后往前尝试最多保留 3 个 rune找到最大的 tailSize 使得 tailBytes <= available
tailSize := 0
tailBytes := 0
for t := 1; t <= 3 && t <= n; t++ {
b := 0
for i := n - t; i < n; i++ {
b += runeBytes[i]
}
if b <= available {
tailSize = t
tailBytes = b
} else {
break
}
buf.WriteRune(r)
}
if truncated {
buf.WriteString(ext)
if tailSize == 0 {
// 连一个尾部 rune 都放不下,回退到 "-id-" 或扩展名
candidate := "-" + id + "-" + ext
if len(candidate) <= maxTotal {
return candidate
}
if len(ext) <= maxTotal {
return ext
}
return ext
}
ret = buf.String()
// 可用于前缀的字节
availFront := available - tailBytes
// 前缀最多不能覆盖到尾部
maxFrontCount := n - tailSize
var frontRunes []rune
frontBytes := 0
for i := 0; i < maxFrontCount; i++ {
if frontBytes+runeBytes[i] > availFront {
break
}
frontBytes += runeBytes[i]
frontRunes = append(frontRunes, runes[i])
}
// 若前缀与尾部合并能覆盖全部 runes则说明无需截断理论上前面已判断过但再验证一次
if len(frontRunes) == maxFrontCount {
return name
}
tailRunes := runes[n-tailSize:]
ret = string(frontRunes) + string(tailRunes) + "-" + id + "-" + ext
return
}