-
Notifications
You must be signed in to change notification settings - Fork 3
/
package_file.go
138 lines (111 loc) · 3.63 KB
/
package_file.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright (c) 2017 Andrey Gayvoronsky <plandem@gmail.com>
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package ooxml
import (
"archive/zip"
"fmt"
)
//PackageFile is helper object that implements common functionality for any file of package. E.g. lazy loading, marking as updated.
type PackageFile struct {
//name of file
fileName string
//pointer to *zip.File or nil in case of a new file
zipFile *zip.File
//pointer to target-object to unmarshal content from a file
target interface{}
//pointer to source-object to marshal content into a file
source interface{}
//package owner of this file
pkg *PackageInfo
//flag that indicate new file or not
isNew bool
}
//NewPackageFile creates and returns package file that attached target via file f with source of information to save
func NewPackageFile(pkg *PackageInfo, f interface{}, target interface{}, source interface{}) *PackageFile {
if source == nil {
source = target
}
pkgFile := &PackageFile{
pkg: pkg,
target: target,
source: source,
isNew: true,
}
if f != nil {
switch ft := f.(type) {
case *zip.File:
pkgFile.fileName = ft.Name
pkgFile.zipFile = ft
pkgFile.isNew = false
case string:
pkgFile.fileName = ft
}
}
if len(pkgFile.fileName) == 0 {
panic("You must provide a file to use - zip.File for existing or filename for a new one.")
}
return pkgFile
}
//FileName returns name of file
func (pf *PackageFile) FileName() string {
return pf.fileName
}
//IsNew returns true if this file is a new file or false in other case
func (pf *PackageFile) IsNew() bool {
return pf.isNew
}
//MarkAsUpdated marks file as updated, so content will be replaced with source's content during packing document.
//Works only with new files or files that where fully loaded (via LoadIfRequired).
func (pf *PackageFile) MarkAsUpdated() {
if pf.zipFile == nil {
pf.pkg.Add(pf.fileName, pf.source)
}
}
//LoadIfRequired lazy loads whole content of file into target and call required callback if there is any
func (pf *PackageFile) LoadIfRequired(callback func()) {
if !pf.isNew && pf.zipFile != nil {
//first time request?
if err := UnmarshalZipFile(pf.zipFile, pf.target); err != nil {
panic(err)
}
pf.zipFile = nil
if callback != nil {
callback()
}
}
}
//ReadStream opens a zip file for manual reading as stream and return *StreamFileReader for it
//Files that were opened as stream can't be marked as updated via MarkAsUpdated and will be saved as is
//Files that were opened as stream must be manually closed via calling Close() to prevent memory leaks
func (pf *PackageFile) ReadStream() (*StreamFileReader, error) {
if pf.isNew {
return nil, fmt.Errorf("can't open a new file as stream")
}
if pf.zipFile == nil {
return nil, fmt.Errorf("can't open as stream file that was already fully loaded")
}
stream, err := NewStreamFileReader(pf.zipFile)
if err != nil {
return nil, err
}
return stream, nil
}
//WriteStream creates a zip file for manual writing as stream and return StreamFileWriter for it
//File can be created as stream only once, any further requests will return previously created stream
func (pf *PackageFile) WriteStream(memory bool, finalizer StreamFileWriterFinalizer) (*StreamFileWriter, error) {
if !pf.isNew {
return nil, fmt.Errorf("can't overwrite already existing file")
}
//is stream already created, then return it
if s, ok := pf.source.(*StreamFileWriter); ok {
return s, nil
}
stream, err := NewStreamFileWriter(pf.fileName, memory, finalizer)
if err != nil {
return nil, err
}
pf.source = stream
pf.pkg.Add(pf.fileName, pf.source)
return stream, nil
}