From b20f411f0d6a5fffe1b4973b196be5c865f191e5 Mon Sep 17 00:00:00 2001 From: xiaoqidun Date: Sat, 10 Oct 2026 21:47:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=BC=96=E8=BE=91=E8=83=BD=E5=8A=9B):=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=89=88=E6=9C=AC=E5=8E=8B=E7=BC=A9=E4=B8=8E?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E9=9A=94=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ofdgo_compression_resources.go | 7 ++++ ofdgo_editor_package.go | 2 +- ofdgo_editor_resources.go | 20 +++++++++- ofdgo_version_edit.go | 69 +++++++++++++++++++++++++++++++--- 4 files changed, 90 insertions(+), 8 deletions(-) diff --git a/ofdgo_compression_resources.go b/ofdgo_compression_resources.go index 543f420..3f21353 100644 --- a/ofdgo_compression_resources.go +++ b/ofdgo_compression_resources.go @@ -51,6 +51,10 @@ func (e *Editor) compressResourceReferences(parts map[string][]byte, reader *Rea return nil } generated = e.generatedVectorReferences(parts, generated) + scope, err := reader.versionResourceFiles(e.output.ctx, parts) + if err != nil { + return err + } names := make(map[string]bool) if reader != nil { for name := range reader.fileIndex { @@ -84,6 +88,9 @@ func (e *Editor) compressResourceReferences(parts map[string][]byte, reader *Rea return nil } actual[key] = name + if scope != nil && !scope[key] { + continue + } data, replaced := parts[name] if known, ok := generated[name]; ok && replaced && known.refs != nil && known.matches(data) { refs.merge(known.refs) diff --git a/ofdgo_editor_package.go b/ofdgo_editor_package.go index 6e9d75c..41f9c63 100644 --- a/ofdgo_editor_package.go +++ b/ofdgo_editor_package.go @@ -596,7 +596,7 @@ func (e *Editor) writeSource(writer io.Writer, fonts map[string][]byte, progress if e.output != nil { ctx = e.output.ctx } - parts, err = reader.versionChanges(ctx, parts) + parts, err = reader.versionOutputChanges(ctx, parts, removed) if err != nil { return 0, err } diff --git a/ofdgo_editor_resources.go b/ofdgo_editor_resources.go index 272cf6e..f0d9f58 100644 --- a/ofdgo_editor_resources.go +++ b/ofdgo_editor_resources.go @@ -17,6 +17,7 @@ package ofdgo import ( "bufio" "bytes" + "context" "encoding/xml" "fmt" "io" @@ -42,8 +43,8 @@ type editorResourceRefs struct { versions map[string]bool } -// compactSourceReferences 合并自产页面的已知引用,其他条目仍完整扫描 -// 按GB/T33190-2016附录A检查标识和路径引用,保留孤立XML中的引用 +// compactSourceReferences 合并自产页面引用,版本文档按当前版本范围扫描 +// 按GB/T33190-2016附录A检查标识和路径引用,保留扫描范围内孤立XML中的引用 // 多文档、未知扩展或无法解析的XML不清理资源,避免误删共享或无法确认用途的条目 // 入参: parts 输出条目, progress 保存进度回调, generated 自产页面及引用 // 返回: map[string]bool 可移除条目, error 读取或取消错误 @@ -56,6 +57,14 @@ func (e *Editor) compactSourceReferences(parts map[string][]byte, progress edito } generated = e.generatedVectorReferences(parts, generated) reader := e.source.reader + ctx := context.Background() + if e.output != nil { + ctx = e.output.ctx + } + scope, err := reader.versionResourceFiles(ctx, parts) + if err != nil { + return nil, err + } names := make(map[string]bool) for name := range reader.fileIndex { names[name] = true @@ -66,6 +75,13 @@ func (e *Editor) compactSourceReferences(parts map[string][]byte, progress edito for name := range parts { names[name] = true } + if scope != nil { + for name := range names { + if !scope[cleanPackagePath(name)] { + delete(names, name) + } + } + } refs := editorResourceRefs{ids: make(map[string]bool), files: make(map[string]bool), fonts: make(map[string]*editorFontUsage)} var resources []string ordered := slices.Sorted(maps.Keys(names)) diff --git a/ofdgo_version_edit.go b/ofdgo_version_edit.go index 7126cf4..5ec227e 100644 --- a/ofdgo_version_edit.go +++ b/ofdgo_version_edit.go @@ -181,10 +181,50 @@ func (r *Reader) versionSharedFiles(ctx context.Context) (map[string]bool, error return shared, nil } +// versionResourceFiles 限定当前版本的资源扫描范围,合并其他文档依赖以保护跨文档引用 +// 入参: ctx 取消上下文, parts 待写入条目 +// 返回: map[string]bool 扫描路径,非版本文档返回nil, error 读取或结构错误 +func (r *Reader) versionResourceFiles(ctx context.Context, parts map[string][]byte) (map[string]bool, error) { + if r == nil || !r.OFD.DocBody[r.documentIndex].versioned { + return nil, nil + } + entry, err := r.DocumentRoot() + if err != nil { + return nil, err + } + graph, err := r.versionEditGraph(ctx, entry, parts) + if err != nil { + return nil, err + } + if r.versionInfo != nil { + for _, file := range r.versionInfo.Files { + graph.used[file.Location] = true + } + } + for index := range r.DocumentCount() { + if index == r.documentIndex { + continue + } + files, err := r.documentFiles(ctx, index) + if err != nil { + return nil, err + } + maps.Copy(graph.used, files) + } + return graph.used, nil +} + // versionChanges 隔离当前入口修改涉及的共享文件,同步版本清单,不修改输入包或修改集 // 入参: ctx 取消上下文, changes 待写入条目 // 返回: map[string][]byte 隔离后的修改集, error 读取、引用或结构错误 func (r *Reader) versionChanges(ctx context.Context, changes map[string][]byte) (map[string][]byte, error) { + return r.versionOutputChanges(ctx, changes, nil) +} + +// versionOutputChanges 隔离版本改动并同步删除清单,保留其他入口仍需使用的文件 +// 入参: ctx 取消上下文, changes 待写入条目, removed 待删除条目,返回前移除受保护路径 +// 返回: map[string][]byte 隔离后的修改集, error 读取、引用或结构错误 +func (r *Reader) versionOutputChanges(ctx context.Context, changes map[string][]byte, removed map[string]bool) (map[string][]byte, error) { if err := ctx.Err(); err != nil { return nil, err } @@ -192,16 +232,19 @@ func (r *Reader) versionChanges(ctx context.Context, changes map[string][]byte) if err != nil { return nil, err } - if !r.OFD.DocBody[r.documentIndex].versioned || len(changes) == 0 { + if !r.OFD.DocBody[r.documentIndex].versioned || len(changes) == 0 && len(removed) == 0 { return changes, ctx.Err() } parts := maps.Clone(changes) + if parts == nil { + parts = make(map[string][]byte) + } for name, data := range parts { if original, err := r.readFileView(name); err == nil && bytes.Equal(original, data) { delete(parts, name) } } - if len(parts) == 0 { + if len(parts) == 0 && len(removed) == 0 { return parts, ctx.Err() } shared, err := r.versionSharedFiles(ctx) @@ -212,6 +255,13 @@ func (r *Reader) versionChanges(ctx context.Context, changes map[string][]byte) if err != nil { return nil, err } + for name := range removed { + if graph.used[name] { + delete(removed, name) + } else { + delete(parts, name) + } + } owned := maps.Clone(graph.used) if r.versionInfo != nil { for _, file := range r.versionInfo.Files { @@ -266,7 +316,7 @@ func (r *Reader) versionChanges(ctx context.Context, changes map[string][]byte) delete(parts, source) } if r.versionInfo != nil { - if err := r.versionManifest(parts, paths, graph.used, shared); err != nil { + if err := r.versionManifest(parts, paths, graph.used, shared, removed); err != nil { return nil, err } } else if target := paths[entry]; target != "" { @@ -284,6 +334,11 @@ func (r *Reader) versionChanges(ctx context.Context, changes map[string][]byte) node := root.childAt("DocBody", r.documentIndex).child("DocRoot") parts["OFD.xml"] = editorPatchXML(data, []editorXMLPatch{editorXMLContent(data, node, editorFontXMLText("/"+target))}) } + for name := range removed { + if shared[name] { + delete(removed, name) + } + } return parts, ctx.Err() } @@ -329,9 +384,9 @@ func (file *versionEditFile) rewrite(paths map[string]string) ([]byte, error) { } // versionManifest 更新所选版本的入口与文件清单,保留已有文件标识及扩展字段 -// 入参: parts 输出条目, paths 隔离路径, used 当前内容依赖, shared 其他入口依赖 +// 入参: parts 输出条目, paths 隔离路径, used 当前内容依赖, shared 其他入口依赖, removed 当前版本移除的文件 // 返回: error 描述读取或XML编码错误 -func (r *Reader) versionManifest(parts map[string][]byte, paths map[string]string, used, shared map[string]bool) error { +func (r *Reader) versionManifest(parts map[string][]byte, paths map[string]string, used, shared, removed map[string]bool) error { version := r.versionInfo data, err := r.readFile(version.Location) if err != nil { @@ -354,6 +409,10 @@ func (r *Reader) versionManifest(parts map[string][]byte, paths map[string]strin if err != nil { return err } + if removed[name] { + patches = append(patches, editorXMLPatch{start: node.start, end: node.end}) + continue + } if target := paths[name]; target != "" { name = target patches = append(patches, editorXMLContent(data, node, editorFontXMLText("/"+target)))