unioffice/zippkg/zippkg.go

70 lines
11 KiB
Go
Raw Normal View History

2020-08-23 14:15:53 +00:00
//
// 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/
2021-04-23 20:00:00 +00:00
package zippkg ;import (_g "archive/zip";_dab "bytes";_da "encoding/xml";_f "fmt";_a "github.com/unidoc/unioffice";_cc "github.com/unidoc/unioffice/algo";_cg "github.com/unidoc/unioffice/common/tempstorage";_ee "github.com/unidoc/unioffice/schema/soo/pkg/relationships";_cb "io";_b "path";_c "sort";_db "strings";_d "time";);
2020-08-23 14:15:53 +00:00
2021-04-23 20:00:00 +00:00
// MarshalXML creates a file inside of a zip and marshals an object as xml, prefixing it
// with a standard XML header.
func MarshalXML (z *_g .Writer ,filename string ,v interface{})error {_af :=&_g .FileHeader {};_af .Method =_g .Deflate ;_af .Name =filename ;_af .SetModTime (_d .Now ());_ddde ,_agf :=z .CreateHeader (_af );if _agf !=nil {return _f .Errorf ("\u0063\u0072\u0065\u0061ti\u006e\u0067\u0020\u0025\u0073\u0020\u0069\u006e\u0020\u007a\u0069\u0070\u003a\u0020%\u0073",filename ,_agf );};_ ,_agf =_ddde .Write ([]byte (XMLHeader ));if _agf !=nil {return _f .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 ,_agf );};if _agf =_da .NewEncoder (SelfClosingWriter {_ddde }).Encode (v );_agf !=nil {return _f .Errorf ("\u006d\u0061\u0072\u0073\u0068\u0061\u006c\u0069\u006e\u0067\u0020\u0025s\u003a\u0020\u0025\u0073",filename ,_agf );};_ ,_agf =_ddde .Write (_ge );return _agf ;};
2021-01-04 16:11:39 +00:00
2021-04-23 20:00:00 +00:00
// Decode loops decoding targets registered with AddTarget and calling th
func (_fcb *DecodeMap )Decode (files []*_g .File )error {_gdg :=1;for _gdg > 0{for len (_fcb ._ea )> 0{_ddd :=_fcb ._ea [len (_fcb ._ea )-1];_fcb ._ea =_fcb ._ea [0:len (_fcb ._ea )-1];_dc :=_ddd .Ifc .(*_ee .Relationships );for _ ,_dag :=range _dc .Relationship {_cbe ,_ :=_fcb ._ab [_dc ];_fcb ._dg (_fcb ,_cbe +_dag .TargetAttr ,_dag .TypeAttr ,files ,_dag ,_ddd );};};for _dae ,_fcc :=range files {if _fcc ==nil {continue ;};if _dfd ,_ddb :=_fcb ._eed [_fcc .Name ];_ddb {delete (_fcb ._eed ,_fcc .Name );if _cff :=Decode (_fcc ,_dfd .Ifc );_cff !=nil {return _cff ;};files [_dae ]=nil ;if _ca ,_be :=_dfd .Ifc .(*_ee .Relationships );_be {_fcb ._ea =append (_fcb ._ea ,_dfd );_dea ,_ :=_b .Split (_b .Clean (_fcc .Name +"\u002f\u002e\u002e\u002f"));_fcb ._ab [_ca ]=_dea ;_gdg ++;};};};_gdg --;};return nil ;};func MarshalXMLByType (z *_g .Writer ,dt _a .DocType ,typ string ,v interface{})error {_gb :=_a .AbsoluteFilename (dt ,typ ,0);return MarshalXML (z ,_gb ,v );};
2021-03-16 20:51:18 +00:00
2021-04-23 20:00:00 +00:00
// RelationsPathFor returns the relations path for a given filename.
func RelationsPathFor (path string )string {_ccb :=_db .Split (path ,"\u002f");_cbb :=_db .Join (_ccb [0:len (_ccb )-1],"\u002f");_eab :=_ccb [len (_ccb )-1];_cbb +="\u002f_\u0072\u0065\u006c\u0073\u002f";_eab +="\u002e\u0072\u0065l\u0073";return _cbb +_eab ;};func (_bc *DecodeMap )RecordIndex (path string ,idx int ){_bc ._ff [path ]=idx };
2020-08-23 14:15:53 +00:00
2021-04-23 20:00:00 +00:00
// 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 *_g .Writer ,zipPath ,storagePath string )error {_fda ,_dagg :=z .Create (zipPath );if _dagg !=nil {return _f .Errorf ("e\u0072\u0072\u006f\u0072 c\u0072e\u0061\u0074\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",zipPath ,_dagg );};_ag ,_dagg :=_cg .Open (storagePath );if _dagg !=nil {return _f .Errorf ("e\u0072r\u006f\u0072\u0020\u006f\u0070\u0065\u006e\u0069n\u0067\u0020\u0025\u0073: \u0025\u0073",storagePath ,_dagg );};defer _ag .Close ();_ ,_dagg =_cb .Copy (_fda ,_ag );return _dagg ;};
// Decode unmarshals the content of a *zip.File as XML to a given destination.
func Decode (f *_g .File ,dest interface{})error {_fde ,_beg :=f .Open ();if _beg !=nil {return _f .Errorf ("e\u0072r\u006f\u0072\u0020\u0072\u0065\u0061\u0064\u0069n\u0067\u0020\u0025\u0073: \u0025\u0073",f .Name ,_beg );};defer _fde .Close ();_cde :=_da .NewDecoder (_fde );if _baf :=_cde .Decode (dest );_baf !=nil {return _f .Errorf ("e\u0072\u0072\u006f\u0072 d\u0065c\u006f\u0064\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",f .Name ,_baf );};if _dba ,_fg :=dest .(*_ee .Relationships );_fg {for _gcf ,_ccc :=range _dba .Relationship {switch _ccc .TypeAttr {case _a .OfficeDocumentTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .OfficeDocumentType ;case _a .StylesTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .StylesType ;case _a .ThemeTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .ThemeType ;case _a .ControlTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .ControlType ;case _a .SettingsTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .SettingsType ;case _a .ImageTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .ImageType ;case _a .CommentsTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .CommentsType ;case _a .ThumbnailTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .ThumbnailType ;case _a .DrawingTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .DrawingType ;case _a .ChartTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .ChartType ;case _a .ExtendedPropertiesTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .ExtendedPropertiesType ;case _a .CustomXMLTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .CustomXMLType ;case _a .WorksheetTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .WorksheetType ;case _a .SharedStringsTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .SharedStringsType ;case _a .TableTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .TableType ;case _a .HeaderTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .HeaderType ;case _a .FooterTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .FooterType ;case _a .NumberingTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .NumberingType ;case _a .FontTableTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .FontTableType ;case _a .WebSettingsTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .WebSettingsType ;case _a .FootNotesTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .FootNotesType ;case _a .EndNotesTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .EndNotesType ;case _a .SlideTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .SlideType ;case _a .VMLDrawingTypeStrict :_dba .Relationship [_gcf ].TypeAttr =_a .VMLDrawingType ;};};_c .Slice (_dba .Relationship ,func (_bf ,_bfc int )bool {_abd :=_dba .Relationship [_bf ];_ffgg :=_dba .Relationship [_bfc ];return _cc .NaturalLess (_abd .IdAttr ,_ffgg .IdAttr );});};return nil ;};
// 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 (_df *DecodeMap )AddTarget (filePath string ,ifc interface{},sourceFileType string ,idx uint32 )bool {if _df ._eed ==nil {_df ._eed =make (map[string ]Target );_df ._ab =make (map[*_ee .Relationships ]string );_df ._cf =make (map[string ]struct{});_df ._ff =make (map[string ]int );};_fa :=_b .Clean (filePath );if _ ,_gd :=_df ._cf [_fa ];_gd {return false ;};_df ._cf [_fa ]=struct{}{};_df ._eed [_fa ]=Target {Path :filePath ,Typ :sourceFileType ,Ifc :ifc ,Index :idx };return true ;};func (_ec SelfClosingWriter )Write (b []byte )(int ,error ){_fb :=0;_bd :=0;for _aed :=0;_aed < len (b )-2;_aed ++{if b [_aed ]=='>'&&b [_aed +1]=='<'&&b [_aed +2]=='/'{_eac :=[]byte {};_ffc :=_aed ;for _ebe :=_aed ;_ebe >=0;_ebe --{if b [_ebe ]==' '{_ffc =_ebe ;}else if b [_ebe ]=='<'{_eac =b [_ebe +1:_ffc ];break ;};};_fbc :=[]byte {};for _ac :=_aed +3;_ac < len (b );_ac ++{if b [_ac ]=='>'{_fbc =b [_aed +3:_ac ];break ;};};if !_dab .Equal (_eac ,_fbc ){continue ;};_fge ,_fba :=_ec .W .Write (b [_fb :_aed ]);if _fba !=nil {return _bd +_fge ,_fba ;};_bd +=_fge ;_ ,_fba =_ec .W .Write (_eba );if _fba !=nil {return _bd ,_fba ;};_bd +=3;for _afa :=_aed +2;_afa < len (b )&&b [_afa ]!='>';_afa ++{_bd ++;_fb =_afa +2;_aed =_fb ;};};};_cccg ,_gbd :=_ec .W .Write (b [_fb :]);return _cccg +_bd ,_gbd ;};func MarshalXMLByTypeIndex (z *_g .Writer ,dt _a .DocType ,typ string ,idx int ,v interface{})error {_gdb :=_a .AbsoluteFilename (dt ,typ ,idx );return MarshalXML (z ,_gdb ,v );};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";
2020-08-23 14:15:53 +00:00
// 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')
2021-04-23 20:00:00 +00:00
type OnNewRelationshipFunc func (_gc *DecodeMap ,_fd ,_fc string ,_ae []*_g .File ,_cd *_ee .Relationship ,_ba Target )error ;
2020-08-23 14:15:53 +00:00
2021-04-23 20:00:00 +00:00
// SelfClosingWriter wraps a writer and replaces XML tags of the
// type <foo></foo> with <foo/>
type SelfClosingWriter struct{W _cb .Writer ;};func (_ffg *DecodeMap )IndexFor (path string )int {return _ffg ._ff [path ]};
2020-12-17 22:07:08 +00:00
2021-04-23 20:00:00 +00:00
// SetOnNewRelationshipFunc sets the function to be called when a new
// relationship has been discovered.
func (_dd *DecodeMap )SetOnNewRelationshipFunc (fn OnNewRelationshipFunc ){_dd ._dg =fn };var _eba =[]byte {'/','>'};
2021-01-04 16:11:39 +00:00
2021-04-23 20:00:00 +00:00
// ExtractToDiskTmp extracts a zip file to a temporary file in a given path,
// returning the name of the file.
func ExtractToDiskTmp (f *_g .File ,path string )(string ,error ){_egc ,_dfb :=_cg .TempFile (path ,"\u007a\u007a");if _dfb !=nil {return "",_dfb ;};defer _egc .Close ();_ffe ,_dfb :=f .Open ();if _dfb !=nil {return "",_dfb ;};defer _ffe .Close ();_ ,_dfb =_cb .Copy (_egc ,_ffe );if _dfb !=nil {return "",_dfb ;};return _egc .Name (),nil ;};type Target struct{Path string ;Typ string ;Ifc interface{};Index uint32 ;};
2021-01-04 16:11:39 +00:00
2021-04-23 20:00:00 +00:00
// DecodeMap is used to walk a tree of relationships, decoding files and passing
// control back to the document.
type DecodeMap struct{_eed map[string ]Target ;_ab map[*_ee .Relationships ]string ;_ea []Target ;_dg OnNewRelationshipFunc ;_cf map[string ]struct{};_ff map[string ]int ;};var _ge =[]byte {'\r','\n'};
2021-03-16 20:51:18 +00:00
// AddFileFromBytes takes a byte array and adds it at a given path to a zip file.
2021-04-23 20:00:00 +00:00
func AddFileFromBytes (z *_g .Writer ,zipPath string ,data []byte )error {_eg ,_deg :=z .Create (zipPath );if _deg !=nil {return _f .Errorf ("e\u0072\u0072\u006f\u0072 c\u0072e\u0061\u0074\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",zipPath ,_deg );};_ ,_deg =_cb .Copy (_eg ,_dab .NewReader (data ));return _deg ;};