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/
2022-02-25 19:20:45 +00:00
package zippkg ;import (_a "archive/zip";_dc "bytes";_ab "encoding/xml";_gb "fmt";_gc "github.com/unidoc/unioffice";_e "github.com/unidoc/unioffice/algo";_fg "github.com/unidoc/unioffice/common/tempstorage";_fa "github.com/unidoc/unioffice/schema/soo/pkg/relationships";_b "io";_gf "path";_g "sort";_d "strings";_c "time";);func (_ca *DecodeMap )RecordIndex (path string ,idx int ){_ca ._gcc [path ]=idx };func MarshalXMLByType (z *_a .Writer ,dt _gc .DocType ,typ string ,v interface{})error {_fedg :=_gc .AbsoluteFilename (dt ,typ ,0);return MarshalXML (z ,_fedg ,v );};func (_eb *DecodeMap )IndexFor (path string )int {return _eb ._gcc [path ]};
2021-03-16 20:51:18 +00:00
2022-02-25 19:20:45 +00:00
// ExtractToDiskTmp extracts a zip file to a temporary file in a given path,
// returning the name of the file.
func ExtractToDiskTmp (f *_a .File ,path string )(string ,error ){_beg ,_cef :=_fg .TempFile (path ,"\u007a\u007a");if _cef !=nil {return "",_cef ;};defer _beg .Close ();_aaf ,_cef :=f .Open ();if _cef !=nil {return "",_cef ;};defer _aaf .Close ();_ ,_cef =_b .Copy (_beg ,_aaf );if _cef !=nil {return "",_cef ;};return _beg .Name (),nil ;};var _dcf =[]byte {'\r','\n'};func MarshalXMLByTypeIndex (z *_a .Writer ,dt _gc .DocType ,typ string ,idx int ,v interface{})error {_dg :=_gc .AbsoluteFilename (dt ,typ ,idx );return MarshalXML (z ,_dg ,v );};
2021-07-30 17:03:26 +00:00
2021-08-23 20:44:48 +00:00
// 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.
2022-02-25 19:20:45 +00:00
func (_bb *DecodeMap )AddTarget (filePath string ,ifc interface{},sourceFileType string ,idx uint32 )bool {if _bb ._bd ==nil {_bb ._bd =make (map[string ]Target );_bb ._daa =make (map[*_fa .Relationships ]string );_bb ._ad =make (map[string ]struct{});_bb ._gcc =make (map[string ]int );};_de :=_gf .Clean (filePath );if _ ,_fgc :=_bb ._ad [_de ];_fgc {return false ;};_bb ._ad [_de ]=struct{}{};_bb ._bd [_de ]=Target {Path :filePath ,Typ :sourceFileType ,Ifc :ifc ,Index :idx };return true ;};
2022-01-15 21:17:38 +00:00
2022-02-25 19:20:45 +00:00
// Decode unmarshals the content of a *zip.File as XML to a given destination.
func Decode (f *_a .File ,dest interface{})error {_cgc ,_ecc :=f .Open ();if _ecc !=nil {return _gb .Errorf ("e\u0072r\u006f\u0072\u0020\u0072\u0065\u0061\u0064\u0069n\u0067\u0020\u0025\u0073: \u0025\u0073",f .Name ,_ecc );};defer _cgc .Close ();_ed :=_ab .NewDecoder (_cgc );if _bc :=_ed .Decode (dest );_bc !=nil {return _gb .Errorf ("e\u0072\u0072\u006f\u0072 d\u0065c\u006f\u0064\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",f .Name ,_bc );};if _egc ,_af :=dest .(*_fa .Relationships );_af {for _bbc ,_fed :=range _egc .Relationship {switch _fed .TypeAttr {case _gc .OfficeDocumentTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .OfficeDocumentType ;case _gc .StylesTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .StylesType ;case _gc .ThemeTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .ThemeType ;case _gc .ControlTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .ControlType ;case _gc .SettingsTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .SettingsType ;case _gc .ImageTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .ImageType ;case _gc .CommentsTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .CommentsType ;case _gc .ThumbnailTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .ThumbnailType ;case _gc .DrawingTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .DrawingType ;case _gc .ChartTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .ChartType ;case _gc .ExtendedPropertiesTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .ExtendedPropertiesType ;case _gc .CustomXMLTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .CustomXMLType ;case _gc .WorksheetTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .WorksheetType ;case _gc .SharedStringsTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .SharedStringsType ;case _gc .TableTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .TableType ;case _gc .HeaderTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .HeaderType ;case _gc .FooterTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .FooterType ;case _gc .NumberingTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .NumberingType ;case _gc .FontTableTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .FontTableType ;case _gc .WebSettingsTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .WebSettingsType ;case _gc .FootNotesTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .FootNotesType ;case _gc .EndNotesTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .EndNotesType ;case _gc .SlideTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .SlideType ;case _gc .VMLDrawingTypeStrict :_egc .Relationship [_bbc ].TypeAttr =_gc .VMLDrawingType ;};};_g .Slice (_egc .Relationship ,func (_ba ,_dfe int )bool {_gfg :=_egc .Relationship [_ba ];_aa :=_egc .Relationship [_dfe ];return _e .NaturalLess (_gfg .IdAttr ,_aa .IdAttr );});};return 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 *_a .Writer ,filename string ,v interface{})error {_dgc :=&_a .FileHeader {};_dgc .Method =_a .Deflate ;_dgc .Name =filename ;_dgc .SetModTime (_c .Now ());_ded ,_cd :=z .CreateHeader (_dgc );if _cd !=nil {return _gb .Errorf ("\u0063\u0072\u0065\u0061ti\u006e\u0067\u0020\u0025\u0073\u0020\u0069\u006e\u0020\u007a\u0069\u0070\u003a\u0020%\u0073",filename ,_cd );};_ ,_cd =_ded .Write ([]byte (XMLHeader ));if _cd !=nil {return _gb .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 ,_cd );};if _cd =_ab .NewEncoder (SelfClosingWriter {_ded }).Encode (v );_cd !=nil {return _gb .Errorf ("\u006d\u0061\u0072\u0073\u0068\u0061\u006c\u0069\u006e\u0067\u0020\u0025s\u003a\u0020\u0025\u0073",filename ,_cd );};_ ,_cd =_ded .Write (_dcf );return _cd ;};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";
2022-01-15 21:17:38 +00:00
// DecodeMap is used to walk a tree of relationships, decoding files and passing
// control back to the document.
2022-02-25 19:20:45 +00:00
type DecodeMap struct{_bd map[string ]Target ;_daa map[*_fa .Relationships ]string ;_cc []Target ;_eg OnNewRelationshipFunc ;_ad map[string ]struct{};_gcc map[string ]int ;};var _bf =[]byte {'/','>'};
2022-02-05 13:05:36 +00:00
2022-02-25 19:20:45 +00:00
// AddFileFromBytes takes a byte array and adds it at a given path to a zip file.
func AddFileFromBytes (z *_a .Writer ,zipPath string ,data []byte )error {_dea ,_egfb :=z .Create (zipPath );if _egfb !=nil {return _gb .Errorf ("e\u0072\u0072\u006f\u0072 c\u0072e\u0061\u0074\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",zipPath ,_egfb );};_ ,_egfb =_b .Copy (_dea ,_dc .NewReader (data ));return _egfb ;};
// RelationsPathFor returns the relations path for a given filename.
func RelationsPathFor (path string )string {_gcf :=_d .Split (path ,"\u002f");_gg :=_d .Join (_gcf [0:len (_gcf )-1],"\u002f");_dagg :=_gcf [len (_gcf )-1];_gg +="\u002f_\u0072\u0065\u006c\u0073\u002f";_dagg +="\u002e\u0072\u0065l\u0073";return _gg +_dagg ;};
// SelfClosingWriter wraps a writer and replaces XML tags of the
// type <foo></foo> with <foo/>
type SelfClosingWriter struct{W _b .Writer ;};type Target struct{Path string ;Typ string ;Ifc interface{};Index uint32 ;};
2022-02-05 13:05:36 +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().
2022-02-25 19:20:45 +00:00
func AddFileFromDisk (z *_a .Writer ,zipPath ,storagePath string )error {_gfc ,_dbd :=z .Create (zipPath );if _dbd !=nil {return _gb .Errorf ("e\u0072\u0072\u006f\u0072 c\u0072e\u0061\u0074\u0069\u006e\u0067 \u0025\u0073\u003a\u0020\u0025\u0073",zipPath ,_dbd );};_egf ,_dbd :=_fg .Open (storagePath );if _dbd !=nil {return _gb .Errorf ("e\u0072r\u006f\u0072\u0020\u006f\u0070\u0065\u006e\u0069n\u0067\u0020\u0025\u0073: \u0025\u0073",storagePath ,_dbd );};defer _egf .Close ();_ ,_dbd =_b .Copy (_gfc ,_egf );return _dbd ;};func (_efg SelfClosingWriter )Write (b []byte )(int ,error ){_fgb :=0;_ceg :=0;for _fc :=0;_fc < len (b )-2;_fc ++{if b [_fc ]=='>'&&b [_fc +1]=='<'&&b [_fc +2]=='/'{_ede :=[]byte {};_ga :=_fc ;for _ecb :=_fc ;_ecb >=0;_ecb --{if b [_ecb ]==' '{_ga =_ecb ;}else if b [_ecb ]=='<'{_ede =b [_ecb +1:_ga ];break ;};};_cgg :=[]byte {};for _gfcc :=_fc +3;_gfcc < len (b );_gfcc ++{if b [_gfcc ]=='>'{_cgg =b [_fc +3:_gfcc ];break ;};};if !_dc .Equal (_ede ,_cgg ){continue ;};_cge ,_aafa :=_efg .W .Write (b [_fgb :_fc ]);if _aafa !=nil {return _ceg +_cge ,_aafa ;};_ceg +=_cge ;_ ,_aafa =_efg .W .Write (_bf );if _aafa !=nil {return _ceg ,_aafa ;};_ceg +=3;for _dbeb :=_fc +2;_dbeb < len (b )&&b [_dbeb ]!='>';_dbeb ++{_ceg ++;_fgb =_dbeb +2;_fc =_fgb ;};};};_cggc ,_edc :=_efg .W .Write (b [_fgb :]);return _cggc +_ceg ,_edc ;};
2022-01-15 21:17:38 +00:00
2022-02-25 19:20:45 +00:00
// SetOnNewRelationshipFunc sets the function to be called when a new
// relationship has been discovered.
func (_cf *DecodeMap )SetOnNewRelationshipFunc (fn OnNewRelationshipFunc ){_cf ._eg =fn };
2022-02-05 13:05:36 +00:00
2022-02-25 19:20:45 +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')
type OnNewRelationshipFunc func (_da *DecodeMap ,_ag ,_cg string ,_dad []*_a .File ,_dd *_fa .Relationship ,_fe Target )error ;
2022-01-15 21:17:38 +00:00
2022-02-25 19:20:45 +00:00
// Decode loops decoding targets registered with AddTarget and calling th
func (_db *DecodeMap )Decode (files []*_a .File )error {_bbg :=1;for _bbg > 0{for len (_db ._cc )> 0{_cb :=_db ._cc [0];_db ._cc =_db ._cc [1:];_ef :=_cb .Ifc .(*_fa .Relationships );for _ ,_cbf :=range _ef .Relationship {_fb ,_ :=_db ._daa [_ef ];_db ._eg (_db ,_fb +_cbf .TargetAttr ,_cbf .TypeAttr ,files ,_cbf ,_cb );};};for _fag ,_dag :=range files {if _dag ==nil {continue ;};if _agf ,_dbe :=_db ._bd [_dag .Name ];_dbe {delete (_db ._bd ,_dag .Name );if _ee :=Decode (_dag ,_agf .Ifc );_ee !=nil {return _ee ;};files [_fag ]=nil ;if _fad ,_be :=_agf .Ifc .(*_fa .Relationships );_be {_db ._cc =append (_db ._cc ,_agf );_dde ,_ :=_gf .Split (_gf .Clean (_dag .Name +"\u002f\u002e\u002e\u002f"));_db ._daa [_fad ]=_dde ;_bbg ++;};};};_bbg --;};return nil ;};