mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
d97c6f4e6f
commit
73889edefb
16 files changed
+175
-175
No files matched your search
@@ -130,12 +130,12 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 1. 打开文档
|
// 1. 打开文档
|
||||||
input, err := ofdgo.OpenFile(context.Background(), "test.ofd", ofdgo.InputOptions{})
|
source, err := ofdgo.OpenFile(context.Background(), "test.ofd", ofdgo.SourceOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
reader, err := ofdgo.NewReader(input)
|
reader, err := ofdgo.NewReader(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -172,11 +172,11 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 1. 打开文档
|
// 1. 打开文档
|
||||||
input, err := ofdgo.OpenFile(context.Background(), "test.pdf", ofdgo.InputOptions{})
|
source, err := ofdgo.OpenFile(context.Background(), "test.pdf", ofdgo.SourceOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
// 2. 创建文件
|
// 2. 创建文件
|
||||||
ofdFile, err := os.Create("test.ofd")
|
ofdFile, err := os.Create("test.ofd")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -184,7 +184,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer ofdFile.Close()
|
defer ofdFile.Close()
|
||||||
// 3. 转换文档
|
// 3. 转换文档
|
||||||
report, err := ofdgo.ConvertPDF(context.Background(), input, ofdFile, ofdgo.PDFImportOptions{})
|
report, err := ofdgo.ConvertPDF(context.Background(), source, ofdFile, ofdgo.PDFImportOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -209,12 +209,12 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 1. 打开OFD文件
|
// 1. 打开OFD文件
|
||||||
input, err := ofdgo.OpenFile(context.Background(), "test.ofd", ofdgo.InputOptions{})
|
source, err := ofdgo.OpenFile(context.Background(), "test.ofd", ofdgo.SourceOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
reader, err := ofdgo.NewReader(input)
|
reader, err := ofdgo.NewReader(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -247,13 +247,13 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 1. 打开OFD文件
|
// 1. 打开OFD文件
|
||||||
input, err := ofdgo.OpenFile(context.Background(), "test.ofd", ofdgo.InputOptions{})
|
source, err := ofdgo.OpenFile(context.Background(), "test.ofd", ofdgo.SourceOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
// 2. 验证OFD签名
|
// 2. 验证OFD签名
|
||||||
reports, err := ofdgo.VerifySignatures(input)
|
reports, err := ofdgo.VerifySignatures(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -296,12 +296,12 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 1. 打开OFD文件
|
// 1. 打开OFD文件
|
||||||
input, err := ofdgo.OpenFile(context.Background(), "invoice.ofd", ofdgo.InputOptions{})
|
source, err := ofdgo.OpenFile(context.Background(), "invoice.ofd", ofdgo.SourceOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
reader, err := ofdgo.NewReader(input)
|
reader, err := ofdgo.NewReader(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-34
@@ -57,7 +57,7 @@ type FontInfo = ofdgo.FontInfo
|
|||||||
type Session struct {
|
type Session struct {
|
||||||
Reader *ofdgo.Reader
|
Reader *ofdgo.Reader
|
||||||
Renderer *ofdgo.Renderer
|
Renderer *ofdgo.Renderer
|
||||||
input *ofdgo.Input
|
source *ofdgo.Source
|
||||||
fontFS *ofdgo.FontFS
|
fontFS *ofdgo.FontFS
|
||||||
doc *ofdgo.Document
|
doc *ofdgo.Document
|
||||||
pageCache map[int]*ofdgo.PageContent
|
pageCache map[int]*ofdgo.PageContent
|
||||||
@@ -425,7 +425,7 @@ type businessEngine struct {
|
|||||||
copiedObjects *editorClipboard
|
copiedObjects *editorClipboard
|
||||||
copiedStyle *ofdgo.GraphicObject
|
copiedStyle *ofdgo.GraphicObject
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
resolveInput func(context.Context, any) (io.ReaderAt, int64, error)
|
resolveSource func(context.Context, any) (io.ReaderAt, int64, error)
|
||||||
conversionPool *ofdgo.ConversionPool
|
conversionPool *ofdgo.ConversionPool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,21 +436,21 @@ func Open(data []byte, opts OpenOptions) (*Session, error) {
|
|||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return nil, fmt.Errorf("empty ofd data")
|
return nil, fmt.Errorf("empty ofd data")
|
||||||
}
|
}
|
||||||
input, err := ofdgo.NewInput(bytes.NewReader(data), int64(len(data)))
|
source, err := ofdgo.NewSource(bytes.NewReader(data), int64(len(data)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader, err := ofdgo.NewReader(input, opts.ReaderOptions...)
|
reader, err := ofdgo.NewReader(source, opts.ReaderOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
input.Close()
|
source.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
session, err := newSession(reader, opts)
|
session, err := newSession(reader, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
input.Close()
|
source.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
session.input = input
|
session.source = source
|
||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,14 +461,14 @@ func (s *Session) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
reader := s.Reader
|
reader := s.Reader
|
||||||
input := s.input
|
source := s.source
|
||||||
*s = Session{}
|
*s = Session{}
|
||||||
var err error
|
var err error
|
||||||
if reader != nil {
|
if reader != nil {
|
||||||
err = reader.Close()
|
err = reader.Close()
|
||||||
}
|
}
|
||||||
if input != nil {
|
if source != nil {
|
||||||
err = errors.Join(err, input.Close())
|
err = errors.Join(err, source.Close())
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1336,12 +1336,12 @@ func (e *businessEngine) detectDocumentFormat(args []platformValue) (any, error)
|
|||||||
return nil, fmt.Errorf("missing detection arguments")
|
return nil, fmt.Errorf("missing detection arguments")
|
||||||
}
|
}
|
||||||
reader := &browserReaderAt{read: args[0], size: int64(args[1].Float()), checkpoint: args[2]}
|
reader := &browserReaderAt{read: args[0], size: int64(args[1].Float()), checkpoint: args[2]}
|
||||||
input, err := ofdgo.NewInput(reader, reader.size)
|
source, err := ofdgo.NewSource(reader, reader.size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
return ofdgo.DetectFormat(input)
|
return ofdgo.DetectFormat(source)
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertPDFDocument 通过库转换PDF,不替换当前文档会话
|
// convertPDFDocument 通过库转换PDF,不替换当前文档会话
|
||||||
@@ -1351,11 +1351,11 @@ func (e *businessEngine) convertPDFDocument(args []platformValue) (any, error) {
|
|||||||
if len(args) != 6 {
|
if len(args) != 6 {
|
||||||
return nil, fmt.Errorf("missing PDF data")
|
return nil, fmt.Errorf("missing PDF data")
|
||||||
}
|
}
|
||||||
input, err := e.inputFromValue(args[0])
|
source, err := e.sourceFromValue(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
fonts, err := e.fontsFromJS(args[1])
|
fonts, err := e.fontsFromJS(args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1376,7 +1376,7 @@ func (e *businessEngine) convertPDFDocument(args []platformValue) (any, error) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
options.RendererOptions = []ofdgo.RendererOption{ofdgo.WithFontFS(fontSources...)}
|
options.RendererOptions = []ofdgo.RendererOption{ofdgo.WithFontFS(fontSources...)}
|
||||||
editor, report, err := ofdgo.ImportPDF(e.operationContext(), input, options)
|
editor, report, err := ofdgo.ImportPDF(e.operationContext(), source, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1478,12 +1478,12 @@ func (e *businessEngine) convertFile(args []platformValue) (any, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader := &browserReaderAt{read: args[0], checkpoint: args[6], size: int64(args[1].Float())}
|
reader := &browserReaderAt{read: args[0], checkpoint: args[6], size: int64(args[1].Float())}
|
||||||
input, err := ofdgo.NewInput(reader, reader.size)
|
source, err := ofdgo.NewSource(reader, reader.size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
report, err := ofdgo.Convert(e.newOutputContext(args[6]), input, writer, options)
|
report, err := ofdgo.Convert(e.newOutputContext(args[6]), source, writer, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1514,8 +1514,8 @@ func (e *businessEngine) packFiles(args []platformValue) (any, error) {
|
|||||||
inputs := make([]*browserReaderAt, files.Length())
|
inputs := make([]*browserReaderAt, files.Length())
|
||||||
defer func() {
|
defer func() {
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if entry.Input != nil {
|
if entry.Source != nil {
|
||||||
entry.Input.Close()
|
entry.Source.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -1524,12 +1524,12 @@ func (e *businessEngine) packFiles(args []platformValue) (any, error) {
|
|||||||
name := file.Get("name").String()
|
name := file.Get("name").String()
|
||||||
read := args[1].Invoke(i)
|
read := args[1].Invoke(i)
|
||||||
reader := &browserReaderAt{read: read, checkpoint: args[4], size: int64(file.Get("size").Float())}
|
reader := &browserReaderAt{read: read, checkpoint: args[4], size: int64(file.Get("size").Float())}
|
||||||
input, err := ofdgo.NewInput(reader, reader.size)
|
source, err := ofdgo.NewSource(reader, reader.size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
inputs[i] = reader
|
inputs[i] = reader
|
||||||
entries[i] = ofdgo.ArchiveFile{Name: name, Input: input}
|
entries[i] = ofdgo.ArchiveFile{Name: name, Source: source}
|
||||||
}
|
}
|
||||||
options := ofdgo.ArchiveOptions{OnProgress: func(completed, total int) error {
|
options := ofdgo.ArchiveOptions{OnProgress: func(completed, total int) error {
|
||||||
if completed > 0 {
|
if completed > 0 {
|
||||||
@@ -1558,14 +1558,14 @@ func (e *businessEngine) openDocument(args []platformValue) (any, error) {
|
|||||||
if len(args) < 3 {
|
if len(args) < 3 {
|
||||||
return nil, fmt.Errorf("missing open arguments")
|
return nil, fmt.Errorf("missing open arguments")
|
||||||
}
|
}
|
||||||
input, err := e.inputFromValue(args[0])
|
source, err := e.sourceFromValue(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
keep := false
|
keep := false
|
||||||
defer func() {
|
defer func() {
|
||||||
if !keep {
|
if !keep {
|
||||||
input.Close()
|
source.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
fonts, err := e.fontsFromJS(args[1])
|
fonts, err := e.fontsFromJS(args[1])
|
||||||
@@ -1582,7 +1582,7 @@ func (e *businessEngine) openDocument(args []platformValue) (any, error) {
|
|||||||
defer clear(credentials.Password)
|
defer clear(credentials.Password)
|
||||||
options.ReaderOptions = append(options.ReaderOptions, ofdgo.WithCredentials(credentials))
|
options.ReaderOptions = append(options.ReaderOptions, ofdgo.WithCredentials(credentials))
|
||||||
}
|
}
|
||||||
reader, err := ofdgo.NewReader(input, options.ReaderOptions...)
|
reader, err := ofdgo.NewReader(source, options.ReaderOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1599,7 +1599,7 @@ func (e *businessEngine) openDocument(args []platformValue) (any, error) {
|
|||||||
e.currentSession = nil
|
e.currentSession = nil
|
||||||
}
|
}
|
||||||
e.currentSession = session
|
e.currentSession = session
|
||||||
session.input = input
|
session.source = source
|
||||||
keep = true
|
keep = true
|
||||||
return e.currentSession.Summary(), nil
|
return e.currentSession.Summary(), nil
|
||||||
}
|
}
|
||||||
@@ -5505,14 +5505,14 @@ func (e *businessEngine) loadImport(args []platformValue) (any, error) {
|
|||||||
if args[0].IsNull() {
|
if args[0].IsNull() {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
input, err := e.inputFromValue(args[0])
|
source, err := e.sourceFromValue(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
keep := false
|
keep := false
|
||||||
defer func() {
|
defer func() {
|
||||||
if !keep {
|
if !keep {
|
||||||
input.Close()
|
source.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
var options []ofdgo.ReaderOption
|
var options []ofdgo.ReaderOption
|
||||||
@@ -5524,11 +5524,11 @@ func (e *businessEngine) loadImport(args []platformValue) (any, error) {
|
|||||||
defer clear(credentials.Password)
|
defer clear(credentials.Password)
|
||||||
options = append(options, ofdgo.WithCredentials(credentials))
|
options = append(options, ofdgo.WithCredentials(credentials))
|
||||||
}
|
}
|
||||||
reader, err := ofdgo.NewReader(input, options...)
|
reader, err := ofdgo.NewReader(source, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader.Closer = input
|
reader.Closer = source
|
||||||
doc, err := reader.Doc()
|
doc, err := reader.Doc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reader.Close()
|
reader.Close()
|
||||||
@@ -6180,7 +6180,7 @@ func (e *businessEngine) selectDocumentVersion(args []platformValue) (any, error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
session.input, e.currentSession.input = e.currentSession.input, nil
|
session.source, e.currentSession.source = e.currentSession.source, nil
|
||||||
_ = e.currentSession.Close()
|
_ = e.currentSession.Close()
|
||||||
e.currentSession = session
|
e.currentSession = session
|
||||||
e.clearImport()
|
e.clearImport()
|
||||||
@@ -6338,7 +6338,7 @@ func (e *businessEngine) selectDocument(args []platformValue) (any, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
session.input, e.currentSession.input = e.currentSession.input, nil
|
session.source, e.currentSession.source = e.currentSession.source, nil
|
||||||
_ = e.currentSession.Close()
|
_ = e.currentSession.Close()
|
||||||
e.currentSession, e.currentEditor = session, session.editor
|
e.currentSession, e.currentEditor = session, session.editor
|
||||||
if e.pendingImport != nil {
|
if e.pendingImport != nil {
|
||||||
@@ -6440,7 +6440,7 @@ func (e *businessEngine) previewEditor(editor *ofdgo.Editor, annotations bool) (
|
|||||||
editor.SetFontFS(session.fontFS)
|
editor.SetFontFS(session.fontFS)
|
||||||
}
|
}
|
||||||
if editor == e.currentEditor {
|
if editor == e.currentEditor {
|
||||||
session.input, e.currentSession.input = e.currentSession.input, nil
|
session.source, e.currentSession.source = e.currentSession.source, nil
|
||||||
}
|
}
|
||||||
_ = e.currentSession.Close()
|
_ = e.currentSession.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ type NativeEngine struct {
|
|||||||
// nativeReader 在会话当前操作上下文中分块读取,不捕获已结束请求的上下文
|
// nativeReader 在会话当前操作上下文中分块读取,不捕获已结束请求的上下文
|
||||||
type nativeReader struct {
|
type nativeReader struct {
|
||||||
engine *NativeEngine
|
engine *NativeEngine
|
||||||
input io.ReaderAt
|
source io.ReaderAt
|
||||||
}
|
}
|
||||||
|
|
||||||
// nativeCall 保存单次worker适配状态
|
// nativeCall 保存单次worker适配状态
|
||||||
@@ -139,7 +139,7 @@ func NewNativeEngine(resolve NativeResolver) *NativeEngine { return &NativeEngin
|
|||||||
func (e *NativeEngine) Call(ctx context.Context, name string, args []any, emit func(any)) (result map[string]any) {
|
func (e *NativeEngine) Call(ctx context.Context, name string, args []any, emit func(any)) (result map[string]any) {
|
||||||
e.once.Do(func() {
|
e.once.Do(func() {
|
||||||
e.gate = make(chan struct{}, 1)
|
e.gate = make(chan struct{}, 1)
|
||||||
e.resolveInput = e.input
|
e.resolveSource = e.source
|
||||||
e.conversionPool = e.ConversionPool
|
e.conversionPool = e.ConversionPool
|
||||||
})
|
})
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
@@ -236,7 +236,7 @@ func (e *NativeEngine) Call(ctx context.Context, name string, args []any, emit f
|
|||||||
|
|
||||||
// Close 释放会话,不关闭宿主持有的ReaderAt资源
|
// Close 释放会话,不关闭宿主持有的ReaderAt资源
|
||||||
func (e *NativeEngine) Close() error {
|
func (e *NativeEngine) Close() error {
|
||||||
e.once.Do(func() { e.gate = make(chan struct{}, 1); e.resolveInput = e.input })
|
e.once.Do(func() { e.gate = make(chan struct{}, 1); e.resolveSource = e.source })
|
||||||
e.gate <- struct{}{}
|
e.gate <- struct{}{}
|
||||||
defer func() { <-e.gate }()
|
defer func() { <-e.gate }()
|
||||||
e.closed = true
|
e.closed = true
|
||||||
@@ -253,8 +253,8 @@ func (e *NativeEngine) Close() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// input 读取授权源并以宿主报告的大小为准
|
// source 读取授权源并以宿主报告的大小为准
|
||||||
func (e *NativeEngine) input(ctx context.Context, value any) (io.ReaderAt, int64, error) {
|
func (e *NativeEngine) source(ctx context.Context, value any) (io.ReaderAt, int64, error) {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ func (e *NativeEngine) input(ctx context.Context, value any) (io.ReaderAt, int64
|
|||||||
value = p.value
|
value = p.value
|
||||||
}
|
}
|
||||||
if data, ok := value.([]byte); ok {
|
if data, ok := value.([]byte); ok {
|
||||||
return nativeReader{engine: e, input: bytes.NewReader(data)}, int64(len(data)), nil
|
return nativeReader{engine: e, source: bytes.NewReader(data)}, int64(len(data)), nil
|
||||||
}
|
}
|
||||||
descriptor, ok := value.(map[string]any)
|
descriptor, ok := value.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -272,14 +272,14 @@ func (e *NativeEngine) input(ctx context.Context, value any) (io.ReaderAt, int64
|
|||||||
if !ok || token == "" || e.Resolve == nil {
|
if !ok || token == "" || e.Resolve == nil {
|
||||||
return nil, 0, fmt.Errorf("unauthorized native file")
|
return nil, 0, fmt.Errorf("unauthorized native file")
|
||||||
}
|
}
|
||||||
input, size, err := e.Resolve(token)
|
source, size, err := e.Resolve(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
if input == nil || size < 0 {
|
if source == nil || size < 0 {
|
||||||
return nil, 0, fmt.Errorf("invalid native file input")
|
return nil, 0, fmt.Errorf("invalid native file source")
|
||||||
}
|
}
|
||||||
return nativeReader{engine: e, input: input}, size, nil
|
return nativeReader{engine: e, source: source}, size, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAt 分块传递取消检查,宿主ReadAt自身阻塞时由宿主控制超时
|
// ReadAt 分块传递取消检查,宿主ReadAt自身阻塞时由宿主控制超时
|
||||||
@@ -290,7 +290,7 @@ func (r nativeReader) ReadAt(data []byte, offset int64) (int, error) {
|
|||||||
return total, err
|
return total, err
|
||||||
}
|
}
|
||||||
n := min(len(data), 256<<10)
|
n := min(len(data), 256<<10)
|
||||||
got, err := r.input.ReadAt(data[:n], offset)
|
got, err := r.source.ReadAt(data[:n], offset)
|
||||||
total += got
|
total += got
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return total, err
|
return total, err
|
||||||
@@ -307,7 +307,7 @@ func (r nativeReader) ReadAt(data []byte, offset int64) (int, error) {
|
|||||||
// 入参: ctx 调用上下文, value 资源参数
|
// 入参: ctx 调用上下文, value 资源参数
|
||||||
// 返回: []byte 资源数据, error 读取错误
|
// 返回: []byte 资源数据, error 读取错误
|
||||||
func (e *NativeEngine) readBytes(ctx context.Context, value any) ([]byte, error) {
|
func (e *NativeEngine) readBytes(ctx context.Context, value any) ([]byte, error) {
|
||||||
input, size, err := e.input(ctx, value)
|
source, size, err := e.source(ctx, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -320,7 +320,7 @@ func (e *NativeEngine) readBytes(ctx context.Context, value any) ([]byte, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
n := int(min(int64(256<<10), size-offset))
|
n := int(min(int64(256<<10), size-offset))
|
||||||
got, err := input.ReadAt(output[int(offset):int(offset)+n], offset)
|
got, err := source.ReadAt(output[int(offset):int(offset)+n], offset)
|
||||||
if got != n {
|
if got != n {
|
||||||
return nil, io.ErrUnexpectedEOF
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
@@ -540,7 +540,7 @@ func (c *nativeCall) progress(kind, stage string, phased bool) nativeCallback {
|
|||||||
|
|
||||||
// readCallback 创建有界随机读取回调
|
// readCallback 创建有界随机读取回调
|
||||||
func (c *nativeCall) readCallback(value any) (nativeCallback, int64, error) {
|
func (c *nativeCall) readCallback(value any) (nativeCallback, int64, error) {
|
||||||
input, size, err := c.engine.input(c.ctx, value)
|
source, size, err := c.engine.source(c.ctx, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@@ -553,7 +553,7 @@ func (c *nativeCall) readCallback(value any) (nativeCallback, int64, error) {
|
|||||||
return nil, fmt.Errorf("invalid native read range")
|
return nil, fmt.Errorf("invalid native read range")
|
||||||
}
|
}
|
||||||
data := make([]byte, n)
|
data := make([]byte, n)
|
||||||
got, err := input.ReadAt(data, offset)
|
got, err := source.ReadAt(data, offset)
|
||||||
if got != n {
|
if got != n {
|
||||||
return nil, io.ErrUnexpectedEOF
|
return nil, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
@@ -876,13 +876,13 @@ func nativeOutputBase(value platformValue) string {
|
|||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
// inputFromValue 读取宿主授权的随机读取源
|
// sourceFromValue 读取宿主授权的随机读取源
|
||||||
func (e *businessEngine) inputFromValue(value platformValue) (*ofdgo.Input, error) {
|
func (e *businessEngine) sourceFromValue(value platformValue) (*ofdgo.Source, error) {
|
||||||
reader, size, err := e.resolveInput(e.operationContext(), value.value)
|
reader, size, err := e.resolveSource(e.operationContext(), value.value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ofdgo.NewInput(reader, size)
|
return ofdgo.NewSource(reader, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// platformValueOf 包装参数
|
// platformValueOf 包装参数
|
||||||
@@ -1028,12 +1028,12 @@ func (e *businessEngine) bytesFromJS(v platformValue) ([]byte, error) {
|
|||||||
if data, ok := v.value.([]byte); ok {
|
if data, ok := v.value.([]byte); ok {
|
||||||
return append([]byte(nil), data...), nil
|
return append([]byte(nil), data...), nil
|
||||||
}
|
}
|
||||||
input, err := e.inputFromValue(v)
|
source, err := e.sourceFromValue(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer input.Close()
|
defer source.Close()
|
||||||
return io.ReadAll(io.NewSectionReader(input, 0, input.Size()))
|
return io.ReadAll(io.NewSectionReader(source, 0, source.Size()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// successResult 保留二进制返回结构
|
// successResult 保留二进制返回结构
|
||||||
|
|||||||
@@ -221,11 +221,11 @@ func platformParseJSON(data []byte) map[string]any {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// inputFromValue 读取浏览器二进制源
|
// sourceFromValue 读取浏览器二进制源
|
||||||
func (e *businessEngine) inputFromValue(value platformValue) (*ofdgo.Input, error) {
|
func (e *businessEngine) sourceFromValue(value platformValue) (*ofdgo.Source, error) {
|
||||||
data, err := e.bytesFromJS(value)
|
data, err := e.bytesFromJS(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return ofdgo.NewInput(bytes.NewReader(data), int64(len(data)))
|
return ofdgo.NewSource(bytes.NewReader(data), int64(len(data)))
|
||||||
}
|
}
|
||||||
@@ -475,11 +475,11 @@ func (h *Host) call(ctx context.Context, name string, value any) (any, error) {
|
|||||||
}
|
}
|
||||||
descriptor, _ := args["data"].(map[string]any)
|
descriptor, _ := args["data"].(map[string]any)
|
||||||
key, _ := descriptor["nativeFile"].(string)
|
key, _ := descriptor["nativeFile"].(string)
|
||||||
input, size, err := h.files.resolve(key)
|
source, size, err := h.files.resolve(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = io.Copy(writer, io.NewSectionReader(input, 0, size))
|
_, err = io.Copy(writer, io.NewSectionReader(source, 0, size))
|
||||||
return nil, err
|
return nil, err
|
||||||
case "fonts":
|
case "fonts":
|
||||||
h.fontOnce.Do(h.readFonts)
|
h.fontOnce.Do(h.readFonts)
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ import (
|
|||||||
basefile "github.com/xiaoqidun/ofdgo/internal/base/file"
|
basefile "github.com/xiaoqidun/ofdgo/internal/base/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Input 统一文件、内存及顺序流的随机读取,可并发读取和关闭,不可复制
|
// Source 统一文件、内存及顺序流的随机读取,可并发读取和关闭,不可复制
|
||||||
// 调用方应在阅读、编辑及转换结束后调用Close,借入的数据需在此期间保持不变
|
// 调用方应在阅读、编辑及转换结束后调用Close,借入的数据需在此期间保持不变
|
||||||
// 借入的随机读取器应支持并发ReadAt,Close不会关闭调用方传入的读取器
|
// 借入的随机读取器应支持并发ReadAt,Close不会关闭调用方传入的读取器
|
||||||
type Input struct {
|
type Source struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
reader io.ReaderAt
|
reader io.ReaderAt
|
||||||
size int64
|
size int64
|
||||||
@@ -43,12 +43,12 @@ type Input struct {
|
|||||||
temp bool
|
temp bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputOptions 设置顺序输入的缓存及大小限制,单位为字节
|
// SourceOptions 设置顺序输入的缓存及大小限制,单位为字节
|
||||||
// MemoryLimit为0时使用8MiB,浏览器WASM仅用内存;负值表示仅用内存
|
// MemoryLimit为0时使用8MiB,浏览器WASM仅用内存;负值表示仅用内存
|
||||||
// TempDir为空时使用系统临时目录,不自动创建调用方指定的目录
|
// TempDir为空时使用系统临时目录,不自动创建调用方指定的目录
|
||||||
// MaxSize为0时不限制输入大小,OpenFile和ReadInput均检查此限制
|
// MaxSize为0时不限制输入大小,OpenFile和ReadSource均检查此限制
|
||||||
// 无临时文件系统的平台可显式使用仅内存模式,并通过MaxSize限制输入
|
// 无临时文件系统的平台可显式使用仅内存模式,并通过MaxSize限制输入
|
||||||
type InputOptions struct {
|
type SourceOptions struct {
|
||||||
MemoryLimit int64
|
MemoryLimit int64
|
||||||
MaxSize int64
|
MaxSize int64
|
||||||
TempDir string
|
TempDir string
|
||||||
@@ -56,8 +56,8 @@ type InputOptions struct {
|
|||||||
|
|
||||||
// OpenFile 打开文件输入,不复制文件内容,Close释放文件句柄
|
// OpenFile 打开文件输入,不复制文件内容,Close释放文件句柄
|
||||||
// 入参: ctx 取消上下文, path 文件路径, options 输入选项
|
// 入参: ctx 取消上下文, path 文件路径, options 输入选项
|
||||||
// 返回: *Input 输入源, error 打开或大小错误
|
// 返回: *Source 输入源, error 打开或大小错误
|
||||||
func OpenFile(ctx context.Context, path string, options InputOptions) (*Input, error) {
|
func OpenFile(ctx context.Context, path string, options SourceOptions) (*Source, error) {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -72,39 +72,39 @@ func OpenFile(ctx context.Context, path string, options InputOptions) (*Input, e
|
|||||||
}
|
}
|
||||||
if !info.Mode().IsRegular() {
|
if !info.Mode().IsRegular() {
|
||||||
f.Close()
|
f.Close()
|
||||||
return nil, fmt.Errorf("input is not a regular file")
|
return nil, fmt.Errorf("source is not a regular file")
|
||||||
}
|
}
|
||||||
input, err := NewInput(f, info.Size())
|
source, err := NewSource(f, info.Size())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
input.file, input.path = f, path
|
source.file, source.path = f, path
|
||||||
if err := input.checkOptions(ctx, options); err != nil {
|
if err := source.checkOptions(ctx, options); err != nil {
|
||||||
input.Close()
|
source.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return input, nil
|
return source, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInput 借用指定长度的随机读取源,不复制数据或接管其生命周期
|
// NewSource 借用指定长度的随机读取源,不复制数据或接管其生命周期
|
||||||
// 入参: reader 随机读取器, size 数据大小
|
// 入参: reader 随机读取器, size 数据大小
|
||||||
// 返回: *Input 输入源, error 参数错误
|
// 返回: *Source 输入源, error 参数错误
|
||||||
func NewInput(reader io.ReaderAt, size int64) (*Input, error) {
|
func NewSource(reader io.ReaderAt, size int64) (*Source, error) {
|
||||||
if reader == nil || size < 0 {
|
if reader == nil || size < 0 {
|
||||||
return nil, fmt.Errorf("invalid input")
|
return nil, fmt.Errorf("invalid source")
|
||||||
}
|
}
|
||||||
return &Input{reader: reader, size: size}, nil
|
return &Source{reader: reader, size: size}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadInput 从当前位置接收顺序输入,超过内存阈值后转入临时文件
|
// ReadSource 从当前位置接收顺序输入,超过内存阈值后转入临时文件
|
||||||
// 已知大小且支持随机访问的可定位读取器直接复用,不移动其当前位置
|
// 已知大小且支持随机访问的可定位读取器直接复用,不移动其当前位置
|
||||||
// 不关闭传入流;取消无法中断阻塞的Read,调用方应自行设置超时或关闭流
|
// 不关闭传入流;取消无法中断阻塞的Read,调用方应自行设置超时或关闭流
|
||||||
// 入参: ctx 取消上下文, reader 输入流, options 输入选项
|
// 入参: ctx 取消上下文, reader 输入流, options 输入选项
|
||||||
// 返回: *Input 输入源, error 读取、缓存或取消错误
|
// 返回: *Source 输入源, error 读取、缓存或取消错误
|
||||||
func ReadInput(ctx context.Context, reader io.Reader, options InputOptions) (*Input, error) {
|
func ReadSource(ctx context.Context, reader io.Reader, options SourceOptions) (*Source, error) {
|
||||||
if reader == nil || options.MaxSize < 0 {
|
if reader == nil || options.MaxSize < 0 {
|
||||||
return nil, fmt.Errorf("invalid input options")
|
return nil, fmt.Errorf("invalid source options")
|
||||||
}
|
}
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -129,16 +129,16 @@ func ReadInput(ctx context.Context, reader io.Reader, options InputOptions) (*In
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if offset < 0 || offset > size {
|
if offset < 0 || offset > size {
|
||||||
return nil, fmt.Errorf("invalid input offset")
|
return nil, fmt.Errorf("invalid source offset")
|
||||||
}
|
}
|
||||||
input, err := NewInput(io.NewSectionReader(random, offset, size-offset), size-offset)
|
source, err := NewSource(io.NewSectionReader(random, offset, size-offset), size-offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := input.checkOptions(ctx, options); err != nil {
|
if err := source.checkOptions(ctx, options); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return input, nil
|
return source, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,11 +149,11 @@ func ReadInput(ctx context.Context, reader io.Reader, options InputOptions) (*In
|
|||||||
limit = -1
|
limit = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input := &Input{}
|
source := &Source{}
|
||||||
success := false
|
success := false
|
||||||
defer func() {
|
defer func() {
|
||||||
if !success {
|
if !success {
|
||||||
input.Close()
|
source.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
var memory bytes.Buffer
|
var memory bytes.Buffer
|
||||||
@@ -165,7 +165,7 @@ func ReadInput(ctx context.Context, reader io.Reader, options InputOptions) (*In
|
|||||||
}
|
}
|
||||||
n, err := reader.Read(buffer)
|
n, err := reader.Read(buffer)
|
||||||
if n < 0 || n > len(buffer) {
|
if n < 0 || n > len(buffer) {
|
||||||
return nil, fmt.Errorf("invalid input read count")
|
return nil, fmt.Errorf("invalid source read count")
|
||||||
}
|
}
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -175,28 +175,28 @@ func ReadInput(ctx context.Context, reader io.Reader, options InputOptions) (*In
|
|||||||
}
|
}
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
empty = 0
|
empty = 0
|
||||||
if input.size > int64(^uint64(0)>>1)-int64(n) || options.MaxSize > 0 && int64(n) > options.MaxSize-input.size {
|
if source.size > int64(^uint64(0)>>1)-int64(n) || options.MaxSize > 0 && int64(n) > options.MaxSize-source.size {
|
||||||
return nil, fmt.Errorf("input exceeds size limit")
|
return nil, fmt.Errorf("source exceeds size limit")
|
||||||
}
|
}
|
||||||
if input.file == nil && limit >= 0 && input.size+int64(n) > limit {
|
if source.file == nil && limit >= 0 && source.size+int64(n) > limit {
|
||||||
file, failure := basefile.NewTemp(options.TempDir)
|
file, failure := basefile.NewTemp(options.TempDir)
|
||||||
if failure != nil {
|
if failure != nil {
|
||||||
return nil, failure
|
return nil, failure
|
||||||
}
|
}
|
||||||
input.file, input.temp = file, true
|
source.file, source.temp = file, true
|
||||||
if _, failure = file.Write(memory.Bytes()); failure != nil {
|
if _, failure = file.Write(memory.Bytes()); failure != nil {
|
||||||
return nil, failure
|
return nil, failure
|
||||||
}
|
}
|
||||||
memory = bytes.Buffer{}
|
memory = bytes.Buffer{}
|
||||||
}
|
}
|
||||||
var output io.Writer = &memory
|
var output io.Writer = &memory
|
||||||
if input.file != nil {
|
if source.file != nil {
|
||||||
output = input.file
|
output = source.file
|
||||||
}
|
}
|
||||||
if _, failure := output.Write(buffer[:n]); failure != nil {
|
if _, failure := output.Write(buffer[:n]); failure != nil {
|
||||||
return nil, failure
|
return nil, failure
|
||||||
}
|
}
|
||||||
input.size += int64(n)
|
source.size += int64(n)
|
||||||
} else if err == nil {
|
} else if err == nil {
|
||||||
empty++
|
empty++
|
||||||
if empty >= 100 {
|
if empty >= 100 {
|
||||||
@@ -210,34 +210,34 @@ func ReadInput(ctx context.Context, reader io.Reader, options InputOptions) (*In
|
|||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
input.reader = bytes.NewReader(memory.Bytes())
|
source.reader = bytes.NewReader(memory.Bytes())
|
||||||
if input.file != nil {
|
if source.file != nil {
|
||||||
input.reader = input.file
|
source.reader = source.file
|
||||||
}
|
}
|
||||||
success = true
|
success = true
|
||||||
return input, nil
|
return source, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkOptions 检查取消状态及输入大小
|
// checkOptions 检查取消状态及输入大小
|
||||||
// 入参: ctx 取消上下文, options 输入选项
|
// 入参: ctx 取消上下文, options 输入选项
|
||||||
// 返回: error 取消或大小错误
|
// 返回: error 取消或大小错误
|
||||||
func (s *Input) checkOptions(ctx context.Context, options InputOptions) error {
|
func (s *Source) checkOptions(ctx context.Context, options SourceOptions) error {
|
||||||
if options.MaxSize < 0 || options.MaxSize > 0 && s.size > options.MaxSize {
|
if options.MaxSize < 0 || options.MaxSize > 0 && s.size > options.MaxSize {
|
||||||
return fmt.Errorf("input exceeds size limit")
|
return fmt.Errorf("source exceeds size limit")
|
||||||
}
|
}
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size 返回输入字节数,关闭后仍可查询
|
// Size 返回输入字节数,关闭后仍可查询
|
||||||
// 返回: int64 数据大小
|
// 返回: int64 数据大小
|
||||||
func (s *Input) Size() int64 {
|
func (s *Source) Size() int64 {
|
||||||
return s.size
|
return s.size
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAt 读取指定位置的数据,关闭后返回os.ErrClosed
|
// ReadAt 读取指定位置的数据,关闭后返回os.ErrClosed
|
||||||
// 入参: data 目标缓冲区, offset 字节偏移
|
// 入参: data 目标缓冲区, offset 字节偏移
|
||||||
// 返回: int 读取字节数, error 读取错误
|
// 返回: int 读取字节数, error 读取错误
|
||||||
func (s *Input) ReadAt(data []byte, offset int64) (int, error) {
|
func (s *Source) ReadAt(data []byte, offset int64) (int, error) {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
defer s.mu.RUnlock()
|
defer s.mu.RUnlock()
|
||||||
if s.reader == nil {
|
if s.reader == nil {
|
||||||
@@ -248,7 +248,7 @@ func (s *Input) ReadAt(data []byte, offset int64) (int, error) {
|
|||||||
|
|
||||||
// Close 释放自有文件和缓存,等待正在进行的读取结束,可重复调用
|
// Close 释放自有文件和缓存,等待正在进行的读取结束,可重复调用
|
||||||
// 返回: error 文件关闭或临时文件删除错误
|
// 返回: error 文件关闭或临时文件删除错误
|
||||||
func (s *Input) Close() error {
|
func (s *Source) Close() error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
s.reader = nil
|
s.reader = nil
|
||||||
@@ -266,18 +266,18 @@ func (s *Input) Close() error {
|
|||||||
|
|
||||||
// NewReader 从统一输入源创建OFD阅读器,不接管输入源生命周期
|
// NewReader 从统一输入源创建OFD阅读器,不接管输入源生命周期
|
||||||
// 阅读器及其派生编辑器使用结束后,调用方再关闭输入源
|
// 阅读器及其派生编辑器使用结束后,调用方再关闭输入源
|
||||||
// 入参: input 输入源, options 阅读选项
|
// 入参: source 输入源, options 阅读选项
|
||||||
// 返回: *Reader 阅读器实例, error 错误信息
|
// 返回: *Reader 阅读器实例, error 错误信息
|
||||||
func NewReader(input *Input, options ...ReaderOption) (*Reader, error) {
|
func NewReader(source *Source, options ...ReaderOption) (*Reader, error) {
|
||||||
if input == nil {
|
if source == nil {
|
||||||
return nil, fmt.Errorf("missing input")
|
return nil, fmt.Errorf("missing source")
|
||||||
}
|
}
|
||||||
zr, err := zip.NewReader(input, input.Size())
|
zr, err := zip.NewReader(source, source.Size())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader := &Reader{
|
reader := &Reader{
|
||||||
Path: input.path,
|
Path: source.path,
|
||||||
Zip: zr,
|
Zip: zr,
|
||||||
}
|
}
|
||||||
if err := reader.open(options); err != nil {
|
if err := reader.open(options); err != nil {
|
||||||
|
|||||||
+6
-6
@@ -27,8 +27,8 @@ import (
|
|||||||
|
|
||||||
// ArchiveFile 描述已生成的归档文件,不关闭调用方提供的源读取器
|
// ArchiveFile 描述已生成的归档文件,不关闭调用方提供的源读取器
|
||||||
type ArchiveFile struct {
|
type ArchiveFile struct {
|
||||||
Name string
|
Name string
|
||||||
Input *Input
|
Source *Source
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArchiveOptions 设置ZIP封装,压缩不重新编码归档内已生成的文档
|
// ArchiveOptions 设置ZIP封装,压缩不重新编码归档内已生成的文档
|
||||||
@@ -46,7 +46,7 @@ func WriteArchive(ctx context.Context, writer io.Writer, files []ArchiveFile, op
|
|||||||
}
|
}
|
||||||
names := map[string]bool{}
|
names := map[string]bool{}
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if !fs.ValidPath(file.Name) || file.Name == "." || strings.Contains(file.Name, "\\") || names[file.Name] || file.Input == nil {
|
if !fs.ValidPath(file.Name) || file.Name == "." || strings.Contains(file.Name, "\\") || names[file.Name] || file.Source == nil {
|
||||||
return 0, fmt.Errorf("invalid archive file %q", file.Name)
|
return 0, fmt.Errorf("invalid archive file %q", file.Name)
|
||||||
}
|
}
|
||||||
names[file.Name] = true
|
names[file.Name] = true
|
||||||
@@ -76,15 +76,15 @@ func WriteArchive(ctx context.Context, writer io.Writer, files []ArchiveFile, op
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
input := convertReader{ctx: ctx, input: file.Input}
|
source := convertReader{ctx: ctx, source: file.Source}
|
||||||
if buffer == nil {
|
if buffer == nil {
|
||||||
buffer = make([]byte, 32<<10)
|
buffer = make([]byte, 32<<10)
|
||||||
}
|
}
|
||||||
written, err := io.CopyBuffer(entry, io.NewSectionReader(input, 0, file.Input.Size()), buffer)
|
written, err := io.CopyBuffer(entry, io.NewSectionReader(source, 0, file.Source.Size()), buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
if written != file.Input.Size() {
|
if written != file.Source.Size() {
|
||||||
return count, io.ErrUnexpectedEOF
|
return count, io.ErrUnexpectedEOF
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-15
@@ -84,8 +84,8 @@ type ConvertReport struct {
|
|||||||
|
|
||||||
// convertReader 将取消上下文传递到随机读取
|
// convertReader 将取消上下文传递到随机读取
|
||||||
type convertReader struct {
|
type convertReader struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
input io.ReaderAt
|
source io.ReaderAt
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertWriter 将取消上下文传递到写入并统计实际字节数
|
// convertWriter 将取消上下文传递到写入并统计实际字节数
|
||||||
@@ -113,9 +113,9 @@ func OutputFormats() []OutputFormat {
|
|||||||
// 原始模式完整OFD另存保持源字节;选页和跨格式输出重新生成文档,压缩仅作用于输出副本
|
// 原始模式完整OFD另存保持源字节;选页和跨格式输出重新生成文档,压缩仅作用于输出副本
|
||||||
// 输入按需随机读取,输出分块写出;解析对象及后端可能缓存资源,不保证恒定内存
|
// 输入按需随机读取,输出分块写出;解析对象及后端可能缓存资源,不保证恒定内存
|
||||||
// 出错时报告保留已有诊断,调用方应丢弃未完成输出;只有返回nil才表示转换成功
|
// 出错时报告保留已有诊断,调用方应丢弃未完成输出;只有返回nil才表示转换成功
|
||||||
// 入参: ctx 取消上下文, input 输入源, output 输出流, options 转换选项
|
// 入参: ctx 取消上下文, source 输入源, output 输出流, options 转换选项
|
||||||
// 返回: ConvertReport 转换报告, error 错误信息
|
// 返回: ConvertReport 转换报告, error 错误信息
|
||||||
func Convert(ctx context.Context, input *Input, output io.Writer, options ConvertOptions) (report ConvertReport, err error) {
|
func Convert(ctx context.Context, source *Source, output io.Writer, options ConvertOptions) (report ConvertReport, err error) {
|
||||||
if options.Pool != nil {
|
if options.Pool != nil {
|
||||||
if err = options.Pool.acquire(ctx, false, 0); err != nil {
|
if err = options.Pool.acquire(ctx, false, 0); err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
@@ -174,14 +174,14 @@ func Convert(ctx context.Context, input *Input, output io.Writer, options Conver
|
|||||||
if err = progress("open", 0, 0); err != nil {
|
if err = progress("open", 0, 0); err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
if input == nil || input.Size() <= 0 {
|
if source == nil || source.Size() <= 0 {
|
||||||
return report, fmt.Errorf("empty document input")
|
return report, fmt.Errorf("empty document source")
|
||||||
}
|
}
|
||||||
size := input.Size()
|
size := source.Size()
|
||||||
operationInput := &Input{reader: convertReader{ctx: ctx, input: input}, size: size}
|
operationSource := &Source{reader: convertReader{ctx: ctx, source: source}, size: size}
|
||||||
report.Input = strings.ToLower(strings.TrimSpace(options.Input))
|
report.Input = strings.ToLower(strings.TrimSpace(options.Input))
|
||||||
if report.Input == "" {
|
if report.Input == "" {
|
||||||
report.Input, err = DetectFormat(operationInput)
|
report.Input, err = DetectFormat(operationSource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,7 @@ func Convert(ctx context.Context, input *Input, output io.Writer, options Conver
|
|||||||
return report, fmt.Errorf("missing output writer")
|
return report, fmt.Errorf("missing output writer")
|
||||||
}
|
}
|
||||||
if report.Input == "pdf" && format == "pdf" && options.Compression.Mode != CompressionUnchanged && options.Pages == nil && strings.TrimSpace(options.PageRange) == "" {
|
if report.Input == "pdf" && format == "pdf" && options.Compression.Mode != CompressionUnchanged && options.Pages == nil && strings.TrimSpace(options.PageRange) == "" {
|
||||||
pdfReader, openErr := pdfgo.NewReaderWithOptions(operationInput, size, pdfgo.ReaderOptions{Password: options.PDF.Password, PasswordUTF8: options.PDF.PasswordUTF8})
|
pdfReader, openErr := pdfgo.NewReaderWithOptions(operationSource, size, pdfgo.ReaderOptions{Password: options.PDF.Password, PasswordUTF8: options.PDF.PasswordUTF8})
|
||||||
if openErr != nil {
|
if openErr != nil {
|
||||||
return report, openErr
|
return report, openErr
|
||||||
}
|
}
|
||||||
@@ -234,13 +234,13 @@ func Convert(ctx context.Context, input *Input, output io.Writer, options Conver
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
editor, report.PDF, err = ImportPDF(ctx, operationInput, pdfOptions)
|
editor, report.PDF, err = ImportPDF(ctx, operationSource, pdfOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
count = editor.PageCount()
|
count = editor.PageCount()
|
||||||
case "ofd":
|
case "ofd":
|
||||||
reader, err = NewReader(operationInput, options.ReaderOptions...)
|
reader, err = NewReader(operationSource, options.ReaderOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
@@ -267,7 +267,7 @@ func Convert(ctx context.Context, input *Input, output io.Writer, options Conver
|
|||||||
if err = progress("write", 0, 0); err != nil {
|
if err = progress("write", 0, 0); err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
_, err = io.Copy(writer, io.NewSectionReader(operationInput, 0, size))
|
_, err = io.Copy(writer, io.NewSectionReader(operationSource, 0, size))
|
||||||
report.Unchanged = err == nil
|
report.Unchanged = err == nil
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@ func Convert(ctx context.Context, input *Input, output io.Writer, options Conver
|
|||||||
if err = progress("write", 0, 0); err != nil {
|
if err = progress("write", 0, 0); err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
_, err = io.Copy(writer, io.NewSectionReader(operationInput, 0, size))
|
_, err = io.Copy(writer, io.NewSectionReader(operationSource, 0, size))
|
||||||
report.Unchanged = err == nil
|
report.Unchanged = err == nil
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
@@ -370,7 +370,7 @@ func (r convertReader) ReadAt(data []byte, offset int64) (int, error) {
|
|||||||
if err := r.ctx.Err(); err != nil {
|
if err := r.ctx.Err(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
n, err := r.input.ReadAt(data, offset)
|
n, err := r.source.ReadAt(data, offset)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = r.ctx.Err()
|
err = r.ctx.Err()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (e *Editor) writeEncrypted(writer io.Writer) (int64, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
defer clear(plaintext.Bytes())
|
defer clear(plaintext.Bytes())
|
||||||
r, err := NewReader(&Input{reader: bytes.NewReader(plaintext.Bytes()), size: int64(plaintext.Len())})
|
r, err := NewReader(&Source{reader: bytes.NewReader(plaintext.Bytes()), size: int64(plaintext.Len())})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ type encryptionEntry struct {
|
|||||||
// 入参: data 明文OFD包, options 加密策略
|
// 入参: data 明文OFD包, options 加密策略
|
||||||
// 返回: []byte 加密OFD包, error 错误信息
|
// 返回: []byte 加密OFD包, error 错误信息
|
||||||
func EncryptPackage(data []byte, options EncryptionOptions) ([]byte, error) {
|
func EncryptPackage(data []byte, options EncryptionOptions) ([]byte, error) {
|
||||||
r, err := NewReader(&Input{reader: bytes.NewReader(data), size: int64(len(data))})
|
r, err := NewReader(&Source{reader: bytes.NewReader(data), size: int64(len(data))})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -24,16 +24,16 @@ import (
|
|||||||
|
|
||||||
// DetectFormat 按文件内容识别PDF或OFD,不读取压缩内容或关闭输入
|
// DetectFormat 按文件内容识别PDF或OFD,不读取压缩内容或关闭输入
|
||||||
// 识别结果不代表文档完整有效,仍需通过对应阅读器解析
|
// 识别结果不代表文档完整有效,仍需通过对应阅读器解析
|
||||||
// 入参: input 输入源
|
// 入参: source 输入源
|
||||||
// 返回: string 格式标识pdf或ofd, error 读取错误或不支持的格式
|
// 返回: string 格式标识pdf或ofd, error 读取错误或不支持的格式
|
||||||
func DetectFormat(input *Input) (string, error) {
|
func DetectFormat(source *Source) (string, error) {
|
||||||
if input == nil || input.Size() <= 0 {
|
if source == nil || source.Size() <= 0 {
|
||||||
return "", fmt.Errorf("empty document input")
|
return "", fmt.Errorf("empty document source")
|
||||||
}
|
}
|
||||||
size := input.Size()
|
size := source.Size()
|
||||||
var header [1024]byte
|
var header [1024]byte
|
||||||
data := header[:min(size, int64(len(header)))]
|
data := header[:min(size, int64(len(header)))]
|
||||||
n, err := input.ReadAt(data, 0)
|
n, err := source.ReadAt(data, 0)
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ func DetectFormat(input *Input) (string, error) {
|
|||||||
if bytes.HasPrefix(data, []byte("%PDF-")) {
|
if bytes.HasPrefix(data, []byte("%PDF-")) {
|
||||||
return "pdf", nil
|
return "pdf", nil
|
||||||
}
|
}
|
||||||
archive, err := zip.NewReader(input, size)
|
archive, err := zip.NewReader(source, size)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
reader := &Reader{Zip: archive}
|
reader := &Reader{Zip: archive}
|
||||||
if err := reader.indexPackage(); err != nil {
|
if err := reader.indexPackage(); err != nil {
|
||||||
|
|||||||
+8
-8
@@ -204,11 +204,11 @@ func (o pdfObjectOrigin) merge(other pdfObjectOrigin) pdfObjectOrigin {
|
|||||||
|
|
||||||
// ImportPDF 将PDF内容转换为独立OFD编辑文档,失败时不返回部分结果
|
// ImportPDF 将PDF内容转换为独立OFD编辑文档,失败时不返回部分结果
|
||||||
// 返回的编辑文档独立于输入源,函数返回后可关闭输入源
|
// 返回的编辑文档独立于输入源,函数返回后可关闭输入源
|
||||||
// 入参: ctx 取消上下文, input 输入源, options 转换选项
|
// 入参: ctx 取消上下文, source 输入源, options 转换选项
|
||||||
// 返回: *Editor 编辑文档, PDFImportReport 转换统计, error 错误信息
|
// 返回: *Editor 编辑文档, PDFImportReport 转换统计, error 错误信息
|
||||||
func ImportPDF(ctx context.Context, input *Input, options PDFImportOptions) (*Editor, PDFImportReport, error) {
|
func ImportPDF(ctx context.Context, source *Source, options PDFImportOptions) (*Editor, PDFImportReport, error) {
|
||||||
if input == nil {
|
if source == nil {
|
||||||
return nil, PDFImportReport{}, fmt.Errorf("missing input")
|
return nil, PDFImportReport{}, fmt.Errorf("missing source")
|
||||||
}
|
}
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, PDFImportReport{}, err
|
return nil, PDFImportReport{}, err
|
||||||
@@ -245,7 +245,7 @@ func ImportPDF(ctx context.Context, input *Input, options PDFImportOptions) (*Ed
|
|||||||
readWarning = func(diagnostic pdfgo.Diagnostic) { diagnostics = append(diagnostics, diagnostic) }
|
readWarning = func(diagnostic pdfgo.Diagnostic) { diagnostics = append(diagnostics, diagnostic) }
|
||||||
readOptions.Warning = func(diagnostic pdfgo.Diagnostic) { readWarning(diagnostic) }
|
readOptions.Warning = func(diagnostic pdfgo.Diagnostic) { readWarning(diagnostic) }
|
||||||
}
|
}
|
||||||
reader, err := pdfgo.NewReaderWithOptions(convertReader{ctx: ctx, input: input}, input.Size(), readOptions)
|
reader, err := pdfgo.NewReaderWithOptions(convertReader{ctx: ctx, source: source}, source.Size(), readOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, PDFImportReport{}, err
|
return nil, PDFImportReport{}, err
|
||||||
}
|
}
|
||||||
@@ -374,10 +374,10 @@ func ImportPDF(ctx context.Context, input *Input, options PDFImportOptions) (*Ed
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConvertPDF 将PDF转换并写入OFD,转换阶段失败时不写入目标
|
// ConvertPDF 将PDF转换并写入OFD,转换阶段失败时不写入目标
|
||||||
// 入参: ctx 取消上下文, input 输入源, output OFD输出, options 转换选项
|
// 入参: ctx 取消上下文, source 输入源, output OFD输出, options 转换选项
|
||||||
// 返回: PDFImportReport 转换统计, error 错误信息
|
// 返回: PDFImportReport 转换统计, error 错误信息
|
||||||
func ConvertPDF(ctx context.Context, input *Input, output io.Writer, options PDFImportOptions) (PDFImportReport, error) {
|
func ConvertPDF(ctx context.Context, source *Source, output io.Writer, options PDFImportOptions) (PDFImportReport, error) {
|
||||||
editor, report, err := ImportPDF(ctx, input, options)
|
editor, report, err := ImportPDF(ctx, source, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return PDFImportReport{}, err
|
return PDFImportReport{}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ func (c *semanticCompiler) drawStampContent(stamp Stamp) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if stamp.Type == "ofd" {
|
if stamp.Type == "ofd" {
|
||||||
reader, err := NewReader(&Input{reader: bytes.NewReader(stamp.Data), size: int64(len(stamp.Data))})
|
reader, err := NewReader(&Source{reader: bytes.NewReader(stamp.Data), size: int64(len(stamp.Data))})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reader, err := NewReader(&Input{reader: bytes.NewReader(s.Data), size: int64(len(s.Data))})
|
reader, err := NewReader(&Source{reader: bytes.NewReader(s.Data), size: int64(len(s.Data))})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
doc, err := reader.DocContext(pageContext)
|
doc, err := reader.DocContext(pageContext)
|
||||||
@@ -114,7 +114,7 @@ func (r *Renderer) renderOFDStampImage(data []byte) image.Image {
|
|||||||
r.renderError = err
|
r.renderError = err
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
reader, err := NewReader(&Input{reader: bytes.NewReader(data), size: int64(len(data))})
|
reader, err := NewReader(&Source{reader: bytes.NewReader(data), size: int64(len(data))})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.renderError = err
|
r.renderError = err
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -236,10 +236,10 @@ func WithSignatureVerifyTime(t time.Time) SignatureVerifyOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VerifySignatures 验证输入源中的OFD签名,不接管输入源生命周期
|
// VerifySignatures 验证输入源中的OFD签名,不接管输入源生命周期
|
||||||
// 入参: input 输入源, opts 签名验证选项
|
// 入参: source 输入源, opts 签名验证选项
|
||||||
// 返回: []SignatureVerifyReport 签名验证报告, error 错误信息
|
// 返回: []SignatureVerifyReport 签名验证报告, error 错误信息
|
||||||
func VerifySignatures(input *Input, opts ...SignatureVerifyOption) ([]SignatureVerifyReport, error) {
|
func VerifySignatures(source *Source, opts ...SignatureVerifyOption) ([]SignatureVerifyReport, error) {
|
||||||
reader, err := NewReader(input)
|
reader, err := NewReader(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -84,7 +84,7 @@ type signatureIDSequence uint64
|
|||||||
// 入参: data 最终包字节, options 签署选项
|
// 入参: data 最终包字节, options 签署选项
|
||||||
// 返回: []byte 签署后的完整包, error 错误信息
|
// 返回: []byte 签署后的完整包, error 错误信息
|
||||||
func SignPackage(data []byte, options SignatureWriteOptions) ([]byte, error) {
|
func SignPackage(data []byte, options SignatureWriteOptions) ([]byte, error) {
|
||||||
r, err := NewReader(&Input{reader: bytes.NewReader(data), size: int64(len(data))}, options.ReaderOptions...)
|
r, err := NewReader(&Source{reader: bytes.NewReader(data), size: int64(len(data))}, options.ReaderOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ func SignEditorTo(writer io.Writer, editor *Editor, options SignatureWriteOption
|
|||||||
if _, err := editor.writePlaintext(&plain); err != nil {
|
if _, err := editor.writePlaintext(&plain); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
r, err := NewReader(&Input{reader: bytes.NewReader(plain.Bytes()), size: int64(plain.Len())})
|
r, err := NewReader(&Source{reader: bytes.NewReader(plain.Bytes()), size: int64(plain.Len())})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ func signatureWriteOutput(r *Reader, options SignatureWriteOptions) ([]byte, err
|
|||||||
if encryption != nil {
|
if encryption != nil {
|
||||||
defer clear(data)
|
defer clear(data)
|
||||||
if options.progress != nil {
|
if options.progress != nil {
|
||||||
signed, err := NewReader(&Input{reader: bytes.NewReader(data), size: int64(len(data))})
|
signed, err := NewReader(&Source{reader: bytes.NewReader(data), size: int64(len(data))})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -434,7 +434,7 @@ func signatureWritePackage(parts map[string][]byte, options SignatureWriteOption
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
check, err := NewReader(&Input{reader: bytes.NewReader(output), size: int64(len(output))})
|
check, err := NewReader(&Source{reader: bytes.NewReader(output), size: int64(len(output))})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user