-
Notifications
You must be signed in to change notification settings - Fork 4
/
write.go
160 lines (138 loc) · 3.88 KB
/
write.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package ods
import (
"archive/zip"
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"io"
"os"
)
// Write Updates the specified ODS file with the provided content
func Write(filepath string, ods ODS, files *zip.ReadCloser) error {
buf := new(bytes.Buffer)
err := WriteTo(buf, ods, files)
if err != nil {
return err
}
outputFile, err := os.Create(filepath)
if err != nil {
return fmt.Errorf("error creating output file: %v", err)
}
defer outputFile.Close()
// Write the new ODS file
_, err = outputFile.Write(buf.Bytes())
if err != nil {
return fmt.Errorf("error writing to file: %v", err)
}
return nil
}
// WriteTo Updates the specified io.Writer with the provided content
func WriteTo(writer io.Writer, ods ODS, files *zip.ReadCloser) error {
// Translate the content for XML compatibility
odsMarshal, err := translate(ods)
if err != nil {
return err
}
// Marshal the translated content into XML bytes
content, err := xml.Marshal(odsMarshal.Content)
if err != nil {
return err
}
meta, err := xml.Marshal(odsMarshal.Meta)
if err != nil {
return err
}
manifest, err := xml.Marshal(odsMarshal.Manifest)
if err != nil {
return err
}
settings, err := xml.Marshal(odsMarshal.Settings)
if err != nil {
return err
}
styles, err := xml.Marshal(odsMarshal.Styles)
if err != nil {
return err
}
// Create a new zip archive in memory
w := zip.NewWriter(writer)
// Add files to the archive, updating "content.xml" with the modified data
for _, file := range files.File {
// Create a new file entry in the archive
f, err := w.Create(file.Name)
if err != nil {
return fmt.Errorf("error creating file in archive: %v", err)
}
// Open the original file from the input ODS archive
rc, err := file.Open()
if err != nil {
return fmt.Errorf("error opening file in archive: %v", err)
}
defer rc.Close()
switch file.Name {
case "content.xml":
content = append([]byte(xml.Header), content...)
if _, err = f.Write(content); err != nil {
return fmt.Errorf("error writing content.xml: %v", err)
}
case "meta.xml":
meta = append([]byte(xml.Header), meta...)
if _, err = f.Write(meta); err != nil {
return fmt.Errorf("error writing meta.xml: %v", err)
}
case "manifest.rdf":
manifest = append([]byte(xml.Header), manifest...)
if _, err = f.Write(manifest); err != nil {
return fmt.Errorf("error writing manifest.rdf: %v", err)
}
case "settings.xml":
settings = append([]byte(xml.Header), settings...)
if _, err = f.Write(settings); err != nil {
return fmt.Errorf("error writing settings.xml: %v", err)
}
case "styles.xml":
styles = append([]byte(xml.Header), styles...)
if _, err = f.Write(styles); err != nil {
return fmt.Errorf("error writing styles.xml: %v", err)
}
case "mimetype":
if _, err = f.Write([]byte(ods.Mimetype)); err != nil {
return fmt.Errorf("error writing styles.xml: %v", err)
}
default:
// Copy all other files as-is
if _, err = io.Copy(f, rc); err != nil {
return fmt.Errorf("error writing file to archive: %v", err)
}
}
}
// Close the zip writer
if err := w.Close(); err != nil {
return fmt.Errorf("error closing archive: %v", err)
}
return nil
}
// Translates the ODS struct to a ODSMarshal struct for XML compatibility
func translate(data ODS) (odsMarshal, error) {
// Modify the ContentMarshal struct to ensure XML compatibility
for _, sheet := range data.Content.Body.Spreadsheet.Table {
for _, row := range sheet.TableRow {
for i := range row.TableCell {
cell := &row.TableCell[i]
cell.ValueType0 = cell.ValueType
}
}
}
// Marshal the contents to JSON, then unmarshal it back to a new struct
// to handle XML compatibility issues
jsonData, err := json.Marshal(data)
if err != nil {
return odsMarshal{}, err
}
var resp odsMarshal
if err = json.Unmarshal(jsonData, &resp); err != nil {
return odsMarshal{}, err
}
return resp, nil
}