mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 16:44:23 +08:00
1 parent
71e67be9c1
commit
1914b5329a
25 files changed
+747
-253
No files matched your search
+63
-11
@@ -26,18 +26,19 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// editorResourceRefs 保存全包资源标识和直接文件引用,不以页面是否加载判断资源存活。
|
||||
// editorResourceRefs 保存全包资源标识和直接文件引用,不以页面是否加载判断资源存活
|
||||
type editorResourceRefs struct {
|
||||
ids map[string]bool
|
||||
files map[string]bool
|
||||
fonts map[string]*editorFontUsage
|
||||
}
|
||||
|
||||
// pruneSourceResources 在保存副本中清理无引用字体和图片,保留其他资源及原始编辑状态。
|
||||
// 按GB/T 33190-2016附录A检查标识和路径引用,包括模板、注释、底纹、裁剪、版本和其他文档。
|
||||
// 全包检查保留孤立XML中的引用;未知命名空间、扩展数据或无法解析的XML使本次清理跳过。
|
||||
// compactSourceResources 在保存副本中清理无引用字体和图片,并裁剪可完整确认用字的原有字体
|
||||
// 按GB/T 33190-2016附录A检查标识和路径引用,包括模板、注释、底纹、裁剪、版本和其他文档
|
||||
// 全包检查保留孤立XML中的引用;未知命名空间、扩展数据或无法解析的XML使本次清理跳过
|
||||
// 入参: parts 已修改和新增的包内条目
|
||||
// 返回: map[string]bool 可移除的二进制条目, error 读取错误
|
||||
func (e *Editor) pruneSourceResources(parts map[string][]byte) (map[string]bool, error) {
|
||||
func (e *Editor) compactSourceResources(parts map[string][]byte) (map[string]bool, error) {
|
||||
if len(parts) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -52,7 +53,7 @@ func (e *Editor) pruneSourceResources(parts map[string][]byte) (map[string]bool,
|
||||
for name := range parts {
|
||||
names[name] = true
|
||||
}
|
||||
refs := editorResourceRefs{ids: make(map[string]bool), files: make(map[string]bool)}
|
||||
refs := editorResourceRefs{ids: make(map[string]bool), files: make(map[string]bool), fonts: make(map[string]*editorFontUsage)}
|
||||
var resources []string
|
||||
for _, name := range slices.Sorted(maps.Keys(names)) {
|
||||
if strings.HasSuffix(name, "/") {
|
||||
@@ -80,6 +81,7 @@ func (e *Editor) pruneSourceResources(parts map[string][]byte) (map[string]bool,
|
||||
removed := make(map[string]bool)
|
||||
usedFiles := maps.Clone(refs.files)
|
||||
updates := make(map[string][]byte)
|
||||
fontFiles := make(map[string]*editorFontUsage)
|
||||
for _, name := range resources {
|
||||
data, ok := parts[name]
|
||||
if !ok {
|
||||
@@ -114,9 +116,21 @@ func (e *Editor) pruneSourceResources(parts map[string][]byte) (map[string]bool,
|
||||
return nil, nil
|
||||
}
|
||||
if location := editorResourceLocation(name, root.attr("BaseLoc"), value); location != "" {
|
||||
alternate := strings.ToLower(cleanPackagePath(resolveResourcePath(name, root.attr("BaseLoc"), value)))
|
||||
if field == "FontFile" {
|
||||
usage := refs.fonts[id]
|
||||
charset := node.attr("Charset")
|
||||
unsafe := id == "" || charset != "" && !strings.EqualFold(charset, "unicode") || location != alternate
|
||||
for _, file := range []string{location, alternate} {
|
||||
if fontFiles[file] == nil {
|
||||
fontFiles[file] = newEditorFontUsage()
|
||||
}
|
||||
fontFiles[file].merge(usage, unsafe || keep && usage == nil)
|
||||
}
|
||||
}
|
||||
if keep {
|
||||
usedFiles[location] = true
|
||||
usedFiles[strings.ToLower(cleanPackagePath(resolveResourcePath(name, root.attr("BaseLoc"), value)))] = true
|
||||
usedFiles[alternate] = true
|
||||
} else {
|
||||
removed[location] = true
|
||||
}
|
||||
@@ -139,6 +153,20 @@ func (e *Editor) pruneSourceResources(parts map[string][]byte) (map[string]bool,
|
||||
for name := range usedFiles {
|
||||
delete(removed, name)
|
||||
}
|
||||
for name := range names {
|
||||
key := strings.ToLower(cleanPackagePath(name))
|
||||
usage := fontFiles[key]
|
||||
if usage == nil || usage.unsafe || refs.files[key] || removed[key] || parts[name] != nil {
|
||||
continue
|
||||
}
|
||||
data, err := reader.readFile(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if subset := subsetSourceFont(data, usage); subset != nil {
|
||||
updates[name] = subset
|
||||
}
|
||||
}
|
||||
maps.Copy(parts, updates)
|
||||
for name := range parts {
|
||||
if removed[strings.ToLower(cleanPackagePath(name))] {
|
||||
@@ -148,7 +176,7 @@ func (e *Editor) pruneSourceResources(parts map[string][]byte) (map[string]bool,
|
||||
return removed, nil
|
||||
}
|
||||
|
||||
// scan 流式读取包内XML引用,二进制条目只探测文件头,不展开页面对象或图片像素。
|
||||
// scan 流式读取包内XML引用,二进制条目只探测文件头,不展开页面对象或图片像素
|
||||
// 入参: input 文件流, name 包内路径
|
||||
// 返回: bool 是否资源索引, bool 是否可完整判断引用
|
||||
func (r *editorResourceRefs) scan(input io.Reader, name string) (bool, bool) {
|
||||
@@ -166,6 +194,7 @@ func (r *editorResourceRefs) scan(input io.Reader, name string) (bool, bool) {
|
||||
}
|
||||
decoder := xml.NewDecoder(buffer)
|
||||
var stack []string
|
||||
var fonts []*editorFontUsage
|
||||
var text strings.Builder
|
||||
resource, base := false, ""
|
||||
for {
|
||||
@@ -194,6 +223,13 @@ func (r *editorResourceRefs) scan(input io.Reader, name string) (bool, bool) {
|
||||
}
|
||||
}
|
||||
}
|
||||
var usage *editorFontUsage
|
||||
if len(fonts) != 0 {
|
||||
usage = fonts[len(fonts)-1]
|
||||
if usage != nil && (stack[len(stack)-1] == "TextCode" || stack[len(stack)-1] == "Glyphs") {
|
||||
usage.unsafe = true
|
||||
}
|
||||
}
|
||||
for _, attr := range token.Attr {
|
||||
if attr.Name.Space == "xmlns" || attr.Name.Local == "xmlns" || attr.Name.Space == "http://www.w3.org/XML/1998/namespace" {
|
||||
continue
|
||||
@@ -204,14 +240,30 @@ func (r *editorResourceRefs) scan(input io.Reader, name string) (bool, bool) {
|
||||
if attr.Name.Local != "ID" {
|
||||
r.reference(name, base, attr.Name.Local, attr.Value, resource)
|
||||
}
|
||||
if attr.Name.Local == "Font" {
|
||||
usage = r.fontUsage(attr.Value)
|
||||
if token.Name.Local != "TextObject" && token.Name.Local != "Text" {
|
||||
usage.unsafe = true
|
||||
}
|
||||
} else if attr.Name.Local == "Substitution" {
|
||||
r.fontUsage(attr.Value).unsafe = true
|
||||
}
|
||||
}
|
||||
stack = append(stack, token.Name.Local)
|
||||
fonts = append(fonts, usage)
|
||||
text.Reset()
|
||||
case xml.CharData:
|
||||
text.Write(token)
|
||||
case xml.EndElement:
|
||||
r.reference(name, base, token.Name.Local, text.String(), resource)
|
||||
if (token.Name.Local == "Substitution" || token.Name.Local == "Font") && strings.TrimSpace(text.String()) != "" {
|
||||
r.fontUsage(text.String()).unsafe = true
|
||||
}
|
||||
if usage := fonts[len(fonts)-1]; usage != nil {
|
||||
usage.text(token.Name.Local, text.String())
|
||||
}
|
||||
stack = stack[:len(stack)-1]
|
||||
fonts = fonts[:len(fonts)-1]
|
||||
text.Reset()
|
||||
case xml.Directive:
|
||||
return false, false
|
||||
@@ -219,7 +271,7 @@ func (r *editorResourceRefs) scan(input io.Reader, name string) (bool, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// reference 记录标准资源标识和路径引用,不将普通数字或资源自身ID视为引用。
|
||||
// reference 记录标准资源标识和路径引用,不将普通数字或资源自身ID视为引用
|
||||
// 入参: name 当前文件, base 资源目录, key 字段, value 值, resource 是否资源索引
|
||||
func (r *editorResourceRefs) reference(name, base, key, value string, resource bool) {
|
||||
value = strings.TrimSpace(value)
|
||||
@@ -248,7 +300,7 @@ func (r *editorResourceRefs) reference(name, base, key, value string, resource b
|
||||
r.files[strings.ToLower(cleanPackagePath(resolveResourcePath(name, base, value)))] = true
|
||||
}
|
||||
|
||||
// editorResourceID 规范化ST_ID与ST_RefID的十进制表示。
|
||||
// editorResourceID 规范化ST_ID与ST_RefID的十进制表示
|
||||
// 入参: value 标识文本
|
||||
// 返回: string 标准十进制标识,无效时为空
|
||||
func editorResourceID(value string) string {
|
||||
@@ -259,7 +311,7 @@ func editorResourceID(value string) string {
|
||||
return strconv.FormatUint(id, 10)
|
||||
}
|
||||
|
||||
// editorResourceLocation 按ST_Loc与Res.BaseLoc解析路径,大小写折叠用于保守保留共享文件。
|
||||
// editorResourceLocation 按ST_Loc与Res.BaseLoc解析路径,大小写折叠用于保守保留共享文件
|
||||
// 入参: name 所在XML, base 资源目录, value 路径值
|
||||
// 返回: string 包内路径
|
||||
func editorResourceLocation(name, base, value string) string {
|
||||
|
||||
Reference in new issue
Block a user