mirror of
https://github.com/unidoc/unioffice.git
synced 2025-05-01 13:48:55 +08:00

Decoding was getting fairly complicated, it seems cleaner to have something handle the relationships file and traversal and the document just be notified via callback when new files have been found.
69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
// Copyright 2017 Baliance. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by the terms of the Affero GNU General
|
|
// Public License version 3.0 as published by the Free Software Foundation and
|
|
// appearing in the file LICENSE included in the packaging of this file. A
|
|
// commercial license can be purchased by contacting sales@baliance.com.
|
|
|
|
package spreadsheet
|
|
|
|
import (
|
|
"archive/zip"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
|
|
"baliance.com/gooxml/zippkg"
|
|
)
|
|
|
|
// Read reads a workbook from an io.Reader(.xlsx).
|
|
func Read(r io.ReaderAt, size int64) (*Workbook, error) {
|
|
wb := New()
|
|
td, err := ioutil.TempDir("", "gooxml-xlsx")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
wb.TmpPath = td
|
|
|
|
zr, err := zip.NewReader(r, size)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parsing zip: %s", err)
|
|
}
|
|
|
|
files := []*zip.File{}
|
|
files = append(files, zr.File...)
|
|
decMap := zippkg.DecodeMap{}
|
|
decMap.SetOnNewRelationshipFunc(wb.onNewRelationship)
|
|
// we should discover all contents by starting with these two files
|
|
decMap.AddTarget(zippkg.ContentTypesFilename, wb.ContentTypes.X())
|
|
decMap.AddTarget(zippkg.BaseRelsFilename, wb.Rels.X())
|
|
decMap.Decode(files)
|
|
|
|
// etra files are things we don't handle yet, or files that happened to have
|
|
// been in the zip before. We just round-trip them.
|
|
for _, f := range files {
|
|
if f == nil {
|
|
continue
|
|
}
|
|
if err := wb.AddExtraFileFromZip(f); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return wb, nil
|
|
}
|
|
|
|
// Open opens and reads a workbook from a file (.xlsx).
|
|
func Open(filename string) (*Workbook, error) {
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error opening %s: %s", filename, err)
|
|
}
|
|
defer f.Close()
|
|
fi, err := os.Stat(filename)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error opening %s: %s", filename, err)
|
|
}
|
|
return Read(f, fi.Size())
|
|
}
|