Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/ExcelPackage.cs @ 12074

Last change on this file since 12074 was 12074, checked in by sraggl, 9 years ago

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 47.8 KB
Line 
1/*******************************************************************************
2 * You may amend and distribute as you like, but don't remove this header!
3 *
4 * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
5 * See http://www.codeplex.com/EPPlus for details.
6 *
7 * Copyright (C) 2011  Jan Källman
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
17 * See the GNU Lesser General Public License for more details.
18 *
19 * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
20 * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
21 *
22 * All code and executables are provided "as is" with no warranty either express or implied.
23 * The author accepts no liability for any damage or loss of business that this product may cause.
24 *
25 * Code change notes:
26 *
27 * Author             Change            Date
28 * ******************************************************************************
29 * Jan Källman                    Initial Release           2009-10-01
30 * Starnuto Di Topo & Jan Källman   Added stream constructors
31 *                                  and Load method Save as
32 *                                  stream                      2010-03-14
33 * Jan Källman    License changed GPL-->LGPL 2011-12-27
34 *******************************************************************************/
35using System;
36using System.Xml;
37using System.IO;
38using System.Collections.Generic;
39using System.Security.Cryptography;
40using OfficeOpenXml.Drawing;
41using OfficeOpenXml.Utils;
42using OfficeOpenXml.Packaging.Ionic.Zlib;
43using OfficeOpenXml.FormulaParsing;
44using OfficeOpenXml.Encryption;
45namespace OfficeOpenXml
46{
47    /// <summary>
48    /// Maps to DotNetZips CompressionLevel enum
49    /// </summary>
50    public enum CompressionLevel
51    {
52        Level0 = 0,
53        None = 0,
54        Level1 = 1,
55        BestSpeed = 1,
56        Level2 = 2,
57        Level3 = 3,
58        Level4 = 4,
59        Level5 = 5,
60        Level6 = 6,
61        Default = 6,
62        Level7 = 7,
63        Level8 = 8,
64        BestCompression = 9,
65        Level9 = 9,
66    }
67    /// <summary>
68    /// Represents an Excel 2007/2010 XLSX file package. 
69    /// This is the top-level object to access all parts of the document.
70    /// <code>
71  ///     FileInfo newFile = new FileInfo(outputDir.FullName + @"\sample1.xlsx");
72  ///   if (newFile.Exists)
73  ///   {
74  ///     newFile.Delete();  // ensures we create a new workbook
75  ///     newFile = new FileInfo(outputDir.FullName + @"\sample1.xlsx");
76  ///   }
77  ///   using (ExcelPackage package = new ExcelPackage(newFile))
78    ///     {
79    ///         // add a new worksheet to the empty workbook
80    ///         ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Inventory");
81    ///         //Add the headers
82    ///         worksheet.Cells[1, 1].Value = "ID";
83    ///         worksheet.Cells[1, 2].Value = "Product";
84    ///         worksheet.Cells[1, 3].Value = "Quantity";
85    ///         worksheet.Cells[1, 4].Value = "Price";
86    ///         worksheet.Cells[1, 5].Value = "Value";
87    ///
88    ///         //Add some items...
89    ///         worksheet.Cells["A2"].Value = "12001";
90    ///         worksheet.Cells["B2"].Value = "Nails";
91    ///         worksheet.Cells["C2"].Value = 37;
92    ///         worksheet.Cells["D2"].Value = 3.99;
93    ///
94    ///         worksheet.Cells["A3"].Value = "12002";
95    ///         worksheet.Cells["B3"].Value = "Hammer";
96    ///         worksheet.Cells["C3"].Value = 5;
97    ///         worksheet.Cells["D3"].Value = 12.10;
98    ///
99    ///         worksheet.Cells["A4"].Value = "12003";
100    ///         worksheet.Cells["B4"].Value = "Saw";
101    ///         worksheet.Cells["C4"].Value = 12;
102    ///         worksheet.Cells["D4"].Value = 15.37;
103    ///
104    ///         //Add a formula for the value-column
105    ///         worksheet.Cells["E2:E4"].Formula = "C2*D2";
106    ///
107    ///            //Ok now format the values;
108    ///         using (var range = worksheet.Cells[1, 1, 1, 5])
109    ///          {
110    ///             range.Style.Font.Bold = true;
111    ///             range.Style.Fill.PatternType = ExcelFillStyle.Solid;
112    ///             range.Style.Fill.BackgroundColor.SetColor(Color.DarkBlue);
113    ///             range.Style.Font.Color.SetColor(Color.White);
114    ///         }
115    ///
116    ///         worksheet.Cells["A5:E5"].Style.Border.Top.Style = ExcelBorderStyle.Thin;
117    ///         worksheet.Cells["A5:E5"].Style.Font.Bold = true;
118    ///
119    ///         worksheet.Cells[5, 3, 5, 5].Formula = string.Format("SUBTOTAL(9,{0})", new ExcelAddress(2,3,4,3).Address);
120    ///         worksheet.Cells["C2:C5"].Style.Numberformat.Format = "#,##0";
121    ///         worksheet.Cells["D2:E5"].Style.Numberformat.Format = "#,##0.00";
122    ///
123    ///         //Create an autofilter for the range
124    ///         worksheet.Cells["A1:E4"].AutoFilter = true;
125    ///
126    ///         worksheet.Cells["A1:E5"].AutoFitColumns(0);
127    ///
128    ///         // lets set the header text
129    ///         worksheet.HeaderFooter.oddHeader.CenteredText = "&amp;24&amp;U&amp;\"Arial,Regular Bold\" Inventory";
130    ///         // add the page number to the footer plus the total number of pages
131    ///         worksheet.HeaderFooter.oddFooter.RightAlignedText =
132    ///         string.Format("Page {0} of {1}", ExcelHeaderFooter.PageNumber, ExcelHeaderFooter.NumberOfPages);
133    ///         // add the sheet name to the footer
134    ///         worksheet.HeaderFooter.oddFooter.CenteredText = ExcelHeaderFooter.SheetName;
135    ///         // add the file path to the footer
136    ///         worksheet.HeaderFooter.oddFooter.LeftAlignedText = ExcelHeaderFooter.FilePath + ExcelHeaderFooter.FileName;
137    ///
138    ///         worksheet.PrinterSettings.RepeatRows = worksheet.Cells["1:2"];
139    ///         worksheet.PrinterSettings.RepeatColumns = worksheet.Cells["A:G"];
140    ///
141    ///          // Change the sheet view to show it in page layout mode
142    ///           worksheet.View.PageLayoutView = true;
143    ///
144    ///         // set some document properties
145    ///         package.Workbook.Properties.Title = "Invertory";
146    ///         package.Workbook.Properties.Author = "Jan Källman";
147    ///         package.Workbook.Properties.Comments = "This sample demonstrates how to create an Excel 2007 workbook using EPPlus";
148    ///
149    ///         // set some extended property values
150    ///         package.Workbook.Properties.Company = "AdventureWorks Inc.";
151    ///
152    ///         // set some custom property values
153    ///         package.Workbook.Properties.SetCustomPropertyValue("Checked by", "Jan Källman");
154    ///         package.Workbook.Properties.SetCustomPropertyValue("AssemblyName", "EPPlus");
155    ///
156    ///         // save our new workbook and we are done!
157    ///         package.Save();
158    ///
159    ///       }
160    ///
161    ///       return newFile.FullName;
162    /// </code>
163    /// More samples can be found at  <a href="http://epplus.codeplex.com/">http://epplus.codeplex.com/</a>
164    /// </summary>
165  public sealed class ExcelPackage : IDisposable
166  {
167        internal const bool preserveWhitespace=false;
168        Stream _stream = null;
169        private bool _isExternalStream=false;
170        internal class ImageInfo
171        {
172            internal string Hash { get; set; }
173            internal Uri Uri{get;set;}
174            internal int RefCount { get; set; }
175            internal Packaging.ZipPackagePart Part { get; set; }
176        }
177        internal Dictionary<string, ImageInfo> _images = new Dictionary<string, ImageInfo>();
178    #region Properties
179    /// <summary>
180    /// Extention Schema types
181    /// </summary>
182        internal const string schemaXmlExtension = "application/xml";
183        internal const string schemaRelsExtension = "application/vnd.openxmlformats-package.relationships+xml";
184        /// <summary>
185    /// Main Xml schema name
186    /// </summary>
187    internal const string schemaMain = @"http://schemas.openxmlformats.org/spreadsheetml/2006/main";
188    /// <summary>
189    /// Relationship schema name
190    /// </summary>
191    internal const string schemaRelationships = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships";
192                                                                             
193        internal const string schemaDrawings = @"http://schemas.openxmlformats.org/drawingml/2006/main";
194        internal const string schemaSheetDrawings = @"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
195        internal const string schemaMarkupCompatibility = @"http://schemas.openxmlformats.org/markup-compatibility/2006";
196
197        internal const string schemaMicrosoftVml = @"urn:schemas-microsoft-com:vml";
198        internal const string schemaMicrosoftOffice = "urn:schemas-microsoft-com:office:office";
199        internal const string schemaMicrosoftExcel = "urn:schemas-microsoft-com:office:excel";
200
201        internal const string schemaChart = @"http://schemas.openxmlformats.org/drawingml/2006/chart";                                                       
202        internal const string schemaHyperlink = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
203        internal const string schemaComment = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
204        internal const string schemaImage = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
205        //Office properties
206        internal const string schemaCore = @"http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
207        internal const string schemaExtended = @"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
208        internal const string schemaCustom = @"http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
209        internal const string schemaDc = @"http://purl.org/dc/elements/1.1/";
210        internal const string schemaDcTerms = @"http://purl.org/dc/terms/";
211        internal const string schemaDcmiType = @"http://purl.org/dc/dcmitype/";
212        internal const string schemaXsi = @"http://www.w3.org/2001/XMLSchema-instance";
213        internal const string schemaVt = @"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
214
215        //Pivottables
216        internal const string schemaPivotTable = @"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml";
217        internal const string schemaPivotCacheDefinition = @"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml";
218        internal const string schemaPivotCacheRecords = @"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml";
219
220        //VBA
221        internal const string schemaVBA = @"application/vnd.ms-office.vbaProject";
222        internal const string schemaVBASignature = @"application/vnd.ms-office.vbaProjectSignature";
223
224        internal const string contentTypeWorkbookDefault = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
225        internal const string contentTypeWorkbookMacroEnabled = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
226        internal const string contentTypeSharedString = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
227        //Package reference
228        private Packaging.ZipPackage _package;
229    internal ExcelWorkbook _workbook;
230        /// <summary>
231        /// Maximum number of columns in a worksheet (16384).
232        /// </summary>
233        public const int MaxColumns = 16384;
234        /// <summary>
235        /// Maximum number of rows in a worksheet (1048576).
236        /// </summary>
237        public const int MaxRows = 1048576;
238    #endregion
239
240    #region ExcelPackage Constructors
241        /// <summary>
242        /// Create a new instance of the ExcelPackage. Output is accessed through the Stream property.
243        /// </summary>
244        public ExcelPackage()
245        {
246            Init();
247            ConstructNewFile(null);
248        }
249        /// <summary>
250    /// Create a new instance of the ExcelPackage class based on a existing file or creates a new file.
251    /// </summary>
252    /// <param name="newFile">If newFile exists, it is opened.  Otherwise it is created from scratch.</param>
253        public ExcelPackage(FileInfo newFile)
254    {
255            Init();
256            File = newFile;
257            ConstructNewFile(null);
258        }
259        /// <summary>
260        /// Create a new instance of the ExcelPackage class based on a existing file or creates a new file.
261        /// </summary>
262        /// <param name="newFile">If newFile exists, it is opened.  Otherwise it is created from scratch.</param>
263        /// <param name="password">Password for an encrypted package</param>
264        public ExcelPackage(FileInfo newFile, string password)
265        {
266            Init();
267            File = newFile;
268            ConstructNewFile(password);
269        }
270    /// <summary>
271    /// Create a new instance of the ExcelPackage class based on a existing template.
272    /// If newFile exists, it will be overwritten when the Save method is called
273    /// </summary>
274    /// <param name="newFile">The name of the Excel file to be created</param>
275    /// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
276    public ExcelPackage(FileInfo newFile, FileInfo template)
277    {
278            Init();
279            File = newFile;
280            CreateFromTemplate(template, null);
281    }
282        /// <summary>
283        /// Create a new instance of the ExcelPackage class based on a existing template.
284        /// If newFile exists, it will be overwritten when the Save method is called
285        /// </summary>
286        /// <param name="newFile">The name of the Excel file to be created</param>
287        /// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
288        /// <param name="password">Password to decrypted the template</param>
289        public ExcelPackage(FileInfo newFile, FileInfo template, string password)
290        {
291            Init();
292            File = newFile;
293            CreateFromTemplate(template, password);
294        }
295        /// <summary>
296        /// Create a new instance of the ExcelPackage class based on a existing template.
297        /// </summary>
298        /// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
299        /// <param name="useStream">if true use a stream. If false create a file in the temp dir with a random name</param>
300        public ExcelPackage(FileInfo template, bool useStream)
301        {
302            Init();
303            CreateFromTemplate(template, null);
304            if (useStream == false)
305            {
306                File = new FileInfo(Path.GetTempPath() + Guid.NewGuid().ToString() + ".xlsx");
307            }
308        }
309        /// <summary>
310        /// Create a new instance of the ExcelPackage class based on a existing template.
311        /// </summary>
312        /// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
313        /// <param name="useStream">if true use a stream. If false create a file in the temp dir with a random name</param>
314        /// <param name="password">Password to decrypted the template</param>
315        public ExcelPackage(FileInfo template, bool useStream, string password)
316        {
317            Init();
318            CreateFromTemplate(template, password);
319            if (useStream == false)
320            {
321                File = new FileInfo(Path.GetTempPath() + Guid.NewGuid().ToString() + ".xlsx");
322            }
323        }
324        /// <summary>
325        /// Create a new instance of the ExcelPackage class based on a stream
326        /// </summary>
327        /// <param name="newStream">The stream object can be empty or contain a package. The stream must be Read/Write</param>
328        public ExcelPackage(Stream newStream)
329        {
330            Init();
331            if (newStream.Length == 0)
332            {
333                _stream = newStream;
334                _isExternalStream = true;
335                ConstructNewFile(null);
336            }
337            else
338            {               
339                Load(newStream);
340            }
341        }
342        /// <summary>
343        /// Create a new instance of the ExcelPackage class based on a stream
344        /// </summary>
345        /// <param name="newStream">The stream object can be empty or contain a package. The stream must be Read/Write</param>
346        /// <param name="Password">The password to decrypt the document</param>
347        public ExcelPackage(Stream newStream, string Password)
348        {
349            if (!(newStream.CanRead && newStream.CanWrite))
350            {
351                throw new Exception("The stream must be read/write");
352            }
353
354            Init();
355            if (newStream.Length > 0)
356            {
357                Load(newStream,Password);
358            }
359            else
360            {
361                _stream = newStream;
362                _isExternalStream = true;
363                //_package = Package.Open(_stream, FileMode.Create, FileAccess.ReadWrite); TODO:Remove
364                _package = new Packaging.ZipPackage(_stream);
365                CreateBlankWb();
366            }
367        }
368        /// <summary>
369        /// Create a new instance of the ExcelPackage class based on a stream
370        /// </summary>
371        /// <param name="newStream">The output stream. Must be an empty read/write stream.</param>
372        /// <param name="templateStream">This stream is copied to the output stream at load</param>
373        public ExcelPackage(Stream newStream, Stream templateStream)
374        {
375            if (newStream.Length > 0)
376            {
377                throw(new Exception("The output stream must be empty. Length > 0"));
378            }
379            else if (!(newStream.CanRead && newStream.CanWrite))
380            {
381                throw new Exception("The stream must be read/write");
382            }
383            Init();
384            Load(templateStream, newStream, null);
385        }
386        /// <summary>
387        /// Create a new instance of the ExcelPackage class based on a stream
388        /// </summary>
389        /// <param name="newStream">The output stream. Must be an empty read/write stream.</param>
390        /// <param name="templateStream">This stream is copied to the output stream at load</param>
391        /// <param name="Password">Password to decrypted the template</param>
392        public ExcelPackage(Stream newStream, Stream templateStream, string Password)
393        {
394            if (newStream.Length > 0)
395            {
396                throw (new Exception("The output stream must be empty. Length > 0"));
397            }
398            else if (!(newStream.CanRead && newStream.CanWrite))
399            {
400                throw new Exception("The stream must be read/write");
401            }
402            Init();
403            Load(templateStream, newStream, Password);
404        }
405        #endregion
406        internal ImageInfo AddImage(byte[] image)
407        {
408            return AddImage(image, null, "");
409        }
410        internal ImageInfo AddImage(byte[] image, Uri uri, string contentType)
411        {
412            var hashProvider = new SHA1CryptoServiceProvider();
413            var hash = BitConverter.ToString(hashProvider.ComputeHash(image)).Replace("-","");
414            lock (_images)
415            {
416                if (_images.ContainsKey(hash))
417                {
418                    _images[hash].RefCount++;
419                }
420                else
421                {
422                    Packaging.ZipPackagePart imagePart;
423                    if (uri == null)
424                    {
425                        uri = GetNewUri(Package, "/xl/media/image{0}.jpg");
426                        imagePart = Package.CreatePart(uri, "image/jpeg", CompressionLevel.None);
427                    }
428                    else
429                    {
430                        imagePart = Package.CreatePart(uri, contentType, CompressionLevel.None);
431                    }
432                    var stream = imagePart.GetStream(FileMode.Create, FileAccess.Write);
433                    stream.Write(image, 0, image.GetLength(0));
434
435                    _images.Add(hash, new ImageInfo() { Uri = uri, RefCount = 1, Hash = hash, Part = imagePart });
436                }
437            }
438            return _images[hash];
439        }
440        internal ImageInfo LoadImage(byte[] image, Uri uri, Packaging.ZipPackagePart imagePart)
441        {
442            var hashProvider = new SHA1CryptoServiceProvider();
443            var hash = BitConverter.ToString(hashProvider.ComputeHash(image)).Replace("-", "");
444            if (_images.ContainsKey(hash))
445            {
446                _images[hash].RefCount++;
447            }
448            else
449            {
450                _images.Add(hash, new ImageInfo() { Uri = uri, RefCount = 1, Hash = hash, Part = imagePart });
451            }
452            return _images[hash];
453        }
454        internal void RemoveImage(string hash)
455        {
456            lock (_images)
457            {
458                if (_images.ContainsKey(hash))
459                {
460                    var ii = _images[hash];
461                    ii.RefCount--;
462                    if (ii.RefCount == 0)
463                    {
464                        Package.DeletePart(ii.Uri);
465                        _images.Remove(hash);
466                    }
467                }
468            }
469        }
470        internal ImageInfo GetImageInfo(byte[] image)
471        {
472            var hashProvider = new SHA1CryptoServiceProvider();
473            var hash = BitConverter.ToString(hashProvider.ComputeHash(image)).Replace("-","");
474
475            if (_images.ContainsKey(hash))
476            {
477                return _images[hash];
478            }
479            else
480            {
481                return null;
482            }
483        }
484        private Uri GetNewUri(Packaging.ZipPackage package, string sUri)
485        {
486            int id = 1;
487            Uri uri;
488            do
489            {
490                uri = new Uri(string.Format(sUri, id++), UriKind.Relative);
491            }
492            while (package.PartExists(uri));
493            return uri;
494        }
495        /// <summary>
496        /// Init values here
497        /// </summary>
498        private void Init()
499        {
500            DoAdjustDrawings = true;
501        }
502        /// <summary>
503        /// Create a new file from a template
504        /// </summary>
505        /// <param name="template">An existing xlsx file to use as a template</param>
506        /// <param name="password">The password to decrypt the package.</param>
507        /// <returns></returns>
508        private void CreateFromTemplate(FileInfo template, string password)
509        {
510            if (template != null) template.Refresh();
511            if (template.Exists)
512            {
513                if(_stream==null) _stream=new MemoryStream();
514                var ms = new MemoryStream();
515                if (password != null)
516                {
517#if !MONO
518                    Encryption.IsEncrypted = true;
519                    Encryption.Password = password;
520                    var encrHandler = new EncryptedPackageHandler();
521                    ms = encrHandler.DecryptPackage(template, Encryption);
522                    encrHandler = null;
523#endif
524#if MONO
525                  throw (new NotImplementedException("No support for Encrypted packages in Mono"));
526#endif
527                  //throw (new NotImplementedException("No support for Encrypted packages in this version"));
528                }
529                else
530                {
531                    byte[] b = System.IO.File.ReadAllBytes(template.FullName);
532                    ms.Write(b, 0, b.Length);
533                }
534                try
535                {
536                    //_package = Package.Open(_stream, FileMode.Open, FileAccess.ReadWrite);
537                    _package = new Packaging.ZipPackage(ms);
538                }
539                catch (Exception ex)
540                {
541#if !MONO
542                    if (password == null && CompoundDocument.IsStorageFile(template.FullName)==0)
543                    {
544                        throw new Exception("Can not open the package. Package is an OLE compound document. If this is an encrypted package, please supply the password", ex);
545                    }
546                    else
547                    {
548                        throw;
549                    }
550#endif
551#if MONO
552                    throw;
553#endif
554                }
555            }
556            else
557                throw new Exception("Passed invalid TemplatePath to Excel Template");
558            //return newFile;
559        }
560        private void ConstructNewFile(string password)
561        {
562            var ms = new MemoryStream();
563            if (_stream == null) _stream = new MemoryStream();
564            if (File != null) File.Refresh();
565            if (File != null && File.Exists)
566            {
567                if (password != null)
568                {
569#if !MONO
570                    var encrHandler = new EncryptedPackageHandler();
571                    Encryption.IsEncrypted = true;
572                    Encryption.Password = password;
573                    ms = encrHandler.DecryptPackage(File, Encryption);
574                    encrHandler = null;
575#endif
576#if MONO
577                    throw new NotImplementedException("No support for Encrypted packages in Mono");
578#endif
579                }
580                else
581                {
582                    byte[] b = System.IO.File.ReadAllBytes(File.FullName);
583                    ms.Write(b, 0, b.Length);
584                }
585                try
586                {
587                    //_package = Package.Open(_stream, FileMode.Open, FileAccess.ReadWrite);
588                    _package = new Packaging.ZipPackage(ms);
589                }
590                catch (Exception ex)
591               {
592#if !MONO
593                    if (password == null && CompoundDocument.IsStorageFile(File.FullName)==0)
594                    {
595                        throw new Exception("Can not open the package. Package is an OLE compound document. If this is an encrypted package, please supply the password", ex);
596                    }
597                    else
598                    {
599                        throw;
600                    }
601#endif
602#if MONO
603                    throw;
604#endif
605                }
606            }
607            else
608            {
609                //_package = Package.Open(_stream, FileMode.Create, FileAccess.ReadWrite);
610                _package = new Packaging.ZipPackage(ms);
611                CreateBlankWb();
612            }
613        }
614
615        private void CreateBlankWb()
616        {
617            XmlDocument workbook = Workbook.WorkbookXml; // this will create the workbook xml in the package
618            // create the relationship to the main part
619            _package.CreateRelationship(UriHelper.GetRelativeUri(new Uri("/xl", UriKind.Relative), Workbook.WorkbookUri), Packaging.TargetMode.Internal, schemaRelationships + "/officeDocument");
620        }
621
622    /// <summary>
623    /// Returns a reference to the package
624    /// </summary>
625    public Packaging.ZipPackage Package { get { return (_package); } }
626        ExcelEncryption _encryption=null;
627        /// <summary>
628        /// Information how and if the package is encrypted
629        /// </summary>
630        public ExcelEncryption Encryption
631        {
632            get
633            {
634                if (_encryption == null)
635                {
636                    _encryption = new ExcelEncryption();
637                }
638                return _encryption;
639            }
640        }
641    /// <summary>
642    /// Returns a reference to the workbook component within the package.
643    /// All worksheets and cells can be accessed through the workbook.
644    /// </summary>
645    public ExcelWorkbook Workbook
646    {
647      get
648      {
649                if (_workbook == null)
650                {
651                    var nsm = CreateDefaultNSM();
652
653                    _workbook = new ExcelWorkbook(this, nsm);
654
655                    _workbook.GetExternalReferences();
656                    _workbook.GetDefinedNames();
657
658                }
659                return (_workbook);
660      }
661    }
662        /// <summary>
663        /// Automaticlly adjust drawing size when column width/row height are adjusted, depending on the drawings editBy property.
664        /// Default True
665        /// </summary>
666        public bool DoAdjustDrawings
667        {
668            get;
669            set;
670        }
671        private XmlNamespaceManager CreateDefaultNSM()
672        {
673            //  Create a NamespaceManager to handle the default namespace,
674            //  and create a prefix for the default namespace:
675            NameTable nt = new NameTable();
676            var ns = new XmlNamespaceManager(nt);
677            ns.AddNamespace(string.Empty, ExcelPackage.schemaMain);
678            ns.AddNamespace("d", ExcelPackage.schemaMain);
679            ns.AddNamespace("r", ExcelPackage.schemaRelationships);
680            ns.AddNamespace("c", ExcelPackage.schemaChart);
681            ns.AddNamespace("vt", schemaVt);
682            // extended properties (app.xml)
683            ns.AddNamespace("xp", schemaExtended);
684            // custom properties
685            ns.AddNamespace("ctp", schemaCustom);
686            // core properties
687            ns.AddNamespace("cp", schemaCore);
688            // core property namespaces
689            ns.AddNamespace("dc", schemaDc);
690            ns.AddNamespace("dcterms", schemaDcTerms);
691            ns.AddNamespace("dcmitype", schemaDcmiType);
692            ns.AddNamespace("xsi", schemaXsi);
693            return ns;
694        }
695   
696    #region SavePart
697    /// <summary>
698    /// Saves the XmlDocument into the package at the specified Uri.
699    /// </summary>
700    /// <param name="uri">The Uri of the component</param>
701    /// <param name="xmlDoc">The XmlDocument to save</param>
702    internal void SavePart(Uri uri, XmlDocument xmlDoc)
703    {
704            Packaging.ZipPackagePart part = _package.GetPart(uri);
705      xmlDoc.Save(part.GetStream(FileMode.Create, FileAccess.Write));
706    }
707        /// <summary>
708    /// Saves the XmlDocument into the package at the specified Uri.
709    /// </summary>
710    /// <param name="uri">The Uri of the component</param>
711    /// <param name="xmlDoc">The XmlDocument to save</param>
712        internal void SaveWorkbook(Uri uri, XmlDocument xmlDoc)
713    {
714            Packaging.ZipPackagePart part = _package.GetPart(uri);
715            if(Workbook.VbaProject==null)
716            {
717                if (part.ContentType != contentTypeWorkbookDefault)
718                {
719                    part = _package.CreatePart(uri, contentTypeWorkbookDefault, Compression);
720                }
721            }
722            else
723            {
724                if (part.ContentType != contentTypeWorkbookMacroEnabled)
725                {
726                    var rels = part.GetRelationships();
727                    _package.DeletePart(uri);
728                    part = Package.CreatePart(uri, contentTypeWorkbookMacroEnabled);
729                    foreach (var rel in rels)
730                    {
731                        Package.DeleteRelationship(rel.Id);
732                        part.CreateRelationship(rel.TargetUri, rel.TargetMode, rel.RelationshipType);
733                    }
734                }
735            }
736      xmlDoc.Save(part.GetStream(FileMode.Create, FileAccess.Write));
737    }
738
739        #endregion
740
741    #region Dispose
742    /// <summary>
743    /// Closes the package.
744    /// </summary>
745    public void Dispose()
746    {
747            if(_package != null)
748            {
749                if (_isExternalStream==false && Stream != null && (Stream.CanRead || Stream.CanWrite))
750                {
751                    Stream.Close();
752                }
753                _package.Close();
754                if(_isExternalStream==false) ((IDisposable)_stream).Dispose();
755                if(_workbook != null)
756                {
757                    _workbook.Dispose();
758                }
759                _package = null;
760                _images = null;
761                _file = null;
762                _workbook = null;
763                _stream = null;
764                _workbook = null;
765            }
766    }
767    #endregion
768
769    #region Save  // ExcelPackage save
770        /// <summary>
771        /// Saves all the components back into the package.
772        /// This method recursively calls the Save method on all sub-components.
773        /// We close the package after the save is done.
774        /// </summary>
775        public void Save()
776        {
777            try
778            {
779                Workbook.Save();
780                if (File == null)
781                {
782                    if(Encryption.IsEncrypted)
783                    {
784#if !MONO
785                        var ms = new MemoryStream();
786                        _package.Save(ms);
787                        byte[] file = ms.ToArray();
788                        EncryptedPackageHandler eph = new EncryptedPackageHandler();
789                        var msEnc = eph.EncryptPackage(file, Encryption);
790                        CopyStream(msEnc, ref _stream);
791#endif
792#if MONO
793                        throw new NotSupportedException("Encryption is not supported under Mono.");
794#endif
795                    }
796                    else
797                    {
798                        _package.Save(_stream);
799                    }
800                    _stream.Flush();
801                    _package.Close();
802                }
803                else
804                {
805                    if (System.IO.File.Exists(File.FullName))
806                    {
807                        try
808                        {
809                            System.IO.File.Delete(File.FullName);
810                        }
811                        catch (Exception ex)
812                        {
813                            throw (new Exception(string.Format("Error overwriting file {0}", File.FullName), ex));
814                        }
815                    }
816
817                    _package.Save(_stream);
818                    _package.Close();
819                    if (Stream is MemoryStream)
820                    {
821                        var fi = new FileStream(File.FullName, FileMode.Create);
822                        //EncryptPackage
823                        if (Encryption.IsEncrypted)
824                        {
825#if !MONO
826                            byte[] file = ((MemoryStream)Stream).ToArray();
827                            EncryptedPackageHandler eph = new EncryptedPackageHandler();
828                            var ms = eph.EncryptPackage(file, Encryption);
829
830                            fi.Write(ms.GetBuffer(), 0, (int)ms.Length);
831#endif
832#if MONO
833                            throw new NotSupportedException("Encryption is not supported under Mono.");
834#endif
835                        }
836                        else
837                        {                           
838                            fi.Write(((MemoryStream)Stream).GetBuffer(), 0, (int)Stream.Length);
839                        }
840                        fi.Close();
841                    }
842                    else
843                    {
844                        System.IO.File.WriteAllBytes(File.FullName, GetAsByteArray(false));
845                    }
846                }
847            }
848            catch (Exception ex)
849            {
850                if (File == null)
851                {
852                    throw;
853                }
854                else
855                {
856                    throw (new InvalidOperationException(string.Format("Error saving file {0}", File.FullName), ex));
857                }
858            }
859        }
860        /// <summary>
861        /// Saves all the components back into the package.
862        /// This method recursively calls the Save method on all sub-components.
863        /// The package is closed after it ha
864        /// d to encrypt the workbook with.
865        /// </summary>
866        /// <param name="password">This parameter overrides the Workbook.Encryption.Password.</param>
867        public void Save(string password)
868    {
869            Encryption.Password = password;
870            Save();
871        }
872        /// <summary>
873        /// Saves the workbook to a new file
874        /// The package is closed after it has been saved       
875        /// </summary>
876        /// <param name="file">The file location</param>
877        public void SaveAs(FileInfo file)
878        {
879            File = file;
880            Save();
881        }
882        /// <summary>
883        /// Saves the workbook to a new file
884        /// The package is closed after it has been saved
885        /// </summary>
886        /// <param name="file">The file</param>
887        /// <param name="password">The password to encrypt the workbook with.
888        /// This parameter overrides the Encryption.Password.</param>
889        public void SaveAs(FileInfo file, string password)
890        {
891            File = file;
892            Encryption.Password = password;
893            Save();
894        }
895        /// <summary>
896        /// Copies the Package to the Outstream
897        /// The package is closed after it has been saved
898        /// </summary>
899        /// <param name="OutputStream">The stream to copy the package to</param>
900        public void SaveAs(Stream OutputStream)
901        {
902            File = null;
903            Save();
904
905            if (OutputStream != _stream)
906            {
907                if (Encryption.IsEncrypted)
908                {
909#if !MONO
910                    //Encrypt Workbook
911                    Byte[] file = new byte[Stream.Length];
912                    long pos = Stream.Position;
913                    Stream.Seek(0, SeekOrigin.Begin);
914                    Stream.Read(file, 0, (int) Stream.Length);
915                    EncryptedPackageHandler eph = new EncryptedPackageHandler();
916                    var ms = eph.EncryptPackage(file, Encryption);
917                    CopyStream(ms, ref OutputStream);
918#endif
919#if MONO
920                throw new NotSupportedException("Encryption is not supported under Mono.");
921#endif
922                }
923                else
924                {
925                    CopyStream(_stream, ref OutputStream);
926                }
927            }
928        }
929        /// <summary>
930        /// Copies the Package to the Outstream
931        /// The package is closed after it has been saved
932        /// </summary>
933        /// <param name="OutputStream">The stream to copy the package to</param>
934        /// <param name="password">The password to encrypt the workbook with.
935        /// This parameter overrides the Encryption.Password.</param>
936        public void SaveAs(Stream OutputStream, string password)
937        {
938            Encryption.Password = password;
939            SaveAs(OutputStream);
940        }
941        FileInfo _file = null;
942
943        /// <summary>
944        /// The output file. Null if no file is used
945        /// </summary>
946        public FileInfo File
947        {
948            get
949            {
950                return _file;
951            }
952            set
953            {
954                _file = value;
955            }
956        }
957        /// <summary>
958        /// The output stream. This stream is the not the encrypted package.
959        /// To get the encrypted package use the SaveAs(stream) method.
960        /// </summary>
961        public Stream Stream
962        {
963            get
964            {
965                return _stream;
966            }
967        }
968    #endregion
969        /// <summary>
970        /// Compression option for the package
971        /// </summary>       
972        public CompressionLevel Compression
973        {
974            get
975            {
976                return Package.Compression;
977            }
978            set
979            {
980                Package.Compression = value;
981            }
982        }
983    #region GetXmlFromUri
984    /// <summary>
985    /// Get the XmlDocument from an URI
986    /// </summary>
987    /// <param name="uri">The Uri to the part</param>
988    /// <returns>The XmlDocument</returns>
989    internal XmlDocument GetXmlFromUri(Uri uri)
990    {
991      XmlDocument xml = new XmlDocument();
992      Packaging.ZipPackagePart part = _package.GetPart(uri);
993            XmlHelper.LoadXmlSafe(xml, part.GetStream());
994      return (xml);
995    }
996    #endregion
997
998        /// <summary>
999        /// Saves and returns the Excel files as a bytearray.
1000        /// Note that the package is closed upon save
1001        /// </summary>
1002        /// <example>     
1003        /// Example how to return a document from a Webserver...
1004        /// <code>
1005        ///  ExcelPackage package=new ExcelPackage();
1006        ///  /**** ... Create the document ****/
1007        ///  Byte[] bin = package.GetAsByteArray();
1008        ///  Response.ContentType = "Application/vnd.ms-Excel";
1009        ///  Response.AddHeader("content-disposition", "attachment;  filename=TheFile.xlsx");
1010    ///  Response.BinaryWrite(bin);
1011        /// </code>
1012        /// </example>
1013        /// <returns></returns>
1014        public byte[] GetAsByteArray()
1015        {
1016           return GetAsByteArray(true);
1017        }
1018        /// <summary>
1019        /// Saves and returns the Excel files as a bytearray
1020        /// Note that the package is closed upon save
1021        /// </summary>
1022        /// <example>     
1023        /// Example how to return a document from a Webserver...
1024        /// <code>
1025        ///  ExcelPackage package=new ExcelPackage();
1026        ///  /**** ... Create the document ****/
1027        ///  Byte[] bin = package.GetAsByteArray();
1028        ///  Response.ContentType = "Application/vnd.ms-Excel";
1029        ///  Response.AddHeader("content-disposition", "attachment;  filename=TheFile.xlsx");
1030        ///  Response.BinaryWrite(bin);
1031        /// </code>
1032        /// </example>
1033        /// <param name="password">The password to encrypt the workbook with.
1034        /// This parameter overrides the Encryption.Password.</param>
1035        /// <returns></returns>
1036        public byte[] GetAsByteArray(string password)
1037        {
1038            if (password != null)
1039            {
1040                Encryption.Password = password;
1041            }
1042            return GetAsByteArray(true);
1043        }
1044        internal byte[] GetAsByteArray(bool save)
1045        {
1046            if (save)
1047            {
1048                Workbook.Save();
1049                _package.Close();
1050                _package.Save(_stream);
1051            }
1052            Byte[] byRet = new byte[Stream.Length];
1053            long pos = Stream.Position;           
1054            Stream.Seek(0, SeekOrigin.Begin);
1055            Stream.Read(byRet, 0, (int)Stream.Length);
1056
1057            //Encrypt Workbook?
1058            if (Encryption.IsEncrypted)
1059            {
1060#if !MONO
1061                EncryptedPackageHandler eph=new EncryptedPackageHandler();
1062                var ms = eph.EncryptPackage(byRet, Encryption);
1063                byRet = ms.ToArray();
1064#endif
1065            }
1066
1067            Stream.Seek(pos, SeekOrigin.Begin);
1068            Stream.Close();
1069            return byRet;
1070        }
1071        /// <summary>
1072        /// Loads the specified package data from a stream.
1073        /// </summary>
1074        /// <param name="input">The input.</param>
1075        public void Load(Stream input)
1076        {
1077            Load(input, new MemoryStream(), null);
1078        }
1079        /// <summary>
1080        /// Loads the specified package data from a stream.
1081        /// </summary>
1082        /// <param name="input">The input.</param>
1083        /// <param name="Password">The password to decrypt the document</param>
1084        public void Load(Stream input, string Password)
1085        {
1086            Load(input, new MemoryStream(), Password);
1087        }
1088        /// <summary>
1089        ///
1090        /// </summary>
1091        /// <param name="input"></param>
1092        /// <param name="output"></param>
1093        /// <param name="Password"></param>
1094        private void Load(Stream input, Stream output, string Password)
1095        {
1096            //Release some resources:
1097            if (this._package != null)
1098            {
1099                this._package.Close();
1100                this._package = null;
1101            }
1102            if (this._stream != null)
1103            {
1104                this._stream.Close();
1105                this._stream.Dispose();
1106                this._stream = null;
1107            }
1108            _isExternalStream = true;
1109            if (input.Length == 0) // Template is blank, Construct new
1110            {
1111                _stream = output;
1112                ConstructNewFile(Password);
1113            }
1114            else
1115            {
1116                Stream ms;
1117                this._stream = output;
1118                if (Password != null)
1119                {
1120#if !MONO
1121                    Stream encrStream = new MemoryStream();
1122                    CopyStream(input, ref encrStream);
1123                    EncryptedPackageHandler eph = new EncryptedPackageHandler();
1124                    Encryption.Password = Password;
1125                    ms = eph.DecryptPackage((MemoryStream)encrStream, Encryption);
1126#endif
1127#if MONO
1128                    throw new NotSupportedException("Encryption is not supported under Mono.");
1129#endif
1130                }
1131                else
1132                {
1133                    ms = new MemoryStream();
1134                    CopyStream(input, ref ms);
1135                }
1136
1137                try
1138                {
1139                    //this._package = Package.Open(this._stream, FileMode.Open, FileAccess.ReadWrite);
1140                    _package = new Packaging.ZipPackage(ms);
1141                }
1142                catch (Exception ex)
1143                {
1144#if !MONO
1145                    EncryptedPackageHandler eph = new EncryptedPackageHandler();
1146                    if (Password == null && CompoundDocument.IsStorageILockBytes(CompoundDocument.GetLockbyte((MemoryStream)_stream)) == 0)
1147                    {
1148                        throw new Exception("Can not open the package. Package is an OLE compound document. If this is an encrypted package, please supply the password", ex);
1149                    }
1150                    else
1151                    {
1152                        throw;
1153                    }
1154#endif
1155#if MONO
1156                    throw;
1157#endif
1158                }
1159            }           
1160            //Clear the workbook so that it gets reinitialized next time
1161            this._workbook = null;
1162        }
1163        static object _lock=new object();
1164        /// <summary>
1165        /// Copies the input stream to the output stream.
1166        /// </summary>
1167        /// <param name="inputStream">The input stream.</param>
1168        /// <param name="outputStream">The output stream.</param>
1169        internal static void CopyStream(Stream inputStream, ref Stream outputStream)
1170        {
1171            if (!inputStream.CanRead)
1172            {
1173                throw (new Exception("Can not read from inputstream"));
1174            }
1175            if (!outputStream.CanWrite)
1176            {
1177                throw (new Exception("Can not write to outputstream"));
1178            }
1179            if (inputStream.CanSeek)
1180            {
1181                inputStream.Seek(0, SeekOrigin.Begin);
1182            }
1183
1184                const int bufferLength = 8096;
1185                var buffer = new Byte[bufferLength];
1186                lock (_lock)
1187                {
1188                    int bytesRead = inputStream.Read(buffer, 0, bufferLength);
1189                    // write the required bytes
1190                    while (bytesRead > 0)
1191                    {
1192                        outputStream.Write(buffer, 0, bytesRead);
1193                        bytesRead = inputStream.Read(buffer, 0, bufferLength);
1194                    }
1195                    outputStream.Flush();
1196            }
1197        }
1198    }
1199}
Note: See TracBrowser for help on using the repository browser.