mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-25 13:48:53 +08:00
97 lines
12 KiB
Go
97 lines
12 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 (_f "archive/zip";_be "bytes";_fee "encoding/xml";_fe "fmt";_g "github.com/unidoc/unioffice";_d "github.com/unidoc/unioffice/algo";_bc "github.com/unidoc/unioffice/common/tempstorage";_cd "github.com/unidoc/unioffice/schema/soo/pkg/relationships";
|
|
_e "io";_fd "path";_b "sort";_fg "strings";_c "time";);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 MarshalXMLByType (z *_f .Writer ,dt _g .DocType ,typ string ,v interface{})error {_fda :=_g .AbsoluteFilename (dt ,typ ,0);return MarshalXML (z ,_fda ,v );};
|
|
|
|
// AddFileFromBytes takes a byte array and adds it at a given path to a zip file.
|
|
func AddFileFromBytes (z *_f .Writer ,zipPath string ,data []byte )error {_dda ,_ccb :=z .Create (zipPath );if _ccb !=nil {return _fe .Errorf ("e\u0072\u0072\u006f\u0072 c\u0072e\u0061\u0074\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",zipPath ,_ccb );
|
|
};_ ,_ccb =_e .Copy (_dda ,_be .NewReader (data ));return _ccb ;};var _aee =[]byte {'/','>'};
|
|
|
|
// 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 *_f .Writer ,zipPath ,storagePath string )error {_agb ,_ggcc :=z .Create (zipPath );if _ggcc !=nil {return _fe .Errorf ("e\u0072\u0072\u006f\u0072 c\u0072e\u0061\u0074\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",zipPath ,_ggcc );
|
|
};_ddfc ,_ggcc :=_bc .Open (storagePath );if _ggcc !=nil {return _fe .Errorf ("e\u0072r\u006f\u0072\u0020\u006f\u0070\u0065\u006e\u0069n\u0067\u0020\u0025\u0073: \u0025\u0073",storagePath ,_ggcc );};defer _ddfc .Close ();_ ,_ggcc =_e .Copy (_agb ,_ddfc );
|
|
return _ggcc ;};
|
|
|
|
// RelationsPathFor returns the relations path for a given filename.
|
|
func RelationsPathFor (path string )string {_gcbg :=_fg .Split (path ,"\u002f");_bec :=_fg .Join (_gcbg [0:len (_gcbg )-1],"\u002f");_acc :=_gcbg [len (_gcbg )-1];_bec +="\u002f_\u0072\u0065\u006c\u0073\u002f";_acc +="\u002e\u0072\u0065l\u0073";return _bec +_acc ;
|
|
};func (_ee *DecodeMap )IndexFor (path string )int {return _ee ._ege [path ]};
|
|
|
|
// ExtractToDiskTmp extracts a zip file to a temporary file in a given path,
|
|
// returning the name of the file.
|
|
func ExtractToDiskTmp (f *_f .File ,path string )(string ,error ){_gd ,_dafc :=_bc .TempFile (path ,"\u007a\u007a");if _dafc !=nil {return "",_dafc ;};defer _gd .Close ();_cg ,_dafc :=f .Open ();if _dafc !=nil {return "",_dafc ;};defer _cg .Close ();_ ,_dafc =_e .Copy (_gd ,_cg );
|
|
if _dafc !=nil {return "",_dafc ;};return _gd .Name (),nil ;};
|
|
|
|
// MarshalXML creates a file inside of a zip and marshals an object as xml, prefixing it
|
|
// with a standard XML header.
|
|
func MarshalXML (z *_f .Writer ,filename string ,v interface{})error {_gea :=&_f .FileHeader {};_gea .Method =_f .Deflate ;_gea .Name =filename ;_gea .SetModTime (_c .Now ());_bdg ,_ccd :=z .CreateHeader (_gea );if _ccd !=nil {return _fe .Errorf ("\u0063\u0072\u0065\u0061ti\u006e\u0067\u0020\u0025\u0073\u0020\u0069\u006e\u0020\u007a\u0069\u0070\u003a\u0020%\u0073",filename ,_ccd );
|
|
};_ ,_ccd =_bdg .Write ([]byte (XMLHeader ));if _ccd !=nil {return _fe .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 ,_ccd );
|
|
};if _ccd =_fee .NewEncoder (SelfClosingWriter {_bdg }).Encode (v );_ccd !=nil {return _fe .Errorf ("\u006d\u0061\u0072\u0073\u0068\u0061\u006c\u0069\u006e\u0067\u0020\u0025s\u003a\u0020\u0025\u0073",filename ,_ccd );};_ ,_ccd =_bdg .Write (_cf );return _ccd ;
|
|
};func (_ac *DecodeMap )RecordIndex (path string ,idx int ){_ac ._ege [path ]=idx };
|
|
|
|
// DecodeMap is used to walk a tree of relationships, decoding files and passing
|
|
// control back to the document.
|
|
type DecodeMap struct{_bed map[string ]Target ;_gc map[*_cd .Relationships ]string ;_dd []Target ;_eg OnNewRelationshipFunc ;_ef map[string ]struct{};_ege map[string ]int ;};
|
|
|
|
// 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 (_ec *DecodeMap )AddTarget (filePath string ,ifc interface{},sourceFileType string ,idx uint32 )bool {if _ec ._bed ==nil {_ec ._bed =make (map[string ]Target );_ec ._gc =make (map[*_cd .Relationships ]string );_ec ._ef =make (map[string ]struct{});
|
|
_ec ._ege =make (map[string ]int );};if _fd .IsAbs (filePath ){filePath =_fg .TrimPrefix (filePath ,"\u002f");};_ad :=_fd .Clean (filePath );if _ ,_fb :=_ec ._ef [_ad ];_fb {return false ;};_ec ._ef [_ad ]=struct{}{};_ec ._bed [_ad ]=Target {Path :_ad ,Typ :sourceFileType ,Ifc :ifc ,Index :idx };
|
|
return true ;};func MarshalXMLByTypeIndex (z *_f .Writer ,dt _g .DocType ,typ string ,idx int ,v interface{})error {_afd :=_g .AbsoluteFilename (dt ,typ ,idx );return MarshalXML (z ,_afd ,v );};
|
|
|
|
// 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 (_beb *DecodeMap ,_bg ,_db string ,_dg []*_f .File ,_ea *_cd .Relationship ,_dgc Target )error ;type Target struct{Path string ;Typ string ;Ifc interface{};Index uint32 ;};
|
|
|
|
// Decode loops decoding targets registered with AddTarget and calling th
|
|
func (_ag *DecodeMap )Decode (files []*_f .File )error {_aa :=1;for _aa > 0{for len (_ag ._dd )> 0{_gf :=_ag ._dd [0];_ag ._dd =_ag ._dd [1:];_ff :=_gf .Ifc .(*_cd .Relationships );for _ ,_ffd :=range _ff .Relationship {_eb :=_ag ._gc [_ff ];_ffd .TargetAttr =_fg .TrimPrefix (_ffd .TargetAttr ,"\u002f");
|
|
if _fg .IndexByte (_eb ,'/')> -1{_da :=_eb [:_fg .IndexByte (_eb ,'/')+1];if _fg .HasPrefix (_ffd .TargetAttr ,_da ){_eb ="";};};if _fg .HasPrefix (_ffd .TargetAttr ,_eb ){_eb ="";};_ag ._eg (_ag ,_eb +_ffd .TargetAttr ,_ffd .TypeAttr ,files ,_ffd ,_gf );
|
|
};};for _ae ,_gg :=range files {if _gg ==nil {continue ;};if _fdd ,_dga :=_ag ._bed [_gg .Name ];_dga {delete (_ag ._bed ,_gg .Name );if _fbf :=Decode (_gg ,_fdd .Ifc );_fbf !=nil {return _fbf ;};files [_ae ]=nil ;if _gcb ,_af :=_fdd .Ifc .(*_cd .Relationships );
|
|
_af {_ag ._dd =append (_ag ._dd ,_fdd );_ed ,_ :=_fd .Split (_fd .Clean (_gg .Name +"\u002f\u002e\u002e\u002f"));_ag ._gc [_gcb ]=_ed ;_aa ++;};};};_aa --;};return nil ;};
|
|
|
|
// SelfClosingWriter wraps a writer and replaces XML tags of the
|
|
// type <foo></foo> with <foo/>
|
|
type SelfClosingWriter struct{W _e .Writer ;};
|
|
|
|
// SetOnNewRelationshipFunc sets the function to be called when a new
|
|
// relationship has been discovered.
|
|
func (_dbf *DecodeMap )SetOnNewRelationshipFunc (fn OnNewRelationshipFunc ){_dbf ._eg =fn };func (_de SelfClosingWriter )Write (b []byte )(int ,error ){_ecb :=0;_cbf :=0;for _aac :=0;_aac < len (b )-2;_aac ++{if b [_aac ]=='>'&&b [_aac +1]=='<'&&b [_aac +2]=='/'{_dfc :=[]byte {};
|
|
_feg :=_aac ;for _fef :=_aac ;_fef >=0;_fef --{if b [_fef ]==' '{_feg =_fef ;}else if b [_fef ]=='<'{_dfc =b [_fef +1:_feg ];break ;};};_bgd :=[]byte {};for _dgd :=_aac +3;_dgd < len (b );_dgd ++{if b [_dgd ]=='>'{_bgd =b [_aac +3:_dgd ];break ;};};if !_be .Equal (_dfc ,_bgd ){continue ;
|
|
};_bf ,_bdgf :=_de .W .Write (b [_ecb :_aac ]);if _bdgf !=nil {return _cbf +_bf ,_bdgf ;};_cbf +=_bf ;_ ,_bdgf =_de .W .Write (_aee );if _bdgf !=nil {return _cbf ,_bdgf ;};_cbf +=3;for _eab :=_aac +2;_eab < len (b )&&b [_eab ]!='>';_eab ++{_cbf ++;_ecb =_eab +2;
|
|
_aac =_ecb ;};};};_gb ,_aaf :=_de .W .Write (b [_ecb :]);return _gb +_cbf ,_aaf ;};var _cf =[]byte {'\r','\n'};
|
|
|
|
// Decode unmarshals the content of a *zip.File as XML to a given destination.
|
|
func Decode (f *_f .File ,dest interface{})error {_bee ,_cdg :=f .Open ();if _cdg !=nil {return _fe .Errorf ("e\u0072r\u006f\u0072\u0020\u0072\u0065\u0061\u0064\u0069n\u0067\u0020\u0025\u0073: \u0025\u0073",f .Name ,_cdg );};defer _bee .Close ();_ge :=_fee .NewDecoder (_bee );
|
|
if _gfe :=_ge .Decode (dest );_gfe !=nil {return _fe .Errorf ("e\u0072\u0072\u006f\u0072 d\u0065c\u006f\u0064\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",f .Name ,_gfe );};if _cc ,_bcc :=dest .(*_cd .Relationships );_bcc {for _daf ,_egb :=range _cc .Relationship {switch _egb .TypeAttr {case _g .OfficeDocumentTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .OfficeDocumentType ;
|
|
case _g .StylesTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .StylesType ;case _g .ThemeTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .ThemeType ;case _g .ControlTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .ControlType ;case _g .SettingsTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .SettingsType ;
|
|
case _g .ImageTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .ImageType ;case _g .CommentsTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .CommentsType ;case _g .ThumbnailTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .ThumbnailType ;case _g .DrawingTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .DrawingType ;
|
|
case _g .ChartTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .ChartType ;case _g .ExtendedPropertiesTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .ExtendedPropertiesType ;case _g .CustomXMLTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .CustomXMLType ;
|
|
case _g .WorksheetTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .WorksheetType ;case _g .SharedStringsTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .SharedStringsType ;case _g .TableTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .TableType ;
|
|
case _g .HeaderTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .HeaderType ;case _g .FooterTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .FooterType ;case _g .NumberingTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .NumberingType ;case _g .FontTableTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .FontTableType ;
|
|
case _g .WebSettingsTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .WebSettingsType ;case _g .FootNotesTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .FootNotesType ;case _g .EndNotesTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .EndNotesType ;
|
|
case _g .SlideTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .SlideType ;case _g .VMLDrawingTypeStrict :_cc .Relationship [_daf ].TypeAttr =_g .VMLDrawingType ;};};_b .Slice (_cc .Relationship ,func (_ab ,_df int )bool {_ggc :=_cc .Relationship [_ab ];
|
|
_ddf :=_cc .Relationship [_df ];return _d .NaturalLess (_ggc .IdAttr ,_ddf .IdAttr );});};return nil ;}; |