mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
a710bc5f41
commit
17a9a03361
2 files changed
+93
-44
No files matched your search
@@ -239,13 +239,19 @@ func (e *Editor) MoveDocumentContext(ctx context.Context, from, to int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return e.editDocumentsContext(ctx, func(reader *Reader, data []byte, root *editorXML) (int, error) {
|
return e.editDocumentsContext(ctx, func(reader *Reader, data []byte, root *editorXML) (int, error) {
|
||||||
bodies := make([][]byte, reader.DocumentCount())
|
nodes := make([]*editorXML, 0, reader.DocumentCount())
|
||||||
for index := range bodies {
|
bodies := make([][]byte, 0, reader.DocumentCount())
|
||||||
|
for _, body := range root.children {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
body := root.childAt("DocBody", index)
|
if body.matchesOFD("DocBody") {
|
||||||
bodies[index] = data[body.start:body.end]
|
nodes = append(nodes, body)
|
||||||
|
bodies = append(bodies, data[body.start:body.end])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(nodes) != reader.DocumentCount() {
|
||||||
|
return 0, fmt.Errorf("document entry count mismatch")
|
||||||
}
|
}
|
||||||
moveEditorItem(bodies, from, to)
|
moveEditorItem(bodies, from, to)
|
||||||
var patches []editorXMLPatch
|
var patches []editorXMLPatch
|
||||||
@@ -253,7 +259,7 @@ func (e *Editor) MoveDocumentContext(ctx context.Context, from, to int) error {
|
|||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
body := root.childAt("DocBody", index)
|
body := nodes[index]
|
||||||
patches = append(patches, editorXMLPatch{body.start, body.end, content})
|
patches = append(patches, editorXMLPatch{body.start, body.end, content})
|
||||||
}
|
}
|
||||||
reader.files["OFD.xml"] = editorPatchXML(data, patches)
|
reader.files["OFD.xml"] = editorPatchXML(data, patches)
|
||||||
|
|||||||
+82
-39
@@ -16,7 +16,9 @@ package ofdgo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -166,59 +168,100 @@ func parseVersionEntries(ctx context.Context, body *editorXML) ([]DocumentVersio
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// readDocumentVersionContext 读取版本描述,按描述文件位置解析清单和文档入口
|
// readDocumentVersionContext 流式读取版本描述,按描述文件位置解析清单和文档入口
|
||||||
// 入参: ctx 取消上下文, id 入口中的版本标识, location 描述文件路径
|
// 入参: ctx 取消上下文, id 入口中的版本标识, location 描述文件路径
|
||||||
// 返回: DocumentVersionInfo 版本信息, error 读取、描述或取消错误
|
// 返回: DocumentVersionInfo 版本信息, error 读取、描述或取消错误
|
||||||
func (r *Reader) readDocumentVersionContext(ctx context.Context, id, location string) (DocumentVersionInfo, error) {
|
func (r *Reader) readDocumentVersionContext(ctx context.Context, id, location string) (DocumentVersionInfo, error) {
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return DocumentVersionInfo{}, err
|
||||||
|
}
|
||||||
|
input, err := r.openFile(location)
|
||||||
|
if err != nil {
|
||||||
|
return DocumentVersionInfo{}, err
|
||||||
|
}
|
||||||
|
defer input.Close()
|
||||||
|
decoder := xml.NewDecoder(imageInput{ReadCloser: input, context: ctx})
|
||||||
var info DocumentVersionInfo
|
var info DocumentVersionInfo
|
||||||
data, err := r.readFileViewContext(ctx, location)
|
var root, parent *editorXML
|
||||||
if err != nil {
|
var files, entry bool
|
||||||
return info, err
|
|
||||||
}
|
|
||||||
root, err := parseEditorXMLContext(ctx, data)
|
|
||||||
if err != nil {
|
|
||||||
return info, err
|
|
||||||
}
|
|
||||||
if root.name.Local != "DocVersion" || strings.TrimSpace(root.attr("ID")) != id {
|
|
||||||
return info, fmt.Errorf("invalid version descriptor %s", location)
|
|
||||||
}
|
|
||||||
list, docRoot := root.child("FileList"), root.child("DocRoot")
|
|
||||||
if list == nil || docRoot == nil {
|
|
||||||
return info, fmt.Errorf("missing version FileList or DocRoot in %s", location)
|
|
||||||
}
|
|
||||||
if root.childAt("FileList", 1) != nil || root.childAt("DocRoot", 1) != nil {
|
|
||||||
return info, fmt.Errorf("duplicate version FileList or DocRoot in %s", location)
|
|
||||||
}
|
|
||||||
entry, err := versionFileLocation(location, editorImportText(data, docRoot))
|
|
||||||
if err != nil {
|
|
||||||
return info, err
|
|
||||||
}
|
|
||||||
info = DocumentVersionInfo{ID: id, Location: location, Version: root.attr("Version"), Name: root.attr("Name"), CreationDate: root.attr("CreationDate"), DocRoot: entry}
|
|
||||||
ids := map[string]bool{id: true}
|
ids := map[string]bool{id: true}
|
||||||
found := false
|
for {
|
||||||
for _, node := range list.children {
|
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return DocumentVersionInfo{}, err
|
return DocumentVersionInfo{}, err
|
||||||
}
|
}
|
||||||
if !node.matchesOFD("File") {
|
token, err := decoder.Token()
|
||||||
continue
|
if err == io.EOF {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
fileID := strings.TrimSpace(node.attr("ID"))
|
|
||||||
if !ofdXMLIDValid(fileID) || ids[fileID] {
|
|
||||||
return DocumentVersionInfo{}, fmt.Errorf("invalid or duplicate version file ID %q", fileID)
|
|
||||||
}
|
|
||||||
ids[fileID] = true
|
|
||||||
name, err := versionFileLocation(location, editorImportText(data, node))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DocumentVersionInfo{}, err
|
return DocumentVersionInfo{}, err
|
||||||
}
|
}
|
||||||
found = found || name == entry
|
switch start := token.(type) {
|
||||||
info.Files = append(info.Files, VersionFile{ID: fileID, Location: name})
|
case xml.StartElement:
|
||||||
|
node := &editorXML{name: start.Name, attrs: start.Attr, parent: parent}
|
||||||
|
if parent == nil {
|
||||||
|
if root != nil || start.Name.Local != "DocVersion" || strings.TrimSpace(node.attr("ID")) != id {
|
||||||
|
return DocumentVersionInfo{}, fmt.Errorf("invalid version descriptor %s", location)
|
||||||
|
}
|
||||||
|
root, parent = node, node
|
||||||
|
info = DocumentVersionInfo{ID: id, Location: location, Version: node.attr("Version"), Name: node.attr("Name"), CreationDate: node.attr("CreationDate")}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case parent == root && node.matchesOFD("FileList"):
|
||||||
|
if files {
|
||||||
|
return DocumentVersionInfo{}, fmt.Errorf("duplicate version FileList in %s", location)
|
||||||
|
}
|
||||||
|
files, parent = true, node
|
||||||
|
case parent == root && node.matchesOFD("DocRoot"):
|
||||||
|
if entry {
|
||||||
|
return DocumentVersionInfo{}, fmt.Errorf("duplicate version DocRoot in %s", location)
|
||||||
|
}
|
||||||
|
var value string
|
||||||
|
if err := decoder.DecodeElement(&value, &start); err != nil {
|
||||||
|
return DocumentVersionInfo{}, err
|
||||||
|
}
|
||||||
|
info.DocRoot, err = versionFileLocation(location, value)
|
||||||
|
if err != nil {
|
||||||
|
return DocumentVersionInfo{}, err
|
||||||
|
}
|
||||||
|
entry = true
|
||||||
|
case parent != root && node.matchesOFD("File"):
|
||||||
|
fileID := strings.TrimSpace(node.attr("ID"))
|
||||||
|
if !ofdXMLIDValid(fileID) || ids[fileID] {
|
||||||
|
return DocumentVersionInfo{}, fmt.Errorf("invalid or duplicate version file ID %q", fileID)
|
||||||
|
}
|
||||||
|
ids[fileID] = true
|
||||||
|
var value string
|
||||||
|
if err := decoder.DecodeElement(&value, &start); err != nil {
|
||||||
|
return DocumentVersionInfo{}, err
|
||||||
|
}
|
||||||
|
name, err := versionFileLocation(location, value)
|
||||||
|
if err != nil {
|
||||||
|
return DocumentVersionInfo{}, err
|
||||||
|
}
|
||||||
|
info.Files = append(info.Files, VersionFile{ID: fileID, Location: name})
|
||||||
|
default:
|
||||||
|
if err := decoder.Skip(); err != nil {
|
||||||
|
return DocumentVersionInfo{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case xml.EndElement:
|
||||||
|
parent = parent.parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !files || !entry {
|
||||||
return DocumentVersionInfo{}, fmt.Errorf("version DocRoot absent from FileList: %s", entry)
|
return DocumentVersionInfo{}, fmt.Errorf("missing version FileList or DocRoot in %s", location)
|
||||||
}
|
}
|
||||||
return info, nil
|
for _, file := range info.Files {
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
return DocumentVersionInfo{}, err
|
||||||
|
}
|
||||||
|
if file.Location == info.DocRoot {
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DocumentVersionInfo{}, fmt.Errorf("version DocRoot absent from FileList: %s", info.DocRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
// versionFileLocation 解析版本描述中的ST_Loc,拒绝空路径和包外路径
|
// versionFileLocation 解析版本描述中的ST_Loc,拒绝空路径和包外路径
|
||||||
|
|||||||
Reference in new issue
Block a user