mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-25 13:48:53 +08:00
70 lines
11 KiB
Go
70 lines
11 KiB
Go
//
|
|
// Copyright 2020 FoxyUtils ehf. All rights reserved.
|
|
//
|
|
// This is a commercial product and requires a license to operate.
|
|
// A trial license can be obtained at https://unidoc.io
|
|
//
|
|
// DO NOT EDIT: generated by unitwist Go source code obfuscator.
|
|
//
|
|
// Use of this source code is governed by the UniDoc End User License Agreement
|
|
// terms that can be accessed at https://unidoc.io/eula/
|
|
|
|
package zippkg ;import (_d "archive/zip";_f "bytes";_gg "encoding/xml";_e "fmt";_bg "github.com/unidoc/unioffice";_ff "github.com/unidoc/unioffice/algo";_cg "github.com/unidoc/unioffice/common/tempstorage";_cb "github.com/unidoc/unioffice/schema/soo/pkg/relationships";_c "io";_eg "path";_b "sort";_a "strings";_da "time";);type Target struct{Path string ;Typ string ;Ifc interface{};Index uint32 ;};
|
|
|
|
// RelationsPathFor returns the relations path for a given filename.
|
|
func RelationsPathFor (path string )string {_aae :=_a .Split (path ,"\u002f");_ge :=_a .Join (_aae [0:len (_aae )-1],"\u002f");_ab :=_aae [len (_aae )-1];_ge +="\u002f_\u0072\u0065\u006c\u0073\u002f";_ab +="\u002e\u0072\u0065l\u0073";return _ge +_ab ;};
|
|
|
|
// AddTarget allows documents to register decode targets. Path is a path that
|
|
// will be found in the zip file and ifc is an XML element that the file will be
|
|
// unmarshaled to. filePath is the absolute path to the target, ifc is the
|
|
// object to decode into, sourceFileType is the type of file that the reference
|
|
// was discovered in, and index is the index of the source file type.
|
|
func (_gf *DecodeMap )AddTarget (filePath string ,ifc interface{},sourceFileType string ,idx uint32 )bool {if _gf ._cgf ==nil {_gf ._cgf =make (map[string ]Target );_gf ._bf =make (map[*_cb .Relationships ]string );_gf ._gd =make (map[string ]struct{});_gf ._fg =make (map[string ]int );};_ba :=_eg .Clean (filePath );if _ ,_ef :=_gf ._gd [_ba ];_ef {return false ;};_gf ._gd [_ba ]=struct{}{};_gf ._cgf [_ba ]=Target {Path :filePath ,Typ :sourceFileType ,Ifc :ifc ,Index :idx };return true ;};
|
|
|
|
// Decode loops decoding targets registered with AddTarget and calling th
|
|
func (_bff *DecodeMap )Decode (files []*_d .File )error {_dcb :=1;for _dcb > 0{for len (_bff ._ed )> 0{_dcg :=_bff ._ed [0];_bff ._ed =_bff ._ed [1:];_cbf :=_dcg .Ifc .(*_cb .Relationships );for _ ,_ga :=range _cbf .Relationship {_ffec ,_ :=_bff ._bf [_cbf ];_bff ._dc (_bff ,_ffec +_ga .TargetAttr ,_ga .TypeAttr ,files ,_ga ,_dcg );};};for _ea ,_ddd :=range files {if _ddd ==nil {continue ;};if _ced ,_efa :=_bff ._cgf [_ddd .Name ];_efa {delete (_bff ._cgf ,_ddd .Name );if _gda :=Decode (_ddd ,_ced .Ifc );_gda !=nil {return _gda ;};files [_ea ]=nil ;if _fbb ,_egd :=_ced .Ifc .(*_cb .Relationships );_egd {_bff ._ed =append (_bff ._ed ,_ced );_ac ,_ :=_eg .Split (_eg .Clean (_ddd .Name +"\u002f\u002e\u002e\u002f"));_bff ._bf [_fbb ]=_ac ;_dcb ++;};};};_dcb --;};return nil ;};
|
|
|
|
// Decode unmarshals the content of a *zip.File as XML to a given destination.
|
|
func Decode (f *_d .File ,dest interface{})error {_dab ,_gfd :=f .Open ();if _gfd !=nil {return _e .Errorf ("e\u0072r\u006f\u0072\u0020\u0072\u0065\u0061\u0064\u0069n\u0067\u0020\u0025\u0073: \u0025\u0073",f .Name ,_gfd );};defer _dab .Close ();_fga :=_gg .NewDecoder (_dab );if _baf :=_fga .Decode (dest );_baf !=nil {return _e .Errorf ("e\u0072\u0072\u006f\u0072 d\u0065c\u006f\u0064\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",f .Name ,_baf );};if _be ,_bec :=dest .(*_cb .Relationships );_bec {for _gfc ,_bc :=range _be .Relationship {switch _bc .TypeAttr {case _bg .OfficeDocumentTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .OfficeDocumentType ;case _bg .StylesTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .StylesType ;case _bg .ThemeTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .ThemeType ;case _bg .ControlTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .ControlType ;case _bg .SettingsTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .SettingsType ;case _bg .ImageTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .ImageType ;case _bg .CommentsTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .CommentsType ;case _bg .ThumbnailTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .ThumbnailType ;case _bg .DrawingTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .DrawingType ;case _bg .ChartTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .ChartType ;case _bg .ExtendedPropertiesTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .ExtendedPropertiesType ;case _bg .CustomXMLTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .CustomXMLType ;case _bg .WorksheetTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .WorksheetType ;case _bg .SharedStringsTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .SharedStringsType ;case _bg .TableTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .TableType ;case _bg .HeaderTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .HeaderType ;case _bg .FooterTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .FooterType ;case _bg .NumberingTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .NumberingType ;case _bg .FontTableTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .FontTableType ;case _bg .WebSettingsTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .WebSettingsType ;case _bg .FootNotesTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .FootNotesType ;case _bg .EndNotesTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .EndNotesType ;case _bg .SlideTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .SlideType ;case _bg .VMLDrawingTypeStrict :_be .Relationship [_gfc ].TypeAttr =_bg .VMLDrawingType ;};};_b .Slice (_be .Relationship ,func (_fac ,_fc int )bool {_acf :=_be .Relationship [_fac ];_gac :=_be .Relationship [_fc ];return _ff .NaturalLess (_acf .IdAttr ,_gac .IdAttr );});};return nil ;};
|
|
|
|
// DecodeMap is used to walk a tree of relationships, decoding files and passing
|
|
// control back to the document.
|
|
type DecodeMap struct{_cgf map[string ]Target ;_bf map[*_cb .Relationships ]string ;_ed []Target ;_dc OnNewRelationshipFunc ;_gd map[string ]struct{};_fg map[string ]int ;};
|
|
|
|
// SelfClosingWriter wraps a writer and replaces XML tags of the
|
|
// type <foo></foo> with <foo/>
|
|
type SelfClosingWriter struct{W _c .Writer ;};var _dcba =[]byte {'\r','\n'};func (_egf *DecodeMap )RecordIndex (path string ,idx int ){_egf ._fg [path ]=idx };const XMLHeader ="\u003c\u003f\u0078\u006d\u006c\u0020\u0076e\u0072\u0073\u0069o\u006e\u003d\u00221\u002e\u0030\"\u0020\u0065\u006e\u0063\u006f\u0064i\u006eg=\u0022\u0055\u0054\u0046\u002d\u0038\u0022\u0020\u0073\u0074\u0061\u006e\u0064\u0061\u006c\u006f\u006e\u0065\u003d\u0022\u0079\u0065\u0073\u0022\u003f\u003e"+"\u000a";func MarshalXMLByTypeIndex (z *_d .Writer ,dt _bg .DocType ,typ string ,idx int ,v interface{})error {_add :=_bg .AbsoluteFilename (dt ,typ ,idx );return MarshalXML (z ,_add ,v );};
|
|
|
|
// AddFileFromDisk reads a file from internal storage and adds it at a given path to a zip file.
|
|
// TODO: Rename to AddFileFromStorage in next major version release (v2).
|
|
// NOTE: If disk storage cannot be used, memory storage can be used instead by calling memstore.SetAsStorage().
|
|
func AddFileFromDisk (z *_d .Writer ,zipPath ,storagePath string )error {_aed ,_eb :=z .Create (zipPath );if _eb !=nil {return _e .Errorf ("e\u0072\u0072\u006f\u0072 c\u0072e\u0061\u0074\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",zipPath ,_eb );};_cf ,_eb :=_cg .Open (storagePath );if _eb !=nil {return _e .Errorf ("e\u0072r\u006f\u0072\u0020\u006f\u0070\u0065\u006e\u0069n\u0067\u0020\u0025\u0073: \u0025\u0073",storagePath ,_eb );};defer _cf .Close ();_ ,_eb =_c .Copy (_aed ,_cf );return _eb ;};
|
|
|
|
// MarshalXML creates a file inside of a zip and marshals an object as xml, prefixing it
|
|
// with a standard XML header.
|
|
func MarshalXML (z *_d .Writer ,filename string ,v interface{})error {_aag :=&_d .FileHeader {};_aag .Method =_d .Deflate ;_aag .Name =filename ;_aag .SetModTime (_da .Now ());_acfd ,_bcd :=z .CreateHeader (_aag );if _bcd !=nil {return _e .Errorf ("\u0063\u0072\u0065\u0061ti\u006e\u0067\u0020\u0025\u0073\u0020\u0069\u006e\u0020\u007a\u0069\u0070\u003a\u0020%\u0073",filename ,_bcd );};_ ,_bcd =_acfd .Write ([]byte (XMLHeader ));if _bcd !=nil {return _e .Errorf ("\u0063\u0072e\u0061\u0074\u0069\u006e\u0067\u0020\u0078\u006d\u006c\u0020\u0068\u0065\u0061\u0064\u0065\u0072\u0020\u0074\u006f\u0020\u0025\u0073: \u0025\u0073",filename ,_bcd );};if _bcd =_gg .NewEncoder (SelfClosingWriter {_acfd }).Encode (v );_bcd !=nil {return _e .Errorf ("\u006d\u0061\u0072\u0073\u0068\u0061\u006c\u0069\u006e\u0067\u0020\u0025s\u003a\u0020\u0025\u0073",filename ,_bcd );};_ ,_bcd =_acfd .Write (_dcba );return _bcd ;};
|
|
|
|
// OnNewRelationshipFunc is called when a new relationship has been discovered.
|
|
//
|
|
// target is a resolved path that takes into account the location of the
|
|
// relationships file source and should be the path in the zip file.
|
|
//
|
|
// files are passed so non-XML files that can't be handled by AddTarget can be
|
|
// decoded directly (e.g. images)
|
|
//
|
|
// rel is the actual relationship so its target can be modified if the source
|
|
// target doesn't match where unioffice will write the file (e.g. read in
|
|
// 'xl/worksheets/MyWorksheet.xml' and we'll write out
|
|
// 'xl/worksheets/sheet1.xml')
|
|
type OnNewRelationshipFunc func (_fd *DecodeMap ,_fa ,_fb string ,_aa []*_d .File ,_ca *_cb .Relationship ,_cbb Target )error ;
|
|
|
|
// SetOnNewRelationshipFunc sets the function to be called when a new
|
|
// relationship has been discovered.
|
|
func (_cc *DecodeMap )SetOnNewRelationshipFunc (fn OnNewRelationshipFunc ){_cc ._dc =fn };func (_ffe *DecodeMap )IndexFor (path string )int {return _ffe ._fg [path ]};func MarshalXMLByType (z *_d .Writer ,dt _bg .DocType ,typ string ,v interface{})error {_gacf :=_bg .AbsoluteFilename (dt ,typ ,0);return MarshalXML (z ,_gacf ,v );};var _gfe =[]byte {'/','>'};
|
|
|
|
// ExtractToDiskTmp extracts a zip file to a temporary file in a given path,
|
|
// returning the name of the file.
|
|
func ExtractToDiskTmp (f *_d .File ,path string )(string ,error ){_af ,_fab :=_cg .TempFile (path ,"\u007a\u007a");if _fab !=nil {return "",_fab ;};defer _af .Close ();_ad ,_fab :=f .Open ();if _fab !=nil {return "",_fab ;};defer _ad .Close ();_ ,_fab =_c .Copy (_af ,_ad );if _fab !=nil {return "",_fab ;};return _af .Name (),nil ;};func (_cbfc SelfClosingWriter )Write (b []byte )(int ,error ){_dg :=0;_fef :=0;for _ag :=0;_ag < len (b )-2;_ag ++{if b [_ag ]=='>'&&b [_ag +1]=='<'&&b [_ag +2]=='/'{_aee :=[]byte {};_afe :=_ag ;for _cec :=_ag ;_cec >=0;_cec --{if b [_cec ]==' '{_afe =_cec ;}else if b [_cec ]=='<'{_aee =b [_cec +1:_afe ];break ;};};_addf :=[]byte {};for _fda :=_ag +3;_fda < len (b );_fda ++{if b [_fda ]=='>'{_addf =b [_ag +3:_fda ];break ;};};if !_f .Equal (_aee ,_addf ){continue ;};_afa ,_dda :=_cbfc .W .Write (b [_dg :_ag ]);if _dda !=nil {return _fef +_afa ,_dda ;};_fef +=_afa ;_ ,_dda =_cbfc .W .Write (_gfe );if _dda !=nil {return _fef ,_dda ;};_fef +=3;for _db :=_ag +2;_db < len (b )&&b [_db ]!='>';_db ++{_fef ++;_dg =_db +2;_ag =_dg ;};};};_gdad ,_beg :=_cbfc .W .Write (b [_dg :]);return _gdad +_fef ,_beg ;};
|
|
|
|
// AddFileFromBytes takes a byte array and adds it at a given path to a zip file.
|
|
func AddFileFromBytes (z *_d .Writer ,zipPath string ,data []byte )error {_fe ,_fgd :=z .Create (zipPath );if _fgd !=nil {return _e .Errorf ("e\u0072\u0072\u006f\u0072 c\u0072e\u0061\u0074\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",zipPath ,_fgd );};_ ,_fgd =_c .Copy (_fe ,_f .NewReader (data ));return _fgd ;}; |