More cleanup for EPPlus.
- Remove useless Dispose() methods in most places
- Remove Save() and associated methdos from ExcelPackage
- Remove encryption support (this doesn't work anyway on Linux, and we
never bother to supply a password so it is effectively a no-op)
- Clean up a bunch of compiler warnings
Change-Id: Iad5bc0e198514faeb78166f13525f4b9da7e062c
Reviewed-on: https://gnocchi-internal-review.git.corp.google.com/c/third_party/epplus/+/207580
Reviewed-by: Hughes Hilton <hugheshilton@google.com>
diff --git a/EPPlus/CellStore.cs b/EPPlus/CellStore.cs
index 6536325..9e05a06 100644
--- a/EPPlus/CellStore.cs
+++ b/EPPlus/CellStore.cs
@@ -52,7 +52,7 @@
set;
}
}
- internal class ColumnIndex : IndexBase, IDisposable
+ internal class ColumnIndex : IndexBase
{
internal IndexBase _searchIx=new IndexBase();
public ColumnIndex ()
@@ -201,21 +201,9 @@
}
internal PageIndex[] _pages;
internal int PageCount;
-
- public void Dispose()
- {
- if (_pages != null)
- {
- for (int p = 0; p < PageCount; p++)
- {
- ((IDisposable)_pages[p]).Dispose();
- }
- _pages = null;
- }
}
- }
- internal class PageIndex : IndexBase, IDisposable
+ internal class PageIndex : IndexBase
{
internal IndexBase _searchIx = new IndexBase();
public PageIndex()
@@ -319,16 +307,12 @@
{
return IndexOffset + Rows[pos].Index;
}
- public void Dispose()
- {
- Rows = null;
- }
}
/// <summary>
/// This is the store for all Rows, Columns and Cells.
/// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID )
/// </summary>
- internal class CellStore<T> : IDisposable// : IEnumerable<ulong>, IEnumerator<ulong>
+ internal class CellStore<T>
{
/**** Size constants ****/
internal const int pageBits = 10; //13bits=8192 Note: Maximum is 13 bits since short is used (PageMax=16K)
@@ -1431,23 +1415,6 @@
}
}
- public void Dispose()
- {
- if(_values!=null) _values.Clear();
- if (_columnIndex != null)
- {
- for (var c = 0; c < ColumnCount; c++)
- {
- if (_columnIndex[c] != null)
- {
- ((IDisposable)_columnIndex[c]).Dispose();
- }
- }
- }
- _values = null;
- _columnIndex = null;
- }
-
//object IEnumerator.Current
//{
// get
@@ -1942,10 +1909,7 @@
}
}
- public void Dispose()
- {
- //_cellStore=null;
- }
+ public void Dispose() { }
object IEnumerator.Current
{
diff --git a/EPPlus/EPPlusSDK.csproj b/EPPlus/EPPlusSDK.csproj
index 9203ac9..c81fe9a 100644
--- a/EPPlus/EPPlusSDK.csproj
+++ b/EPPlus/EPPlusSDK.csproj
@@ -4,7 +4,7 @@
<RootNamespace>OfficeOpenXml</RootNamespace>
<AssemblyName>EPPlus</AssemblyName>
<PackageId>Appsheet.EPPlus</PackageId>
- <Version>1.0.4</Version>
+ <Version>1.0.5</Version>
<DefaultItemExcludes>$(DefaultItemExcludes);Properties/AssemblyInfo.cs;FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/**;FormulaParsing/LexicalAnalysis/TokenHandler.cs;FormulaParsing/Excel/Functions/Math/Rank.cs</DefaultItemExcludes>
<DefineConstants>Core;STANDARD20</DefineConstants>
<ImplicitUsings>disable</ImplicitUsings>
diff --git a/EPPlus/Encryption/EncryptionHandler.cs b/EPPlus/Encryption/EncryptionHandler.cs
deleted file mode 100644
index 11853da..0000000
--- a/EPPlus/Encryption/EncryptionHandler.cs
+++ /dev/null
@@ -1,997 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011 Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author Change Date
- * ******************************************************************************
- * Jan Källman Added 2013-01-05
- *******************************************************************************/
-using OfficeOpenXml.Utils;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Security;
-using System.Security.Cryptography;
-using System.Text;
-using System.Xml;
-using comTypes = System.Runtime.InteropServices.ComTypes;
-
-namespace OfficeOpenXml.Encryption
-{
-
- /// <summary>
- /// Handels encrypted Excel documents
- /// </summary>
- internal class EncryptedPackageHandler
- {
-#if !MONO
- /// <summary>
- /// Read the package from the OLE document and decrypt it using the supplied password
- /// </summary>
- /// <param name="fi">The file</param>
- /// <param name="encryption"></param>
- /// <returns></returns>
- internal MemoryStream DecryptPackage(FileInfo fi, ExcelEncryption encryption)
- {
- CompoundDocument doc = new CompoundDocument(fi);
-
- MemoryStream ret = null;
- if (CompoundDocument.IsStorageFile(fi.FullName) == 0)
- {
- ret = GetStreamFromPackage(doc, encryption);
- }
- else
- {
- throw (new InvalidDataException(string.Format("File {0} is not an encrypted package", fi.FullName)));
- }
- return ret;
- }
-
- //Helpmethod to output the streams in the storage
- //private void WriteDoc(CompoundDocument.StoragePart storagePart, string p)
- //{
- // foreach (var store in storagePart.SubStorage)
- // {
- // string sdir=p + store.Key.Replace((char)6,'x') + "\\";
- // Directory.CreateDirectory(sdir);
- // WriteDoc(store.Value, sdir);
- // }
- // foreach (var str in storagePart.DataStreams)
- // {
- // File.WriteAllBytes(p + str.Key.Replace((char)6, 'x') + ".bin", str.Value);
- // }
- //}
- /// <summary>
- /// Read the package from the OLE document and decrypt it using the supplied password
- /// </summary>
- /// <param name="stream">The memory stream. </param>
- /// <param name="encryption">The encryption object from the Package</param>
- /// <returns></returns>
- [SecuritySafeCritical]
- internal MemoryStream DecryptPackage(MemoryStream stream, ExcelEncryption encryption)
- {
- //Create the lockBytes object.
- CompoundDocument.ILockBytes lb=null;
- try
- {
- lb = CompoundDocument.GetLockbyte(stream);
-
- if (CompoundDocument.IsStorageILockBytes(lb) == 0)
- {
- var doc = new CompoundDocument(lb);
- return GetStreamFromPackage(doc, encryption);
- }
- else
- {
- Marshal.ReleaseComObject(lb);
- throw (new InvalidDataException("The stream is not an valid/supported encrypted document."));
- }
- }
- catch// (Exception ex)
- {
- throw;
- }
- finally
- {
- Marshal.ReleaseComObject(lb);
- lb = null;
- }
-
- }
- /// <summary>
- /// Encrypts a package
- /// </summary>
- /// <param name="package">The package as a byte array</param>
- /// <param name="encryption">The encryption info from the workbook</param>
- /// <returns></returns>
- internal MemoryStream EncryptPackage(byte[] package, ExcelEncryption encryption)
- {
- if (encryption.Version == EncryptionVersion.Standard) //Standard encryption
- {
- return EncryptPackageBinary(package, encryption);
- }
- else if (encryption.Version == EncryptionVersion.Agile) //Agile encryption
- {
- return EncryptPackageAgile(package, encryption);
- }
- throw(new ArgumentException("Unsupported encryption version."));
- }
-
- private MemoryStream EncryptPackageAgile(byte[] package, ExcelEncryption encryption)
- {
- var xml= "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n";
- xml += "<encryption xmlns=\"http://schemas.microsoft.com/office/2006/encryption\" xmlns:p=\"http://schemas.microsoft.com/office/2006/keyEncryptor/password\" xmlns:c=\"http://schemas.microsoft.com/office/2006/keyEncryptor/certificate\">";
- xml += "<keyData saltSize=\"16\" blockSize=\"16\" keyBits=\"256\" hashSize=\"64\" cipherAlgorithm=\"AES\" cipherChaining=\"ChainingModeCBC\" hashAlgorithm=\"SHA512\" saltValue=\"\"/>";
- xml += "<dataIntegrity encryptedHmacKey=\"\" encryptedHmacValue=\"\"/>";
- xml += "<keyEncryptors>";
- xml += "<keyEncryptor uri=\"http://schemas.microsoft.com/office/2006/keyEncryptor/password\">";
- xml += "<p:encryptedKey spinCount=\"100000\" saltSize=\"16\" blockSize=\"16\" keyBits=\"256\" hashSize=\"64\" cipherAlgorithm=\"AES\" cipherChaining=\"ChainingModeCBC\" hashAlgorithm=\"SHA512\" saltValue=\"\" encryptedVerifierHashInput=\"\" encryptedVerifierHashValue=\"\" encryptedKeyValue=\"\" />";
- xml += "</keyEncryptor></keyEncryptors></encryption>";
-
- var encryptionInfo = new EncryptionInfoAgile();
- encryptionInfo.ReadFromXml(xml);
- var encr = encryptionInfo.KeyEncryptors[0];
- var rnd = RandomNumberGenerator.Create();
-
- var s = new byte[16];
- rnd.GetBytes(s);
- encryptionInfo.KeyData.SaltValue = s;
-
- rnd.GetBytes(s);
- encr.SaltValue = s;
-
- encr.KeyValue = new byte[encr.KeyBits / 8];
- rnd.GetBytes(encr.KeyValue);
-
- //Get the passwork key.
- var hashProvider = GetHashProvider(encryptionInfo.KeyEncryptors[0]);
- var baseHash = GetPasswordHash(hashProvider, encr.SaltValue, encryption.Password, encr.SpinCount, encr.HashSize);
- var hashFinal = GetFinalHash(hashProvider, encr, BlockKey_KeyValue, baseHash);
- hashFinal = FixHashSize(hashFinal, encr.KeyBits / 8);
-
- var encrData = EncryptDataAgile(package, encryptionInfo, hashProvider);
-
- /**** Data Integrity ****/
- var saltHMAC=new byte[64];
- rnd.GetBytes(saltHMAC);
-
- SetHMAC(encryptionInfo,hashProvider,saltHMAC, encrData);
-
- /**** Verifier ****/
- encr.VerifierHashInput = new byte[16];
- rnd.GetBytes(encr.VerifierHashInput);
-
- encr.VerifierHash = hashProvider.ComputeHash(encr.VerifierHashInput);
-
- var VerifierInputKey = GetFinalHash(hashProvider, encr, BlockKey_HashInput, baseHash);
- var VerifierHashKey = GetFinalHash(hashProvider, encr, BlockKey_HashValue, baseHash);
- var KeyValueKey = GetFinalHash(hashProvider, encr, BlockKey_KeyValue, baseHash);
-
- var ms = new MemoryStream();
- EncryptAgileFromKey(encr, VerifierInputKey, encr.VerifierHashInput, 0, encr.VerifierHashInput.Length, encr.SaltValue, ms);
- encr.EncryptedVerifierHashInput = ms.ToArray();
-
- ms = new MemoryStream();
- EncryptAgileFromKey(encr, VerifierHashKey, encr.VerifierHash, 0, encr.VerifierHash.Length, encr.SaltValue, ms);
- encr.EncryptedVerifierHash = ms.ToArray();
-
- ms = new MemoryStream();
- EncryptAgileFromKey(encr, KeyValueKey, encr.KeyValue, 0, encr.KeyValue.Length, encr.SaltValue, ms);
- encr.EncryptedKeyValue = ms.ToArray();
-
- xml = encryptionInfo.Xml.OuterXml;
-
- var byXml = Encoding.UTF8.GetBytes(xml);
-
- ms = new MemoryStream();
- ms.Write(BitConverter.GetBytes((ushort)4), 0, 2); //Major Version
- ms.Write(BitConverter.GetBytes((ushort)4), 0, 2); //Minor Version
- ms.Write(BitConverter.GetBytes((uint)0x40), 0, 4); //Reserved
- ms.Write(byXml,0,byXml.Length);
-
- var doc = new CompoundDocument();
-
- //Add the dataspace streams
- CreateDataSpaces(doc);
- //EncryptionInfo...
- doc.Storage.DataStreams.Add("EncryptionInfo", ms.ToArray());
- //...and the encrypted package
- doc.Storage.DataStreams.Add("EncryptedPackage", encrData);
-
- ms = new MemoryStream();
- var e=doc.Save();
- ms.Write(e,0,e.Length);
- return ms;
- }
-
- private byte[] EncryptDataAgile(byte[] data, EncryptionInfoAgile encryptionInfo, HashAlgorithm hashProvider)
- {
- var ke = encryptionInfo.KeyEncryptors[0];
- RijndaelManaged aes = new RijndaelManaged();
- aes.KeySize = ke.KeyBits;
- aes.Mode = CipherMode.CBC;
- aes.Padding = PaddingMode.Zeros;
-
- int pos=0;
- int segment=0;
-
- //Encrypt the data
- var ms = new MemoryStream();
- ms.Write(BitConverter.GetBytes(data.LongLength), 0, 8);
- while (pos < data.Length)
- {
- var segmentSize = (int)(data.Length - pos > 4096 ? 4096 : data.Length - pos);
-
- var ivTmp = new byte[4 + encryptionInfo.KeyData.SaltSize];
- Array.Copy(encryptionInfo.KeyData.SaltValue, 0, ivTmp, 0, encryptionInfo.KeyData.SaltSize);
- Array.Copy(BitConverter.GetBytes(segment), 0, ivTmp, encryptionInfo.KeyData.SaltSize, 4);
- var iv=hashProvider.ComputeHash(ivTmp);
-
- EncryptAgileFromKey(ke, ke.KeyValue, data, pos, segmentSize, iv, ms);
- pos += segmentSize;
- segment++;
- }
- ms.Flush();
- return ms.ToArray();
- }
- // Set the dataintegrity
- private void SetHMAC(EncryptionInfoAgile ei, HashAlgorithm hashProvider, byte[] salt, byte[] data)
- {
- var iv = GetFinalHash(hashProvider, ei.KeyEncryptors[0], BlockKey_HmacKey, ei.KeyData.SaltValue);
- var ms = new MemoryStream();
- EncryptAgileFromKey(ei.KeyEncryptors[0], ei.KeyEncryptors[0].KeyValue, salt, 0L, salt.LongLength, iv, ms);
- ei.DataIntegrity.EncryptedHmacKey = ms.ToArray();
-
- var h = GetHmacProvider(ei.KeyEncryptors[0], salt);
- var hmacValue = h.ComputeHash(data);
-
- ms = new MemoryStream();
- iv = GetFinalHash(hashProvider, ei.KeyEncryptors[0], BlockKey_HmacValue, ei.KeyData.SaltValue);
- EncryptAgileFromKey(ei.KeyEncryptors[0], ei.KeyEncryptors[0].KeyValue, hmacValue, 0L, hmacValue.LongLength, iv, ms);
- ei.DataIntegrity.EncryptedHmacValue = ms.ToArray();
- }
-
- private HMAC GetHmacProvider(EncryptionInfoAgile.EncryptionKeyEncryptor ei, byte[] salt)
- {
- switch (ei.HashAlgorithm)
- {
- case eHashAlogorithm.MD5:
- return new HMACMD5(salt);
- case eHashAlogorithm.SHA1:
- return new HMACSHA1(salt);
- case eHashAlogorithm.SHA256:
- return new HMACSHA256(salt);
- case eHashAlogorithm.SHA384:
- return new HMACSHA384(salt);
- case eHashAlogorithm.SHA512:
- return new HMACSHA512(salt);
- default:
- throw(new NotSupportedException(string.Format("Hash method {0} not supported.",ei.HashAlgorithm)));
- }
- }
-
- private MemoryStream EncryptPackageBinary(byte[] package, ExcelEncryption encryption)
- {
- byte[] encryptionKey;
- //Create the Encryption Info. This also returns the Encryptionkey
- var encryptionInfo = CreateEncryptionInfo(encryption.Password,
- encryption.Algorithm == EncryptionAlgorithm.AES128 ?
- AlgorithmID.AES128 :
- encryption.Algorithm == EncryptionAlgorithm.AES192 ?
- AlgorithmID.AES192 :
- AlgorithmID.AES256, out encryptionKey);
-
- //ILockBytes lb;
- //var iret = CreateILockBytesOnHGlobal(IntPtr.Zero, true, out lb);
-
- //IStorage storage = null;
- //MemoryStream ret = null;
-
- var doc = new CompoundDocument();
- CreateDataSpaces(doc);
-
- doc.Storage.DataStreams.Add("EncryptionInfo", encryptionInfo.WriteBinary());
-
- //Encrypt the package
- byte[] encryptedPackage = EncryptData(encryptionKey, package, false);
- MemoryStream ms = new MemoryStream();
- ms.Write(BitConverter.GetBytes((ulong)package.LongLength), 0, 8);
- ms.Write(encryptedPackage, 0, encryptedPackage.Length);
- doc.Storage.DataStreams.Add("EncryptedPackage", ms.ToArray());
-
- var ret = new MemoryStream();
- var buffer = doc.Save();
- ret.Write(buffer, 0, buffer.Length);
-
- return ret;
- }
- #region "Dataspaces Stream methods"
- private void CreateDataSpaces(CompoundDocument doc)
- {
- var ds = new CompoundDocument.StoragePart();
- doc.Storage.SubStorage.Add("\x06" + "DataSpaces", ds);
- var ver=new CompoundDocument.StoragePart();
- ds.DataStreams.Add("Version", CreateVersionStream());
- ds.DataStreams.Add("DataSpaceMap", CreateDataSpaceMap());
-
- var dsInfo=new CompoundDocument.StoragePart();
- ds.SubStorage.Add("DataSpaceInfo", dsInfo);
- dsInfo.DataStreams.Add("StrongEncryptionDataSpace", CreateStrongEncryptionDataSpaceStream());
-
- var transInfo=new CompoundDocument.StoragePart();
- ds.SubStorage.Add("TransformInfo", transInfo);
-
- var strEncTrans=new CompoundDocument.StoragePart();
- transInfo.SubStorage.Add("StrongEncryptionTransform", strEncTrans);
-
- strEncTrans.DataStreams.Add("\x06Primary", CreateTransformInfoPrimary());
- }
- private byte[] CreateStrongEncryptionDataSpaceStream()
- {
- MemoryStream ms = new MemoryStream();
- BinaryWriter bw = new BinaryWriter(ms);
-
- bw.Write((int)8); //HeaderLength
- bw.Write((int)1); //EntryCount
-
- string tr = "StrongEncryptionTransform";
- bw.Write((int)tr.Length*2);
- bw.Write(UTF8Encoding.Unicode.GetBytes(tr + "\0")); // end \0 is for padding
-
- bw.Flush();
- return ms.ToArray();
- }
- private byte[] CreateVersionStream()
- {
- MemoryStream ms = new MemoryStream();
- BinaryWriter bw = new BinaryWriter(ms);
-
- bw.Write((short)0x3C); //Major
- bw.Write((short)0); //Minor
- bw.Write(UTF8Encoding.Unicode.GetBytes("Microsoft.Container.DataSpaces"));
- bw.Write((int)1); //ReaderVersion
- bw.Write((int)1); //UpdaterVersion
- bw.Write((int)1); //WriterVersion
-
- bw.Flush();
- return ms.ToArray();
- }
- private byte[] CreateDataSpaceMap()
- {
- MemoryStream ms = new MemoryStream();
- BinaryWriter bw = new BinaryWriter(ms);
-
- bw.Write((int)8); //HeaderLength
- bw.Write((int)1); //EntryCount
- string s1 = "EncryptedPackage";
- string s2 = "StrongEncryptionDataSpace";
- bw.Write((int)(s1.Length + s2.Length)*2 + 0x16);
- bw.Write((int)1); //ReferenceComponentCount
- bw.Write((int)0); //Stream=0
- bw.Write((int)s1.Length * 2); //Length s1
- bw.Write(UTF8Encoding.Unicode.GetBytes(s1));
- bw.Write((int)(s2.Length * 2)); //Length s2
- bw.Write(UTF8Encoding.Unicode.GetBytes(s2 + "\0")); // end \0 is for padding
-
- bw.Flush();
- return ms.ToArray();
- }
- private byte[] CreateTransformInfoPrimary()
- {
- MemoryStream ms = new MemoryStream();
- BinaryWriter bw = new BinaryWriter(ms);
- string TransformID = "{FF9A3F03-56EF-4613-BDD5-5A41C1D07246}";
- string TransformName = "Microsoft.Container.EncryptionTransform";
- bw.Write(TransformID.Length * 2 + 12);
- bw.Write((int)1);
- bw.Write(TransformID.Length * 2);
- bw.Write(UTF8Encoding.Unicode.GetBytes(TransformID));
- bw.Write(TransformName.Length * 2);
- bw.Write(UTF8Encoding.Unicode.GetBytes(TransformName + "\0"));
- bw.Write((int)1); //ReaderVersion
- bw.Write((int)1); //UpdaterVersion
- bw.Write((int)1); //WriterVersion
-
- bw.Write((int)0);
- bw.Write((int)0);
- bw.Write((int)0); //CipherMode
- bw.Write((int)4); //Reserved
-
- bw.Flush();
- return ms.ToArray();
- }
- #endregion
- /// <summary>
- /// Create an EncryptionInfo object to encrypt a workbook
- /// </summary>
- /// <param name="password">The password</param>
- /// <param name="algID"></param>
- /// <param name="key">The Encryption key</param>
- /// <returns></returns>
- private EncryptionInfoBinary CreateEncryptionInfo(string password, AlgorithmID algID, out byte[] key)
- {
- if (algID == AlgorithmID.Flags || algID == AlgorithmID.RC4)
- {
- throw (new ArgumentException("algID must be AES128, AES192 or AES256"));
- }
- var encryptionInfo = new EncryptionInfoBinary();
- encryptionInfo.MajorVersion = 4;
- encryptionInfo.MinorVersion = 2;
- encryptionInfo.Flags = Flags.fAES | Flags.fCryptoAPI;
-
- //Header
- encryptionInfo.Header = new EncryptionHeader();
- encryptionInfo.Header.AlgID = algID;
- encryptionInfo.Header.AlgIDHash = AlgorithmHashID.SHA1;
- encryptionInfo.Header.Flags = encryptionInfo.Flags;
- encryptionInfo.Header.KeySize =
- (algID == AlgorithmID.AES128 ? 0x80 : algID == AlgorithmID.AES192 ? 0xC0 : 0x100);
- encryptionInfo.Header.ProviderType = ProviderType.AES;
- encryptionInfo.Header.CSPName = "Microsoft Enhanced RSA and AES Cryptographic Provider\0";
- encryptionInfo.Header.Reserved1 = 0;
- encryptionInfo.Header.Reserved2 = 0;
- encryptionInfo.Header.SizeExtra = 0;
-
- //Verifier
- encryptionInfo.Verifier = new EncryptionVerifier();
- encryptionInfo.Verifier.Salt = new byte[16];
-
- var rnd = RandomNumberGenerator.Create();
- rnd.GetBytes(encryptionInfo.Verifier.Salt);
- encryptionInfo.Verifier.SaltSize = 0x10;
-
- key = GetPasswordHashBinary(password, encryptionInfo);
-
- var verifier = new byte[16];
- rnd.GetBytes(verifier);
- encryptionInfo.Verifier.EncryptedVerifier = EncryptData(key, verifier, true);
-
- //AES = 32 Bits
- encryptionInfo.Verifier.VerifierHashSize = 0x20;
- SHA1 sha = new SHA1Managed();
- var verifierHash = sha.ComputeHash(verifier);
-
- encryptionInfo.Verifier.EncryptedVerifierHash = EncryptData(key, verifierHash, false);
-
- return encryptionInfo;
- }
- private byte[] EncryptData(byte[] key, byte[] data, bool useDataSize)
- {
- RijndaelManaged aes = new RijndaelManaged();
- aes.KeySize = key.Length * 8;
- aes.Mode = CipherMode.ECB;
- aes.Padding = PaddingMode.Zeros;
-
- //Encrypt the data
- var crypt = aes.CreateEncryptor(key, null);
- var ms = new MemoryStream();
- var cs = new CryptoStream(ms, crypt, CryptoStreamMode.Write);
- cs.Write(data, 0, data.Length);
-
- cs.FlushFinalBlock();
-
- byte[] ret;
- if (useDataSize)
- {
- ret = new byte[data.Length];
- ms.Seek(0, SeekOrigin.Begin);
- ms.Read(ret, 0, data.Length); //Truncate any padded Zeros
- return ret;
- }
- else
- {
- return ms.ToArray();
- }
- }
- private MemoryStream GetStreamFromPackage(CompoundDocument doc, ExcelEncryption encryption)
- {
- var ret = new MemoryStream();
- if(doc.Storage.DataStreams.ContainsKey("EncryptionInfo") ||
- doc.Storage.DataStreams.ContainsKey("EncryptedPackage"))
- {
- var encryptionInfo = EncryptionInfo.ReadBinary(doc.Storage.DataStreams["EncryptionInfo"]);
-
- return DecryptDocument(doc.Storage.DataStreams["EncryptedPackage"], encryptionInfo, encryption.Password);
- }
- else
- {
- throw (new InvalidDataException("Invalid document. EncryptionInfo or EncryptedPackage stream is missing"));
- }
- }
-
- /// <summary>
- /// Decrypt a document
- /// </summary>
- /// <param name="data">The Encrypted data</param>
- /// <param name="encryptionInfo">Encryption Info object</param>
- /// <param name="password">The password</param>
- /// <returns></returns>
- private MemoryStream DecryptDocument(byte[] data, EncryptionInfo encryptionInfo, string password)
- {
- long size = BitConverter.ToInt64(data, 0);
-
- var encryptedData = new byte[data.Length - 8];
- Array.Copy(data, 8, encryptedData, 0, encryptedData.Length);
-
- if (encryptionInfo is EncryptionInfoBinary)
- {
- return DecryptBinary((EncryptionInfoBinary)encryptionInfo, password, size, encryptedData);
- }
- else
- {
- return DecryptAgile((EncryptionInfoAgile)encryptionInfo, password, size, encryptedData, data);
- }
-
- }
-
- readonly byte[] BlockKey_HashInput = new byte[] { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 };
- readonly byte[] BlockKey_HashValue = new byte[] { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e };
- readonly byte[] BlockKey_KeyValue = new byte[] { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 };
- readonly byte[] BlockKey_HmacKey = new byte[] { 0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, 0xf6 };//MSOFFCRYPTO 2.3.4.14 section 3
- readonly byte[] BlockKey_HmacValue = new byte[] { 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, 0x33 };//MSOFFCRYPTO 2.3.4.14 section 5
-
- private MemoryStream DecryptAgile(EncryptionInfoAgile encryptionInfo, string password, long size, byte[] encryptedData, byte[] data)
- {
- MemoryStream doc = new MemoryStream();
-
- if (encryptionInfo.KeyData.CipherAlgorithm == eCipherAlgorithm.AES)
- {
- var encr = encryptionInfo.KeyEncryptors[0];
- var hashProvider = GetHashProvider(encr);
- var baseHash = GetPasswordHash(hashProvider, encr.SaltValue, password, encr.SpinCount, encr.HashSize);
-
- //Get the keys for the verifiers and the key value
- var valInputKey = GetFinalHash(hashProvider, encr, BlockKey_HashInput, baseHash);
- var valHashKey = GetFinalHash(hashProvider, encr, BlockKey_HashValue, baseHash);
- var valKeySizeKey = GetFinalHash(hashProvider, encr, BlockKey_KeyValue, baseHash);
-
- //Decrypt
- encr.VerifierHashInput = DecryptAgileFromKey(encr, valInputKey, encr.EncryptedVerifierHashInput, encr.SaltSize, encr.SaltValue);
- encr.VerifierHash = DecryptAgileFromKey(encr, valHashKey, encr.EncryptedVerifierHash, encr.HashSize, encr.SaltValue);
- encr.KeyValue = DecryptAgileFromKey(encr, valKeySizeKey, encr.EncryptedKeyValue, encr.KeyBits / 8, encr.SaltValue);
-
- if (IsPasswordValid(hashProvider, encr))
- {
- var ivhmac = GetFinalHash(hashProvider, encr, BlockKey_HmacKey, encryptionInfo.KeyData.SaltValue);
- var key = DecryptAgileFromKey(encr, encr.KeyValue, encryptionInfo.DataIntegrity.EncryptedHmacKey, encryptionInfo.KeyData.HashSize, ivhmac);
-
- ivhmac = GetFinalHash(hashProvider, encr, BlockKey_HmacValue, encryptionInfo.KeyData.SaltValue);
- var value = DecryptAgileFromKey(encr, encr.KeyValue, encryptionInfo.DataIntegrity.EncryptedHmacValue, encryptionInfo.KeyData.HashSize, ivhmac);
-
- var hmca = GetHmacProvider(encr, key);
- var v2 = hmca.ComputeHash(data);
-
- for (int i = 0; i < v2.Length; i++)
- {
- if (value[i] != v2[i])
- {
- throw (new Exception("Dataintegrity key missmatch"));
- }
- }
-
- int pos = 0;
- uint segment = 0;
- while (pos < size)
- {
- var segmentSize = (int)(size - pos > 4096 ? 4096 : size - pos);
- var bufferSize = (int)(encryptedData.Length - pos > 4096 ? 4096 : encryptedData.Length - pos);
- var ivTmp = new byte[4 + encryptionInfo.KeyData.SaltSize];
- Array.Copy(encryptionInfo.KeyData.SaltValue, 0, ivTmp, 0, encryptionInfo.KeyData.SaltSize);
- Array.Copy(BitConverter.GetBytes(segment), 0, ivTmp, encryptionInfo.KeyData.SaltSize, 4);
- var iv = hashProvider.ComputeHash(ivTmp);
- var buffer = new byte[bufferSize];
- Array.Copy(encryptedData, pos, buffer, 0, bufferSize);
-
- var b = DecryptAgileFromKey(encr, encr.KeyValue, buffer, segmentSize, iv);
- doc.Write(b, 0, b.Length);
- pos += segmentSize;
- segment++;
- }
- doc.Flush();
- return doc;
- }
- else
- {
- throw (new SecurityException("Invalid password"));
- }
- }
- return null;
- }
- private HashAlgorithm GetHashProvider(EncryptionInfoAgile.EncryptionKeyEncryptor encr)
- {
- switch (encr.HashAlgorithm)
- {
- case eHashAlogorithm.MD5:
- return new MD5CryptoServiceProvider();
- case eHashAlogorithm.SHA1:
- return new SHA1CryptoServiceProvider();
- case eHashAlogorithm.SHA256:
- return new SHA256CryptoServiceProvider();
- case eHashAlogorithm.SHA384:
- return new SHA384CryptoServiceProvider();
- case eHashAlogorithm.SHA512:
- return new SHA512CryptoServiceProvider();
- default:
- throw new NotSupportedException(string.Format("Hash provider is unsupported. {0}", encr.HashAlgorithm));
- }
- }
- private MemoryStream DecryptBinary(EncryptionInfoBinary encryptionInfo, string password, long size, byte[] encryptedData)
- {
- MemoryStream doc = new MemoryStream();
-
- if (encryptionInfo.Header.AlgID == AlgorithmID.AES128 || (encryptionInfo.Header.AlgID == AlgorithmID.Flags && ((encryptionInfo.Flags & (Flags.fAES | Flags.fExternal | Flags.fCryptoAPI)) == (Flags.fAES | Flags.fCryptoAPI)))
- ||
- encryptionInfo.Header.AlgID == AlgorithmID.AES192
- ||
- encryptionInfo.Header.AlgID == AlgorithmID.AES256
- )
- {
- RijndaelManaged decryptKey = new RijndaelManaged();
- decryptKey.KeySize = encryptionInfo.Header.KeySize;
- decryptKey.Mode = CipherMode.ECB;
- decryptKey.Padding = PaddingMode.None;
-
- var key = GetPasswordHashBinary(password, encryptionInfo);
- if (IsPasswordValid(key, encryptionInfo))
- {
- ICryptoTransform decryptor = decryptKey.CreateDecryptor(
- key,
- null);
-
- var dataStream = new MemoryStream(encryptedData);
- var cryptoStream = new CryptoStream(dataStream,
- decryptor,
- CryptoStreamMode.Read);
-
- var decryptedData = new byte[size];
-
- cryptoStream.Read(decryptedData, 0, (int)size);
- doc.Write(decryptedData, 0, (int)size);
- }
- else
- {
- throw (new UnauthorizedAccessException("Invalid password"));
- }
- }
- return doc;
- }
- /// <summary>
- /// Validate the password
- /// </summary>
- /// <param name="key">The encryption key</param>
- /// <param name="encryptionInfo">The encryption info extracted from the ENCRYPTIOINFO stream inside the OLE document</param>
- /// <returns></returns>
- private bool IsPasswordValid(byte[] key, EncryptionInfoBinary encryptionInfo)
- {
- RijndaelManaged decryptKey = new RijndaelManaged();
- decryptKey.KeySize = encryptionInfo.Header.KeySize;
- decryptKey.Mode = CipherMode.ECB;
- decryptKey.Padding = PaddingMode.None;
-
- ICryptoTransform decryptor = decryptKey.CreateDecryptor(
- key,
- null);
-
-
- //Decrypt the verifier
- MemoryStream dataStream = new MemoryStream(encryptionInfo.Verifier.EncryptedVerifier);
- CryptoStream cryptoStream = new CryptoStream(dataStream,
- decryptor,
- CryptoStreamMode.Read);
- var decryptedVerifier = new byte[16];
- cryptoStream.Read(decryptedVerifier, 0, 16);
-
- dataStream = new MemoryStream(encryptionInfo.Verifier.EncryptedVerifierHash);
-
- cryptoStream = new CryptoStream(dataStream,
- decryptor,
- CryptoStreamMode.Read);
-
- //Decrypt the verifier hash
- var decryptedVerifierHash = new byte[16];
- cryptoStream.Read(decryptedVerifierHash, 0, (int)16);
-
- //Get the hash for the decrypted verifier
- var sha = new SHA1Managed();
- var hash = sha.ComputeHash(decryptedVerifier);
-
- //Equal?
- for (int i = 0; i < 16; i++)
- {
- if (hash[i] != decryptedVerifierHash[i])
- {
- return false;
- }
- }
- return true;
- }
- /// <summary>
- /// Validate the password
- /// </summary>
- /// <param name="sha">The hash algorithm</param>
- /// <param name="encr">The encryption info extracted from the ENCRYPTIOINFO stream inside the OLE document</param>
- /// <returns></returns>
- private bool IsPasswordValid(HashAlgorithm sha, EncryptionInfoAgile.EncryptionKeyEncryptor encr)
- {
- var valHash = sha.ComputeHash(encr.VerifierHashInput);
-
- //Equal?
- for (int i = 0; i < valHash.Length; i++)
- {
- if (encr.VerifierHash[i] != valHash[i])
- {
- return false;
- }
- }
- return true;
- }
-
- private byte[] DecryptAgileFromKey(EncryptionInfoAgile.EncryptionKeyEncryptor encr, byte[] key, byte[] encryptedData, long size, byte[] iv)
- {
- SymmetricAlgorithm decryptKey = GetEncryptionAlgorithm(encr);
- decryptKey.BlockSize = encr.BlockSize << 3;
- decryptKey.KeySize = encr.KeyBits;
- decryptKey.Mode = encr.ChiptherChaining == eChainingMode.ChainingModeCBC ? CipherMode.CBC : CipherMode.CFB;
- decryptKey.Padding = PaddingMode.Zeros;
-
- ICryptoTransform decryptor = decryptKey.CreateDecryptor(
- FixHashSize(key, encr.KeyBits / 8),
- FixHashSize(iv, encr.BlockSize, 0x36));
-
-
- MemoryStream dataStream = new MemoryStream(encryptedData);
-
- CryptoStream cryptoStream = new CryptoStream(dataStream,
- decryptor,
- CryptoStreamMode.Read);
-
- var decryptedData = new byte[size];
-
- cryptoStream.Read(decryptedData, 0, (int)size);
- return decryptedData;
- }
-
- private SymmetricAlgorithm GetEncryptionAlgorithm(EncryptionInfoAgile.EncryptionKeyEncryptor encr)
- {
- switch (encr.CipherAlgorithm)
- {
- case eCipherAlgorithm.AES:
- return new RijndaelManaged();
- case eCipherAlgorithm.DES:
- return new DESCryptoServiceProvider();
- case eCipherAlgorithm.TRIPLE_DES:
- case eCipherAlgorithm.TRIPLE_DES_112:
- return new TripleDESCryptoServiceProvider();
- case eCipherAlgorithm.RC2:
- return new RC2CryptoServiceProvider();
- default:
- throw(new NotSupportedException(string.Format("Unsupported Cipher Algorithm: {0}", encr.CipherAlgorithm.ToString())));
- }
- }
- private void EncryptAgileFromKey(EncryptionInfoAgile.EncryptionKeyEncryptor encr, byte[] key, byte[] data, long pos, long size, byte[] iv,MemoryStream ms)
- {
- var encryptKey = GetEncryptionAlgorithm(encr);
- encryptKey.BlockSize = encr.BlockSize << 3;
- encryptKey.KeySize = encr.KeyBits;
- encryptKey.Mode = encr.ChiptherChaining==eChainingMode.ChainingModeCBC ? CipherMode.CBC : CipherMode.CFB;
- encryptKey.Padding = PaddingMode.Zeros;
-
- ICryptoTransform encryptor = encryptKey.CreateEncryptor(
- FixHashSize(key, encr.KeyBits / 8),
- FixHashSize(iv, 16, 0x36));
-
-
- CryptoStream cryptoStream = new CryptoStream(ms,
- encryptor,
- CryptoStreamMode.Write);
-
- var cryptoSize = size % encr.BlockSize == 0 ? size : (size + (encr.BlockSize - (size % encr.BlockSize)));
- var buffer = new byte[size];
- Array.Copy(data, pos, buffer, 0, size);
- cryptoStream.Write(buffer, 0, (int)size);
- while (size % encr.BlockSize != 0)
- {
- cryptoStream.WriteByte(0);
- size++;
- }
- }
-
- /// <summary>
- /// Create the hash.
- /// This method is written with the help of Lyquidity library, many thanks for this nice sample
- /// </summary>
- /// <param name="password">The password</param>
- /// <param name="encryptionInfo">The encryption info extracted from the ENCRYPTIOINFO stream inside the OLE document</param>
- /// <returns>The hash to encrypt the document</returns>
- private byte[] GetPasswordHashBinary(string password, EncryptionInfoBinary encryptionInfo)
- {
- byte[] hash = null;
- byte[] tempHash = new byte[4 + 20]; //Iterator + prev. hash
- try
- {
- HashAlgorithm hashProvider;
- if (encryptionInfo.Header.AlgIDHash == AlgorithmHashID.SHA1 || encryptionInfo.Header.AlgIDHash == AlgorithmHashID.App && (encryptionInfo.Flags & Flags.fExternal) == 0)
- {
- hashProvider = new SHA1CryptoServiceProvider();
- }
- else if (encryptionInfo.Header.KeySize > 0 && encryptionInfo.Header.KeySize < 80)
- {
- throw new NotSupportedException("RC4 Hash provider is not supported. Must be SHA1(AlgIDHash == 0x8004)");
- }
- else
- {
- throw new NotSupportedException("Hash provider is invalid. Must be SHA1(AlgIDHash == 0x8004)");
- }
-
- hash = GetPasswordHash(hashProvider, encryptionInfo.Verifier.Salt, password, 50000, 20);
-
- // Append "block" (0)
- Array.Copy(hash, tempHash, hash.Length);
- Array.Copy(System.BitConverter.GetBytes(0), 0, tempHash, hash.Length, 4);
- hash = hashProvider.ComputeHash(tempHash);
-
- /***** Now use the derived key algorithm *****/
- byte[] derivedKey = new byte[64];
- int keySizeBytes = encryptionInfo.Header.KeySize / 8;
-
- //First XOR hash bytes with 0x36 and fill the rest with 0x36
- for (int i = 0; i < derivedKey.Length; i++)
- derivedKey[i] = (byte)(i < hash.Length ? 0x36 ^ hash[i] : 0x36);
-
-
- byte[] X1 = hashProvider.ComputeHash(derivedKey);
-
- //if verifier size is bigger than the key size we can return X1
- if ((int)encryptionInfo.Verifier.VerifierHashSize > keySizeBytes)
- return FixHashSize(X1, keySizeBytes);
-
- //Else XOR hash bytes with 0x5C and fill the rest with 0x5C
- for (int i = 0; i < derivedKey.Length; i++)
- derivedKey[i] = (byte)(i < hash.Length ? 0x5C ^ hash[i] : 0x5C);
-
- byte[] X2 = hashProvider.ComputeHash(derivedKey);
-
- //Join the two and return
- byte[] join = new byte[X1.Length + X2.Length];
-
- Array.Copy(X1, 0, join, 0, X1.Length);
- Array.Copy(X2, 0, join, X1.Length, X2.Length);
-
-
- return FixHashSize(join, keySizeBytes);
- }
- catch (Exception ex)
- {
- throw (new Exception("An error occured when the encryptionkey was created", ex));
- }
- }
-
- /// <summary>
- /// Create the hash.
- /// This method is written with the help of Lyquidity library, many thanks for this nice sample
- /// </summary>
- /// <param name="password">The password</param>
- /// <param name="encr">The encryption info extracted from the ENCRYPTIOINFO stream inside the OLE document</param>
- /// <param name="blockKey">The block key appended to the hash to obtain the final hash</param>
- /// <returns>The hash to encrypt the document</returns>
- private byte[] GetPasswordHashAgile(string password, EncryptionInfoAgile.EncryptionKeyEncryptor encr, byte[] blockKey)
- {
- try
- {
- var hashProvider = GetHashProvider(encr);
- var hash = GetPasswordHash(hashProvider, encr.SaltValue, password, encr.SpinCount, encr.HashSize);
- var hashFinal = GetFinalHash(hashProvider, encr, blockKey, hash);
-
- return FixHashSize(hashFinal, encr.KeyBits / 8);
- }
- catch (Exception ex)
- {
- throw (new Exception("An error occured when the encryptionkey was created", ex));
- }
- }
-#endif
- private byte[] GetFinalHash(HashAlgorithm hashProvider, EncryptionInfoAgile.EncryptionKeyEncryptor encr, byte[] blockKey, byte[] hash)
- {
- //2.3.4.13 MS-OFFCRYPTO
- var tempHash = new byte[hash.Length + blockKey.Length];
- Array.Copy(hash, tempHash, hash.Length);
- Array.Copy(blockKey, 0, tempHash, hash.Length, blockKey.Length);
- var hashFinal = hashProvider.ComputeHash(tempHash);
- return hashFinal;
- }
- private byte[] GetPasswordHash(HashAlgorithm hashProvider, byte[] salt, string password, int spinCount, int hashSize)
- {
- byte[] hash = null;
- byte[] tempHash = new byte[4 + hashSize]; //Iterator + prev. hash
- hash = hashProvider.ComputeHash(CombinePassword(salt, password));
-
- //Iterate "spinCount" times, inserting i in first 4 bytes and then the prev. hash in byte 5-24
- for (int i = 0; i < spinCount; i++)
- {
- Array.Copy(BitConverter.GetBytes(i), tempHash, 4);
- Array.Copy(hash, 0, tempHash, 4, hash.Length);
-
- hash = hashProvider.ComputeHash(tempHash);
- }
-
- return hash;
- }
- private byte[] FixHashSize(byte[] hash, int size, byte fill=0)
- {
- if (hash.Length == size)
- return hash;
- else if (hash.Length < size)
- {
- byte[] buff = new byte[size];
- Array.Copy(hash, buff, hash.Length);
- for (int i = hash.Length; i < size; i++)
- {
- buff[i] = fill;
- }
- return buff;
- }
- else
- {
- byte[] buff = new byte[size];
- Array.Copy(hash, buff, size);
- return buff;
- }
- }
- private byte[] CombinePassword(byte[] salt, string password)
- {
- if (password == "")
- {
- password = "VelvetSweatshop"; //Used if Password is blank
- }
- // Convert password to unicode...
- byte[] passwordBuf = UnicodeEncoding.Unicode.GetBytes(password);
-
- byte[] inputBuf = new byte[salt.Length + passwordBuf.Length];
- Array.Copy(salt, inputBuf, salt.Length);
- Array.Copy(passwordBuf, 0, inputBuf, salt.Length, passwordBuf.Length);
- return inputBuf;
- }
- internal static ushort CalculatePasswordHash(string Password)
- {
- //Calculate the hash
- //Thanks to Kohei Yoshida for the sample http://kohei.us/2008/01/18/excel-sheet-protection-password-hash/
- ushort hash = 0;
- for (int i = Password.Length - 1; i >= 0; i--)
- {
- hash ^= Password[i];
- hash = (ushort)(((ushort)((hash >> 14) & 0x01))
- |
- ((ushort)((hash << 1) & 0x7FFF))); //Shift 1 to the left. Overflowing bit 15 goes into bit 0
- }
-
- hash ^= (0x8000 | ('N' << 8) | 'K'); //Xor NK with high bit set(0xCE4B)
- hash ^= (ushort)Password.Length;
-
- return hash;
- }
- }
-}
diff --git a/EPPlus/Encryption/EncryptionHeader.cs b/EPPlus/Encryption/EncryptionHeader.cs
deleted file mode 100644
index c0ca697..0000000
--- a/EPPlus/Encryption/EncryptionHeader.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011 Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author Change Date
- * ******************************************************************************
- * Jan Källman Added 2013-01-05
- *******************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-
-namespace OfficeOpenXml.Encryption
-{
- [Flags]
- internal enum Flags
- {
- Reserved1 = 1, // (1 bit): MUST be set to zero, and MUST be ignored.
- Reserved2 = 2, // (1 bit): MUST be set to zero, and MUST be ignored.
- fCryptoAPI = 4, // (1 bit): A flag that specifies whether CryptoAPI RC4 or [ECMA-376] encryption is used. It MUST be set to 1 unless fExternal is 1. If fExternal is set to 1, it MUST be set to zero.
- fDocProps = 8, // (1 bit): MUST be set to zero if document properties are encrypted. Otherwise, it MUST be set to 1. Encryption of document properties is specified in section 2.3.5.4.
- fExternal = 16, // (1 bit): If extensible encryption is used, it MUST be set to 1. Otherwise, it MUST be set to zero. If this field is set to 1, all other fields in this structure MUST be set to zero.
- fAES = 32 //(1 bit): If the protected content is an [ECMA-376] document, it MUST be set to 1. Otherwise, it MUST be set to zero. If the fAES bit is set to 1, the fCryptoAPI bit MUST also be set to 1
- }
- internal enum AlgorithmID
- {
- Flags = 0x00000000, // Determined by Flags
- RC4 = 0x00006801, // RC4
- AES128 = 0x0000660E, // 128-bit AES
- AES192 = 0x0000660F, // 192-bit AES
- AES256 = 0x00006610 // 256-bit AES
- }
- internal enum AlgorithmHashID
- {
- App = 0x00000000,
- SHA1 = 0x00008004,
- }
- internal enum ProviderType
- {
- Flags = 0x00000000,//Determined by Flags
- RC4 = 0x00000001,
- AES = 0x00000018,
- }
- /// <summary>
- /// Encryption Header inside the EncryptionInfo stream
- /// </summary>
- internal class EncryptionHeader
- {
- internal Flags Flags;
- internal int SizeExtra; //MUST be 0x00000000.
- internal AlgorithmID AlgID; //MUST be 0x0000660E (AES-128), 0x0000660F (AES-192), or 0x00006610 (AES-256).
- internal AlgorithmHashID AlgIDHash; //MUST be 0x00008004 (SHA-1).
- internal int KeySize; //MUST be 0x00000080 (AES-128), 0x000000C0 (AES-192), or 0x00000100 (AES-256).
- internal ProviderType ProviderType; //SHOULD<10> be 0x00000018 (AES).
- internal int Reserved1; //Undefined and MUST be ignored.
- internal int Reserved2; //MUST be 0x00000000 and MUST be ignored.
- internal string CSPName; //SHOULD<11> be set to either "Microsoft Enhanced RSA and AES Cryptographic Provider" or "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" as a null-terminated Unicode string.
- internal byte[] WriteBinary()
- {
- MemoryStream ms = new MemoryStream();
- BinaryWriter bw = new BinaryWriter(ms);
-
- bw.Write((int)Flags);
- bw.Write(SizeExtra);
- bw.Write((int)AlgID);
- bw.Write((int)AlgIDHash);
- bw.Write((int)KeySize);
- bw.Write((int)ProviderType);
- bw.Write(Reserved1);
- bw.Write(Reserved2);
- bw.Write(Encoding.Unicode.GetBytes(CSPName));
-
- bw.Flush();
- return ms.ToArray();
- }
- }
-}
diff --git a/EPPlus/Encryption/EncryptionInfo.cs b/EPPlus/Encryption/EncryptionInfo.cs
deleted file mode 100644
index d29a369..0000000
--- a/EPPlus/Encryption/EncryptionInfo.cs
+++ /dev/null
@@ -1,584 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011 Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author Change Date
- * ******************************************************************************
- * Jan Källman Added 2013-01-05
- *******************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Xml;
-
-namespace OfficeOpenXml.Encryption
-{
- internal abstract class EncryptionInfo
- {
- internal short MajorVersion;
- internal short MinorVersion;
- internal abstract void Read(byte[] data);
-
- internal static EncryptionInfo ReadBinary(byte[] data)
- {
- var majorVersion = BitConverter.ToInt16(data, 0);
- var minorVersion = BitConverter.ToInt16(data, 2);
- EncryptionInfo ret;
- if ((minorVersion == 2 || minorVersion == 3) && majorVersion <= 4) // minorVersion==1 is RC4, not supported.
- {
- ret = new EncryptionInfoBinary();
- }
- else if (majorVersion == 4 && minorVersion==4)
- {
- ret = new EncryptionInfoAgile();
- }
- else
- {
- throw (new NotSupportedException("Unsupported encryption format"));
- }
- ret.MajorVersion = majorVersion;
- ret.MinorVersion = minorVersion;
- ret.Read(data);
- return ret;
- }
- }
- internal enum eCipherAlgorithm
- {
- /// <summary>
- /// AES. MUST conform to the AES algorithm.
- /// </summary>
- AES,
- /// <summary>
- /// RC2. MUST conform to [RFC2268].
- /// </summary>
- RC2,
- /// <summary>
- /// RC4.
- /// </summary>
- RC4,
- /// <summary>
- /// MUST conform to the DES algorithm.
- /// </summary>
- DES,
- /// <summary>
- /// MUST conform to the [DRAFT-DESX] algorithm.
- /// </summary>
- DESX,
- /// <summary>
- /// 3DES. MUST conform to the [RFC1851] algorithm.
- /// </summary>
- TRIPLE_DES,
- /// 3DES_112 MUST conform to the [RFC1851] algorithm.
- TRIPLE_DES_112
- }
- internal enum eChainingMode
- {
- /// <summary>
- /// Cipher block chaining (CBC).
- /// </summary>
- ChainingModeCBC,
- /// <summary>
- /// Cipher feedback chaining (CFB), with 8-bit window.
- /// </summary>
- ChainingModeCFB
- }
- /// <summary>
- /// Hashalgorithm
- /// </summary>
- internal enum eHashAlogorithm
- {
- /// <summary>
- /// Sha 1-MUST conform to [RFC4634]
- /// </summary>
- SHA1,
- /// <summary>
- /// Sha 256-MUST conform to [RFC4634]
- /// </summary>
- SHA256,
- /// <summary>
- /// Sha 384-MUST conform to [RFC4634]
- /// </summary>
- SHA384,
- /// <summary>
- /// Sha 512-MUST conform to [RFC4634]
- /// </summary>
- SHA512,
- /// <summary>
- /// MD5
- /// </summary>
- MD5,
- /// <summary>
- /// MD4
- /// </summary>
- MD4,
- /// <summary>
- /// MD2
- /// </summary>
- MD2,
- /// <summary>
- /// RIPEMD-128 MUST conform to [ISO/IEC 10118]
- /// </summary>
- RIPEMD128,
- /// <summary>
- /// RIPEMD-160 MUST conform to [ISO/IEC 10118]
- /// </summary>
- RIPEMD160,
- /// <summary>
- /// WHIRLPOOL MUST conform to [ISO/IEC 10118]
- /// </summary>
- WHIRLPOOL
- }
- /// <summary>
- /// Handels the agile encryption
- /// </summary>
- internal class EncryptionInfoAgile : EncryptionInfo
- {
- XmlNamespaceManager _nsm;
- public EncryptionInfoAgile()
- {
- var nt = new NameTable();
- _nsm = new XmlNamespaceManager(nt);
- _nsm.AddNamespace("d", "http://schemas.microsoft.com/office/2006/encryption");
- _nsm.AddNamespace("c", "http://schemas.microsoft.com/office/2006/keyEncryptor/certificate");
- _nsm.AddNamespace("p", "http://schemas.microsoft.com/office/2006/keyEncryptor/password");
- }
- internal class EncryptionKeyData : XmlHelper
- {
- public EncryptionKeyData(XmlNamespaceManager nsm, XmlNode topNode) :
- base(nsm, topNode)
- {
-
- }
- internal byte[] SaltValue
- {
- get
- {
- var s = GetXmlNodeString("@saltValue");
- if (!string.IsNullOrEmpty(s))
- {
- return Convert.FromBase64String(s);
- }
- return null;
- }
- set
- {
- SetXmlNodeString("@saltValue", Convert.ToBase64String(value));
- }
- }
- internal eHashAlogorithm HashAlgorithm
- {
- get
- {
- return GetHashAlgorithm(GetXmlNodeString("@hashAlgorithm"));
- }
- set
- {
- SetXmlNodeString("@hashAlgorithm", GetHashAlgorithmString(value));
- }
- }
-
- private eHashAlogorithm GetHashAlgorithm(string v)
- {
- switch (v)
- {
- case "RIPEMD-128":
- return eHashAlogorithm.RIPEMD128;
- case "RIPEMD-160":
- return eHashAlogorithm.RIPEMD160;
- case "SHA-1":
- return eHashAlogorithm.SHA1;
- default:
- try
- {
- return (eHashAlogorithm)Enum.Parse(typeof(eHashAlogorithm),v);
- }
- catch
- {
- throw (new InvalidDataException("Invalid Hash algorithm"));
- }
- }
- }
-
- private string GetHashAlgorithmString(eHashAlogorithm value)
- {
- switch (value)
- {
- case eHashAlogorithm.RIPEMD128:
- return "RIPEMD-128";
- case eHashAlogorithm.RIPEMD160:
- return "RIPEMD-160";
- case eHashAlogorithm.SHA1:
- return "SHA-1";
- default:
- return value.ToString();
- }
- }
- internal eChainingMode ChiptherChaining
- {
- get
- {
- var v=GetXmlNodeString("@cipherChaining");
- try
- {
- return (eChainingMode)Enum.Parse(typeof(eChainingMode), v);
- }
- catch
- {
- throw (new InvalidDataException("Invalid chaining mode"));
- }
- }
- set
- {
- SetXmlNodeString("@cipherChaining", value.ToString());
- }
- }
- internal eCipherAlgorithm CipherAlgorithm
- {
- get
- {
- return GetCipherAlgorithm(GetXmlNodeString("@cipherAlgorithm"));
- }
- set
- {
- SetXmlNodeString("@cipherAlgorithm", GetCipherAlgorithmString(value));
- }
- }
-
- private eCipherAlgorithm GetCipherAlgorithm(string v)
- {
- switch (v)
- {
- case "3DES":
- return eCipherAlgorithm.TRIPLE_DES;
- case "3DES_112":
- return eCipherAlgorithm.TRIPLE_DES_112;
- default:
- try
- {
- return (eCipherAlgorithm)Enum.Parse(typeof(eCipherAlgorithm), v);
- }
- catch
- {
- throw (new InvalidDataException("Invalid Hash algorithm"));
- }
- }
- }
-
- private string GetCipherAlgorithmString(eCipherAlgorithm alg)
- {
- switch (alg)
- {
- case eCipherAlgorithm.TRIPLE_DES:
- return "3DES";
- case eCipherAlgorithm.TRIPLE_DES_112:
- return "3DES_112";
- default:
- return alg.ToString();
- }
- }
- internal int HashSize
- {
- get
- {
- return GetXmlNodeInt("@hashSize");
- }
- set
- {
- SetXmlNodeString("@hashSize", value.ToString());
- }
- }
- internal int KeyBits
- {
- get
- {
- return GetXmlNodeInt("@keyBits");
- }
- set
- {
- SetXmlNodeString("@keyBits", value.ToString());
- }
- }
- internal int BlockSize
- {
- get
- {
- return GetXmlNodeInt("@blockSize");
- }
- set
- {
- SetXmlNodeString("@blockSize", value.ToString());
- }
- }
- internal int SaltSize
- {
- get
- {
- return GetXmlNodeInt("@saltSize");
- }
- set
- {
- SetXmlNodeString("@saltSize", value.ToString());
- }
- }
- }
- internal class EncryptionDataIntegrity : XmlHelper
- {
- public EncryptionDataIntegrity(XmlNamespaceManager nsm, XmlNode topNode) :
- base(nsm, topNode)
- {
-
- }
- internal byte[] EncryptedHmacValue
- {
- get
- {
- var s = GetXmlNodeString("@encryptedHmacValue");
- if (!string.IsNullOrEmpty(s))
- {
- return Convert.FromBase64String(s);
- }
- return null;
- }
- set
- {
- SetXmlNodeString("@encryptedHmacValue", Convert.ToBase64String(value));
- }
- }
- internal byte[] EncryptedHmacKey
- {
- get
- {
- var s = GetXmlNodeString("@encryptedHmacKey");
- if (!string.IsNullOrEmpty(s))
- {
- return Convert.FromBase64String(s);
- }
- return null;
- }
- set
- {
- SetXmlNodeString("@encryptedHmacKey", Convert.ToBase64String(value));
- }
- }
- }
- internal class EncryptionKeyEncryptor : EncryptionKeyData
- {
- public EncryptionKeyEncryptor(XmlNamespaceManager nsm, XmlNode topNode) :
- base(nsm, topNode)
- {
-
- }
- internal byte[] EncryptedKeyValue
- {
- get
- {
- var s = GetXmlNodeString("@encryptedKeyValue");
- if (!string.IsNullOrEmpty(s))
- {
- return Convert.FromBase64String(s);
- }
- return null;
- }
- set
- {
- SetXmlNodeString("@encryptedKeyValue", Convert.ToBase64String(value));
- }
- }
- internal byte[] EncryptedVerifierHash
- {
- get
- {
- var s = GetXmlNodeString("@encryptedVerifierHashValue");
- if (!string.IsNullOrEmpty(s))
- {
- return Convert.FromBase64String(s);
- }
- return null;
-
- }
- set
- {
- SetXmlNodeString("@encryptedVerifierHashValue", Convert.ToBase64String(value));
- }
- }
- internal byte[] EncryptedVerifierHashInput
- {
- get
- {
- var s = GetXmlNodeString("@encryptedVerifierHashInput");
- if (!string.IsNullOrEmpty(s))
- {
- return Convert.FromBase64String(s);
- }
- return null;
- }
- set
- {
- SetXmlNodeString("@encryptedVerifierHashInput", Convert.ToBase64String(value));
- }
- }
- internal byte[] VerifierHashInput { get; set; }
- internal byte[] VerifierHash { get; set; }
- internal byte[] KeyValue { get; set; }
- internal int SpinCount
- {
- get
- {
- return GetXmlNodeInt("@spinCount");
- }
- set
- {
- SetXmlNodeString("@spinCount", value.ToString());
- }
- }
- }
- /*
- <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <encryption xmlns="http://schemas.microsoft.com/office/2006/encryption" xmlns:p="http://schemas.microsoft.com/office/2006/keyEncryptor/password" xmlns:c="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate">
- <keyData saltSize="16" blockSize="16" keyBits="256" hashSize="64" cipherAlgorithm="AES" cipherChaining="ChainingModeCBC" hashAlgorithm="SHA512" saltValue="pa+hrJ3s1zrY6hmVuSa5JQ==" />
- <dataIntegrity encryptedHmacKey="nd8i4sEKjsMjVN2gLo91oFN2e7bhMpWKDCAUBEpz4GW6NcE3hBXDobLksZvQGwLrPj0SUVzQA8VuDMyjMAfVCA==" encryptedHmacValue="O6oegHpQVz2uO7Om4oZijSi4kzLiiMZGIjfZlq/EFFO6PZbKitenBqe2or1REaxaI7gO/JmtJzZ1ViucqTaw4g==" />
- <keyEncryptors>
- <keyEncryptor uri="http://schemas.microsoft.com/office/2006/keyEncryptor/password">
- <p:encryptedKey spinCount="100000" saltSize="16" blockSize="16" keyBits="256" hashSize="64" cipherAlgorithm="AES" cipherChaining="ChainingModeCBC" hashAlgorithm="SHA512" saltValue="u2BNFAuHYn3M/WRja3/uPg==" encryptedVerifierHashInput="M0V+fRolJMRgFyI9w+AVxQ==" encryptedVerifierHashValue="V/6l9pFH7AaXFqEbsnFBfHe7gMOqFeRwaNMjc7D3LNdw6KgZzOOQlt5sE8/oG7GPVBDGfoQMTxjQydVPVy4qng==" encryptedKeyValue="B0/rbSQRiIKG5CQDH6AKYSybdXzxgKAfX1f+S5k7mNE=" />
- </keyEncryptor></keyEncryptors></encryption>
- */
-
- /***
- * <?xml version="1.0" encoding="UTF-8" standalone="true"?>
- <encryption xmlns:c="http://schemas.microsoft.com/office/2006/keyEncryptor/certificate" xmlns:p="http://schemas.microsoft.com/office/2006/keyEncryptor/password" xmlns="http://schemas.microsoft.com/office/2006/encryption">
- * <keyData saltValue="XmTB/XBGJSbwd/GTKzQv5A==" hashAlgorithm="SHA512" cipherChaining="ChainingModeCBC" cipherAlgorithm="AES" hashSize="64" keyBits="256" blockSize="16" saltSize="16"/>
- * <dataIntegrity encryptedHmacValue="WWw3Bb2dbcNPMnl9f1o7rO0u7sclWGKTXqBA6rRzKsP2KzWS5T0LxY9qFoC6QE67t/t+FNNtMDdMtE3D1xvT8w==" encryptedHmacKey="p/dVdlJY5Kj0k3jI1HRjqtk4s0Y4HmDAsc8nqZgfxNS7DopAsS3LU/2p3CYoIRObHsnHTAtbueH08DFCYGZURg=="/>
- * <keyEncryptors>
- * <keyEncryptor uri="http://schemas.microsoft.com/office/2006/keyEncryptor/password">
- * <p:encryptedKey saltValue="EeBtY0QftyOkLztCl7NF0g==" hashAlgorithm="SHA512" cipherChaining="ChainingModeCBC" cipherAlgorithm="AES" hashSize="64" keyBits="256" blockSize="16" saltSize="16" encryptedKeyValue="Z7AO8vHnnPZEb1VqyZLJ6JFc3Mq3E322XPxWXS21fbU=" encryptedVerifierHashValue="G7BxbKnZanldvtsbu51mP9J3f9Wr5vCfCpvWSh5eIJff7Sr3J2DzH1/9aKj9uIpqFQIsLohpRk+oBYDcX7hRgw==" encryptedVerifierHashInput="851eszl5y5rdU1RnTjEWHw==" spinCount="100000"/>
- * </keyEncryptor>
- * </keyEncryptors>
- * </encryption
- * ***/
- internal EncryptionDataIntegrity DataIntegrity { get; set; }
- internal EncryptionKeyData KeyData { get; set; }
- internal List<EncryptionKeyEncryptor> KeyEncryptors
- {
- get;
- private set;
- }
-
- internal XmlDocument Xml {get;set;}
- internal override void Read(byte[] data)
- {
- var byXml = new byte[data.Length - 8];
- Array.Copy(data, 8, byXml, 0, data.Length - 8);
- var xml = Encoding.UTF8.GetString(byXml);
- ReadFromXml(xml);
- }
- internal void ReadFromXml(string xml)
- {
- Xml = new XmlDocument();
- XmlHelper.LoadXmlSafe(Xml, xml, Encoding.UTF8);
- var node = Xml.SelectSingleNode("/d:encryption/d:keyData", _nsm);
- KeyData = new EncryptionKeyData(_nsm, node);
- node = Xml.SelectSingleNode("/d:encryption/d:dataIntegrity", _nsm);
- DataIntegrity = new EncryptionDataIntegrity(_nsm, node);
- KeyEncryptors = new List<EncryptionKeyEncryptor>();
-
- var list = Xml.SelectNodes("/d:encryption/d:keyEncryptors/d:keyEncryptor/p:encryptedKey", _nsm);
- if (list != null)
- {
- foreach (XmlNode n in list)
- {
- KeyEncryptors.Add(new EncryptionKeyEncryptor(_nsm, n));
- }
- }
-
- }
- }
- /// <summary>
- /// Handles the EncryptionInfo stream
- /// </summary>
- internal class EncryptionInfoBinary : EncryptionInfo
- {
-
-
- internal Flags Flags;
- internal uint HeaderSize;
- internal EncryptionHeader Header;
- internal EncryptionVerifier Verifier;
- internal override void Read(byte[] data)
- {
- Flags = (Flags)BitConverter.ToInt32(data, 4);
- HeaderSize = (uint)BitConverter.ToInt32(data, 8);
-
- /**** EncryptionHeader ****/
- Header = new EncryptionHeader();
- Header.Flags = (Flags)BitConverter.ToInt32(data, 12);
- Header.SizeExtra = BitConverter.ToInt32(data, 16);
- Header.AlgID = (AlgorithmID)BitConverter.ToInt32(data, 20);
- Header.AlgIDHash = (AlgorithmHashID)BitConverter.ToInt32(data, 24);
- Header.KeySize = BitConverter.ToInt32(data, 28);
- Header.ProviderType = (ProviderType)BitConverter.ToInt32(data, 32);
- Header.Reserved1 = BitConverter.ToInt32(data, 36);
- Header.Reserved2 = BitConverter.ToInt32(data, 40);
-
- byte[] text = new byte[(int)HeaderSize - 34];
- Array.Copy(data, 44, text, 0, (int)HeaderSize - 34);
- Header.CSPName = UTF8Encoding.Unicode.GetString(text);
-
- int pos = (int)HeaderSize + 12;
-
- /**** EncryptionVerifier ****/
- Verifier = new EncryptionVerifier();
- Verifier.SaltSize = (uint)BitConverter.ToInt32(data, pos);
- Verifier.Salt = new byte[Verifier.SaltSize];
-
- Array.Copy(data, pos + 4, Verifier.Salt, 0, Verifier.SaltSize);
-
- Verifier.EncryptedVerifier = new byte[16];
- Array.Copy(data, pos + 20, Verifier.EncryptedVerifier, 0, 16);
-
- Verifier.VerifierHashSize = (uint)BitConverter.ToInt32(data, pos + 36);
- Verifier.EncryptedVerifierHash = new byte[Verifier.VerifierHashSize];
- Array.Copy(data, pos + 40, Verifier.EncryptedVerifierHash, 0, Verifier.VerifierHashSize);
- }
- internal byte[] WriteBinary()
- {
- MemoryStream ms = new MemoryStream();
- BinaryWriter bw = new BinaryWriter(ms);
-
- bw.Write(MajorVersion);
- bw.Write(MinorVersion);
- bw.Write((int)Flags);
- byte[] header = Header.WriteBinary();
- bw.Write((uint)header.Length);
- bw.Write(header);
- bw.Write(Verifier.WriteBinary());
-
- bw.Flush();
- return ms.ToArray();
- }
-
- }
-}
diff --git a/EPPlus/Encryption/EncryptionVerifier.cs b/EPPlus/Encryption/EncryptionVerifier.cs
deleted file mode 100644
index bfd1353..0000000
--- a/EPPlus/Encryption/EncryptionVerifier.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011 Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author Change Date
- * ******************************************************************************
- * Jan Källman Added 2013-01-05
- *******************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-
-namespace OfficeOpenXml.Encryption
-{
- /// <summary>
- /// Encryption verifier inside the EncryptionInfo stream
- /// </summary>
- internal class EncryptionVerifier
- {
- internal uint SaltSize; // An unsigned integer that specifies the size of the Salt field. It MUST be 0x00000010.
- internal byte[] Salt; //(16 bytes): An array of bytes that specifies the salt value used during password hash generation. It MUST NOT be the same data used for the verifier stored encrypted in the EncryptedVerifier field.
- internal byte[] EncryptedVerifier; //(16 bytes): MUST be the randomly generated Verifier value encrypted using the algorithm chosen by the implementation.
- internal uint VerifierHashSize; //(4 bytes): An unsigned integer that specifies the number of bytes needed to contain the hash of the data used to generate the EncryptedVerifier field.
- internal byte[] EncryptedVerifierHash; //(variable): An array of bytes that contains the encrypted form of the hash of the randomly generated Verifier value. The length of the array MUST be the size of the encryption block size multiplied by the number of blocks needed to encrypt the hash of the Verifier. If the encryption algorithm is RC4, the length MUST be 20 bytes. If the encryption algorithm is AES, the length MUST be 32 bytes.
- internal byte[] WriteBinary()
- {
- MemoryStream ms = new MemoryStream();
- BinaryWriter bw = new BinaryWriter(ms);
-
- bw.Write(SaltSize);
- bw.Write(Salt);
- bw.Write(EncryptedVerifier);
- bw.Write(0x14); //Sha1 is 20 bytes (Encrypted is 32)
- bw.Write(EncryptedVerifierHash);
-
- bw.Flush();
- return ms.ToArray();
- }
- }
-}
diff --git a/EPPlus/ExcelCommentCollection.cs b/EPPlus/ExcelCommentCollection.cs
index 6597653..cf0a540 100644
--- a/EPPlus/ExcelCommentCollection.cs
+++ b/EPPlus/ExcelCommentCollection.cs
@@ -206,11 +206,8 @@
}
}
- void IDisposable.Dispose()
- {
- if (_comments != null)
- ((IDisposable)_comments).Dispose();
- }
+ void IDisposable.Dispose() { }
+
/// <summary>
/// Removes the comment at the specified position
/// </summary>
diff --git a/EPPlus/ExcelEncryption.cs b/EPPlus/ExcelEncryption.cs
deleted file mode 100644
index 6bddb51..0000000
--- a/EPPlus/ExcelEncryption.cs
+++ /dev/null
@@ -1,175 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011 Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- ***************************************************************************************
- * This class is created with the help of the MS-OFFCRYPTO PDF documentation... http://msdn.microsoft.com/en-us/library/cc313071(office.12).aspx
- * Decrypytion library for Office Open XML files(Lyquidity) and Sminks very nice example
- * on "Reading compound documents in c#" on Stackoverflow. Many thanks!
- ***************************************************************************************
- *
- * Code change notes:
- *
- * Author Change Date
- *******************************************************************************
- * Jan Källman Added 10-AUG-2010
- * Jan Källman License changed GPL-->LGPL 2011-12-27
- *******************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace OfficeOpenXml
-{
- /// <summary>
- /// Encryption Algorithm
- /// </summary>
- public enum EncryptionAlgorithm
- {
- /// <summary>
- /// 128-bit AES. Default
- /// </summary>
- AES128,
- /// <summary>
- /// 192-bit AES.
- /// </summary>
- AES192,
- /// <summary>
- /// 256-bit AES.
- /// </summary>
- AES256
- }
- /// <summary>
- /// The major version of the Encryption
- /// </summary>
- public enum EncryptionVersion
- {
- /// <summary>
- /// Standard Encryption.
- /// Used in Excel 2007 and previous version with compatibility pack.
- /// <remarks>Default AES 128 with SHA-1 as the hash algorithm. Spincount is hardcoded to 50000</remarks>
- /// </summary>
- Standard,
- /// <summary>
- /// Agile Encryption.
- /// Used in Excel 2010-
- /// Default.
- /// </summary>
- Agile
- }
- /// <summary>
- /// How and if the workbook is encrypted
- ///<seealso cref="ExcelProtection"/>
- ///<seealso cref="ExcelSheetProtection"/>
- /// </summary>
- public class ExcelEncryption
- {
- /// <summary>
- /// Constructor
- /// <remarks>Default AES 256 with SHA-512 as the hash algorithm. Spincount is set to 100000</remarks>
- /// </summary>
- internal ExcelEncryption()
- {
- Algorithm = EncryptionAlgorithm.AES256;
- }
- /// <summary>
- /// Constructor
- /// </summary>
- /// <param name="encryptionAlgorithm">Algorithm used to encrypt the package. Default is AES128</param>
- internal ExcelEncryption(EncryptionAlgorithm encryptionAlgorithm)
- {
- Algorithm = encryptionAlgorithm;
- }
- bool _isEncrypted = false;
- /// <summary>
- /// Is the package encrypted
- /// </summary>
- public bool IsEncrypted
- {
- get
- {
- return _isEncrypted;
- }
- set
- {
- _isEncrypted = value;
- if (_isEncrypted)
- {
- if (_password == null) _password = "";
- }
- else
- {
- _password = null;
- }
- }
- }
- string _password=null;
- /// <summary>
- /// The password used to encrypt the workbook.
- /// </summary>
- public string Password
- {
- get
- {
- return _password;
- }
- set
- {
- _password = value;
- _isEncrypted = (value != null);
- }
- }
- /// <summary>
- /// Algorithm used for encrypting the package. Default is AES 128-bit for standard and AES 256 for agile
- /// </summary>
- public EncryptionAlgorithm Algorithm { get; set; }
- private EncryptionVersion _version = EncryptionVersion.Agile;
- /// <summary>
- /// The version of the encryption.
- /// </summary>
- public EncryptionVersion Version
- {
- get
- {
- return _version;
- }
- set
- {
- if (value != Version)
- {
- if (value == EncryptionVersion.Agile)
- {
- Algorithm = EncryptionAlgorithm.AES256;
- }
- else
- {
- Algorithm = EncryptionAlgorithm.AES128;
- }
- _version = value;
- }
- }
- }
- }
-}
diff --git a/EPPlus/ExcelPackage.cs b/EPPlus/ExcelPackage.cs
index bb2b983..78c4083 100644
--- a/EPPlus/ExcelPackage.cs
+++ b/EPPlus/ExcelPackage.cs
@@ -38,7 +38,6 @@
using System.Collections.Generic;
using System.Security.Cryptography;
using OfficeOpenXml.Utils;
-using OfficeOpenXml.Encryption;
namespace OfficeOpenXml
{
/// <summary>
@@ -159,19 +158,10 @@
/// </code>
/// More samples can be found at <a href="http://epplus.codeplex.com/">http://epplus.codeplex.com/</a>
/// </summary>
- public sealed class ExcelPackage : IDisposable
+ public sealed class ExcelPackage
{
internal const bool preserveWhitespace=false;
- Stream _stream = null;
- private bool _isExternalStream=false;
- internal class ImageInfo
- {
- internal string Hash { get; set; }
- internal Uri Uri{get;set;}
- internal int RefCount { get; set; }
- internal Packaging.ZipPackagePart Part { get; set; }
- }
- internal Dictionary<string, ImageInfo> _images = new Dictionary<string, ImageInfo>();
+
#region Properties
/// <summary>
/// Extention Schema types
@@ -188,8 +178,6 @@
internal const string schemaRelationships = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships";
internal const string schemaDrawings = @"http://schemas.openxmlformats.org/drawingml/2006/main";
- internal const string schemaSheetDrawings = @"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
- internal const string schemaMarkupCompatibility = @"http://schemas.openxmlformats.org/markup-compatibility/2006";
internal const string schemaMicrosoftVml = @"urn:schemas-microsoft-com:vml";
internal const string schemaMicrosoftOffice = "urn:schemas-microsoft-com:office:office";
@@ -198,7 +186,6 @@
internal const string schemaChart = @"http://schemas.openxmlformats.org/drawingml/2006/chart";
internal const string schemaHyperlink = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
internal const string schemaComment = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
- internal const string schemaImage = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
//Office properties
internal const string schemaCore = @"http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
internal const string schemaExtended = @"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
@@ -214,16 +201,9 @@
internal const string schemaPivotCacheDefinition = @"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml";
internal const string schemaPivotCacheRecords = @"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml";
- //VBA
- internal const string schemaVBA = @"application/vnd.ms-office.vbaProject";
- internal const string schemaVBASignature = @"application/vnd.ms-office.vbaProjectSignature";
-
internal const string contentTypeWorkbookDefault = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
internal const string contentTypeWorkbookMacroEnabled = "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
internal const string contentTypeSharedString = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
- //Package reference
- private Packaging.ZipPackage _package;
- internal ExcelWorkbook _workbook;
/// <summary>
/// Maximum number of columns in a worksheet (16384).
/// </summary>
@@ -240,404 +220,56 @@
/// </summary>
public ExcelPackage()
{
- ConstructNewFile(null);
+ Package = new();
+ Workbook = CreateWorkbook();
+ _ = Workbook.WorkbookXml;
+ // create the relationship to the main part
+ Package.CreateRelationship(UriHelper.GetRelativeUri(new Uri("/xl", UriKind.Relative), Workbook.WorkbookUri), Packaging.TargetMode.Internal, schemaRelationships + "/officeDocument");
}
+
/// <summary>
/// Create a new instance of the ExcelPackage class based on a existing file or creates a new file.
/// </summary>
/// <param name="newFile">If newFile exists, it is opened. Otherwise it is created from scratch.</param>
public ExcelPackage(FileInfo newFile)
- {
- File = newFile;
- ConstructNewFile(null);
- }
- /// <summary>
- /// Create a new instance of the ExcelPackage class based on a existing file or creates a new file.
- /// </summary>
- /// <param name="newFile">If newFile exists, it is opened. Otherwise it is created from scratch.</param>
- /// <param name="password">Password for an encrypted package</param>
- public ExcelPackage(FileInfo newFile, string password)
{
- File = newFile;
- ConstructNewFile(password);
+ using var inputStream = newFile.OpenRead();
+ Package = new(inputStream);
+ Workbook = CreateWorkbook();
}
- /// <summary>
- /// Create a new instance of the ExcelPackage class based on a existing template.
- /// If newFile exists, it will be overwritten when the Save method is called
- /// </summary>
- /// <param name="newFile">The name of the Excel file to be created</param>
- /// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
- public ExcelPackage(FileInfo newFile, FileInfo template)
- {
- File = newFile;
- CreateFromTemplate(template, null);
- }
- /// <summary>
- /// Create a new instance of the ExcelPackage class based on a existing template.
- /// If newFile exists, it will be overwritten when the Save method is called
- /// </summary>
- /// <param name="newFile">The name of the Excel file to be created</param>
- /// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
- /// <param name="password">Password to decrypted the template</param>
- public ExcelPackage(FileInfo newFile, FileInfo template, string password)
- {
- File = newFile;
- CreateFromTemplate(template, password);
- }
- /// <summary>
- /// Create a new instance of the ExcelPackage class based on a existing template.
- /// </summary>
- /// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
- /// <param name="useStream">if true use a stream. If false create a file in the temp dir with a random name</param>
- public ExcelPackage(FileInfo template, bool useStream)
- {
- CreateFromTemplate(template, null);
- if (useStream == false)
- {
- File = new FileInfo(Path.GetTempPath() + Guid.NewGuid().ToString() + ".xlsx");
- }
- }
- /// <summary>
- /// Create a new instance of the ExcelPackage class based on a existing template.
- /// </summary>
- /// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
- /// <param name="useStream">if true use a stream. If false create a file in the temp dir with a random name</param>
- /// <param name="password">Password to decrypted the template</param>
- public ExcelPackage(FileInfo template, bool useStream, string password)
- {
- CreateFromTemplate(template, password);
- if (useStream == false)
- {
- File = new FileInfo(Path.GetTempPath() + Guid.NewGuid().ToString() + ".xlsx");
- }
- }
+
/// <summary>
/// Create a new instance of the ExcelPackage class based on a stream
/// </summary>
/// <param name="newStream">The stream object can be empty or contain a package. The stream must be Read/Write</param>
public ExcelPackage(Stream newStream)
{
- if (newStream.Length == 0)
- {
- _stream = newStream;
- _isExternalStream = true;
- ConstructNewFile(null);
- }
- else
- {
- Load(newStream);
- }
+ Package = new(newStream);
+ Workbook = CreateWorkbook();
}
- /// <summary>
- /// Create a new instance of the ExcelPackage class based on a stream
- /// </summary>
- /// <param name="newStream">The stream object can be empty or contain a package. The stream must be Read/Write</param>
- /// <param name="Password">The password to decrypt the document</param>
- public ExcelPackage(Stream newStream, string Password)
+
+ private ExcelWorkbook CreateWorkbook()
{
- if (!(newStream.CanRead && newStream.CanWrite))
- {
- throw new Exception("The stream must be read/write");
- }
- if (newStream.Length > 0)
- {
- Load(newStream,Password);
- }
- else
- {
- _stream = newStream;
- _isExternalStream = true;
- //_package = Package.Open(_stream, FileMode.Create, FileAccess.ReadWrite); TODO:Remove
- _package = new Packaging.ZipPackage(_stream);
- CreateBlankWb();
- }
- }
- /// <summary>
- /// Create a new instance of the ExcelPackage class based on a stream
- /// </summary>
- /// <param name="newStream">The output stream. Must be an empty read/write stream.</param>
- /// <param name="templateStream">This stream is copied to the output stream at load</param>
- public ExcelPackage(Stream newStream, Stream templateStream)
- {
- if (newStream.Length > 0)
- {
- throw(new Exception("The output stream must be empty. Length > 0"));
- }
- else if (!(newStream.CanRead && newStream.CanWrite))
- {
- throw new Exception("The stream must be read/write");
- }
- Load(templateStream, newStream, null);
- }
- /// <summary>
- /// Create a new instance of the ExcelPackage class based on a stream
- /// </summary>
- /// <param name="newStream">The output stream. Must be an empty read/write stream.</param>
- /// <param name="templateStream">This stream is copied to the output stream at load</param>
- /// <param name="Password">Password to decrypted the template</param>
- public ExcelPackage(Stream newStream, Stream templateStream, string Password)
- {
- if (newStream.Length > 0)
- {
- throw (new Exception("The output stream must be empty. Length > 0"));
- }
- else if (!(newStream.CanRead && newStream.CanWrite))
- {
- throw new Exception("The stream must be read/write");
- }
- Load(templateStream, newStream, Password);
- }
+ ExcelWorkbook workbook = new(this, CreateDefaultNSM());
+ workbook.GetExternalReferences();
+ workbook.GetDefinedNames();
+ return workbook;
+ }
+
#endregion
- internal ImageInfo AddImage(byte[] image)
- {
- return AddImage(image, null, "");
- }
- internal ImageInfo AddImage(byte[] image, Uri uri, string contentType)
- {
- var hashProvider = new SHA1CryptoServiceProvider();
- var hash = BitConverter.ToString(hashProvider.ComputeHash(image)).Replace("-","");
- lock (_images)
- {
- if (_images.ContainsKey(hash))
- {
- _images[hash].RefCount++;
- }
- else
- {
- Packaging.ZipPackagePart imagePart;
- if (uri == null)
- {
- uri = GetNewUri(Package, "/xl/media/image{0}.jpg");
- imagePart = Package.CreatePart(uri, "image/jpeg", CompressionLevel.None);
- }
- else
- {
- imagePart = Package.CreatePart(uri, contentType, CompressionLevel.None);
- }
- var stream = imagePart.GetStream(FileMode.Create, FileAccess.Write);
- stream.Write(image, 0, image.GetLength(0));
-
- _images.Add(hash, new ImageInfo() { Uri = uri, RefCount = 1, Hash = hash, Part = imagePart });
- }
- }
- return _images[hash];
- }
- internal ImageInfo LoadImage(byte[] image, Uri uri, Packaging.ZipPackagePart imagePart)
- {
- var hashProvider = new SHA1CryptoServiceProvider();
- var hash = BitConverter.ToString(hashProvider.ComputeHash(image)).Replace("-", "");
- if (_images.ContainsKey(hash))
- {
- _images[hash].RefCount++;
- }
- else
- {
- _images.Add(hash, new ImageInfo() { Uri = uri, RefCount = 1, Hash = hash, Part = imagePart });
- }
- return _images[hash];
- }
- internal void RemoveImage(string hash)
- {
- lock (_images)
- {
- if (_images.ContainsKey(hash))
- {
- var ii = _images[hash];
- ii.RefCount--;
- if (ii.RefCount == 0)
- {
- Package.DeletePart(ii.Uri);
- _images.Remove(hash);
- }
- }
- }
- }
- internal ImageInfo GetImageInfo(byte[] image)
- {
- var hashProvider = new SHA1CryptoServiceProvider();
- var hash = BitConverter.ToString(hashProvider.ComputeHash(image)).Replace("-","");
-
- if (_images.ContainsKey(hash))
- {
- return _images[hash];
- }
- else
- {
- return null;
- }
- }
- private Uri GetNewUri(Packaging.ZipPackage package, string sUri)
- {
- int id = 1;
- Uri uri;
- do
- {
- uri = new Uri(string.Format(sUri, id++), UriKind.Relative);
- }
- while (package.PartExists(uri));
- return uri;
- }
- /// <summary>
- /// Create a new file from a template
- /// </summary>
- /// <param name="template">An existing xlsx file to use as a template</param>
- /// <param name="password">The password to decrypt the package.</param>
- /// <returns></returns>
- private void CreateFromTemplate(FileInfo template, string password)
- {
- if (template != null) template.Refresh();
- if (template.Exists)
- {
- if(_stream==null) _stream=new MemoryStream();
- var ms = new MemoryStream();
- if (password != null)
- {
-#if !MONO
- Encryption.IsEncrypted = true;
- Encryption.Password = password;
- var encrHandler = new EncryptedPackageHandler();
- ms = encrHandler.DecryptPackage(template, Encryption);
- encrHandler = null;
-#endif
-#if MONO
- throw (new NotImplementedException("No support for Encrypted packages in Mono"));
-#endif
- //throw (new NotImplementedException("No support for Encrypted packages in this version"));
- }
- else
- {
- byte[] b = System.IO.File.ReadAllBytes(template.FullName);
- ms.Write(b, 0, b.Length);
- }
- try
- {
- //_package = Package.Open(_stream, FileMode.Open, FileAccess.ReadWrite);
- _package = new Packaging.ZipPackage(ms);
- }
- catch (Exception ex)
- {
-#if !MONO
- if (password == null && CompoundDocument.IsStorageFile(template.FullName)==0)
- {
- 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);
- }
- else
- {
- throw;
- }
-#endif
-#if MONO
- throw;
-#endif
- }
- }
- else
- throw new Exception("Passed invalid TemplatePath to Excel Template");
- //return newFile;
- }
- private void ConstructNewFile(string password)
- {
- var ms = new MemoryStream();
- if (_stream == null) _stream = new MemoryStream();
- if (File != null) File.Refresh();
- if (File != null && File.Exists)
- {
- if (password != null)
- {
-#if !MONO
- var encrHandler = new EncryptedPackageHandler();
- Encryption.IsEncrypted = true;
- Encryption.Password = password;
- ms = encrHandler.DecryptPackage(File, Encryption);
- encrHandler = null;
-#endif
-#if MONO
- throw new NotImplementedException("No support for Encrypted packages in Mono");
-#endif
- }
- else
- {
- byte[] b = System.IO.File.ReadAllBytes(File.FullName);
- ms.Write(b, 0, b.Length);
- }
- try
- {
- //_package = Package.Open(_stream, FileMode.Open, FileAccess.ReadWrite);
- _package = new Packaging.ZipPackage(ms);
- }
- catch (Exception ex)
- {
-#if !MONO
- if (password == null && CompoundDocument.IsStorageFile(File.FullName)==0)
- {
- 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);
- }
- else
- {
- throw;
- }
-#endif
-#if MONO
- throw;
-#endif
- }
- }
- else
- {
- //_package = Package.Open(_stream, FileMode.Create, FileAccess.ReadWrite);
- _package = new Packaging.ZipPackage(ms);
- CreateBlankWb();
- }
- }
-
- private void CreateBlankWb()
- {
- XmlDocument workbook = Workbook.WorkbookXml; // this will create the workbook xml in the package
- // create the relationship to the main part
- _package.CreateRelationship(UriHelper.GetRelativeUri(new Uri("/xl", UriKind.Relative), Workbook.WorkbookUri), Packaging.TargetMode.Internal, schemaRelationships + "/officeDocument");
- }
-
+
/// <summary>
/// Returns a reference to the package
/// </summary>
- public Packaging.ZipPackage Package { get { return (_package); } }
- ExcelEncryption _encryption=null;
- /// <summary>
- /// Information how and if the package is encrypted
- /// </summary>
- public ExcelEncryption Encryption
- {
- get
- {
- if (_encryption == null)
- {
- _encryption = new ExcelEncryption();
- }
- return _encryption;
- }
- }
+ internal Packaging.ZipPackage Package { get; }
+
/// <summary>
/// Returns a reference to the workbook component within the package.
/// All worksheets and cells can be accessed through the workbook.
/// </summary>
- public ExcelWorkbook Workbook
- {
- get
- {
- if (_workbook == null)
- {
- var nsm = CreateDefaultNSM();
+ public ExcelWorkbook Workbook { get; }
- _workbook = new ExcelWorkbook(this, nsm);
-
- _workbook.GetExternalReferences();
- _workbook.GetDefinedNames();
-
- }
- return (_workbook);
- }
- }
- private XmlNamespaceManager CreateDefaultNSM()
+ private XmlNamespaceManager CreateDefaultNSM()
{
// Create a NamespaceManager to handle the default namespace,
// and create a prefix for the default namespace:
@@ -670,240 +302,12 @@
/// <param name="xmlDoc">The XmlDocument to save</param>
internal void SavePart(Uri uri, XmlDocument xmlDoc)
{
- Packaging.ZipPackagePart part = _package.GetPart(uri);
+ Packaging.ZipPackagePart part = Package.GetPart(uri);
xmlDoc.Save(part.GetStream(FileMode.Create, FileAccess.Write));
}
#endregion
- #region Dispose
- /// <summary>
- /// Closes the package.
- /// </summary>
- public void Dispose()
- {
- if(_package != null)
- {
- if (_isExternalStream==false && Stream != null && (Stream.CanRead || Stream.CanWrite))
- {
- Stream.Close();
- }
- _package.Close();
- if(_isExternalStream==false) ((IDisposable)_stream).Dispose();
- if(_workbook != null)
- {
- _workbook.Dispose();
- }
- _package = null;
- _images = null;
- _file = null;
- _workbook = null;
- _stream = null;
- _workbook = null;
- }
- }
- #endregion
-
- #region Save // ExcelPackage save
- /// <summary>
- /// Saves all the components back into the package.
- /// This method recursively calls the Save method on all sub-components.
- /// We close the package after the save is done.
- /// </summary>
- public void Save()
- {
- try
- {
- Workbook.Save();
- if (File == null)
- {
- if(Encryption.IsEncrypted)
- {
-#if !MONO
- var ms = new MemoryStream();
- _package.Save(ms);
- byte[] file = ms.ToArray();
- EncryptedPackageHandler eph = new EncryptedPackageHandler();
- var msEnc = eph.EncryptPackage(file, Encryption);
- CopyStream(msEnc, ref _stream);
-#endif
-#if MONO
- throw new NotSupportedException("Encryption is not supported under Mono.");
-#endif
- }
- else
- {
- _package.Save(_stream);
- }
- _stream.Flush();
- _package.Close();
- }
- else
- {
- if (System.IO.File.Exists(File.FullName))
- {
- try
- {
- System.IO.File.Delete(File.FullName);
- }
- catch (Exception ex)
- {
- throw (new Exception(string.Format("Error overwriting file {0}", File.FullName), ex));
- }
- }
-
- _package.Save(_stream);
- _package.Close();
- if (Stream is MemoryStream)
- {
- var fi = new FileStream(File.FullName, FileMode.Create);
- //EncryptPackage
- if (Encryption.IsEncrypted)
- {
-#if !MONO
- byte[] file = ((MemoryStream)Stream).ToArray();
- EncryptedPackageHandler eph = new EncryptedPackageHandler();
- var ms = eph.EncryptPackage(file, Encryption);
-
- fi.Write(ms.GetBuffer(), 0, (int)ms.Length);
-#endif
-#if MONO
- throw new NotSupportedException("Encryption is not supported under Mono.");
-#endif
- }
- else
- {
- fi.Write(((MemoryStream)Stream).GetBuffer(), 0, (int)Stream.Length);
- }
- fi.Close();
- }
- else
- {
- System.IO.File.WriteAllBytes(File.FullName, GetAsByteArray(false));
- }
- }
- }
- catch (Exception ex)
- {
- if (File == null)
- {
- throw;
- }
- else
- {
- throw (new InvalidOperationException(string.Format("Error saving file {0}", File.FullName), ex));
- }
- }
- }
- /// <summary>
- /// Saves all the components back into the package.
- /// This method recursively calls the Save method on all sub-components.
- /// The package is closed after it ha
- /// d to encrypt the workbook with.
- /// </summary>
- /// <param name="password">This parameter overrides the Workbook.Encryption.Password.</param>
- public void Save(string password)
- {
- Encryption.Password = password;
- Save();
- }
- /// <summary>
- /// Saves the workbook to a new file
- /// The package is closed after it has been saved
- /// </summary>
- /// <param name="file">The file location</param>
- public void SaveAs(FileInfo file)
- {
- File = file;
- Save();
- }
- /// <summary>
- /// Saves the workbook to a new file
- /// The package is closed after it has been saved
- /// </summary>
- /// <param name="file">The file</param>
- /// <param name="password">The password to encrypt the workbook with.
- /// This parameter overrides the Encryption.Password.</param>
- public void SaveAs(FileInfo file, string password)
- {
- File = file;
- Encryption.Password = password;
- Save();
- }
- /// <summary>
- /// Copies the Package to the Outstream
- /// The package is closed after it has been saved
- /// </summary>
- /// <param name="OutputStream">The stream to copy the package to</param>
- public void SaveAs(Stream OutputStream)
- {
- File = null;
- Save();
-
- if (OutputStream != _stream)
- {
- if (Encryption.IsEncrypted)
- {
-#if !MONO
- //Encrypt Workbook
- Byte[] file = new byte[Stream.Length];
- long pos = Stream.Position;
- Stream.Seek(0, SeekOrigin.Begin);
- Stream.Read(file, 0, (int) Stream.Length);
- EncryptedPackageHandler eph = new EncryptedPackageHandler();
- var ms = eph.EncryptPackage(file, Encryption);
- CopyStream(ms, ref OutputStream);
-#endif
-#if MONO
- throw new NotSupportedException("Encryption is not supported under Mono.");
-#endif
- }
- else
- {
- CopyStream(_stream, ref OutputStream);
- }
- }
- }
- /// <summary>
- /// Copies the Package to the Outstream
- /// The package is closed after it has been saved
- /// </summary>
- /// <param name="OutputStream">The stream to copy the package to</param>
- /// <param name="password">The password to encrypt the workbook with.
- /// This parameter overrides the Encryption.Password.</param>
- public void SaveAs(Stream OutputStream, string password)
- {
- Encryption.Password = password;
- SaveAs(OutputStream);
- }
- FileInfo _file = null;
-
- /// <summary>
- /// The output file. Null if no file is used
- /// </summary>
- public FileInfo File
- {
- get
- {
- return _file;
- }
- set
- {
- _file = value;
- }
- }
- /// <summary>
- /// The output stream. This stream is the not the encrypted package.
- /// To get the encrypted package use the SaveAs(stream) method.
- /// </summary>
- public Stream Stream
- {
- get
- {
- return _stream;
- }
- }
- #endregion
/// <summary>
/// Compression option for the package
/// </summary>
@@ -927,7 +331,7 @@
internal XmlDocument GetXmlFromUri(Uri uri)
{
XmlDocument xml = new XmlDocument();
- Packaging.ZipPackagePart part = _package.GetPart(uri);
+ Packaging.ZipPackagePart part = Package.GetPart(uri);
XmlHelper.LoadXmlSafe(xml, part.GetStream());
return (xml);
}
@@ -951,187 +355,10 @@
/// <returns></returns>
public byte[] GetAsByteArray()
{
- return GetAsByteArray(true);
- }
- /// <summary>
- /// Saves and returns the Excel files as a bytearray
- /// Note that the package is closed upon save
- /// </summary>
- /// <example>
- /// Example how to return a document from a Webserver...
- /// <code>
- /// ExcelPackage package=new ExcelPackage();
- /// /**** ... Create the document ****/
- /// Byte[] bin = package.GetAsByteArray();
- /// Response.ContentType = "Application/vnd.ms-Excel";
- /// Response.AddHeader("content-disposition", "attachment; filename=TheFile.xlsx");
- /// Response.BinaryWrite(bin);
- /// </code>
- /// </example>
- /// <param name="password">The password to encrypt the workbook with.
- /// This parameter overrides the Encryption.Password.</param>
- /// <returns></returns>
- public byte[] GetAsByteArray(string password)
- {
- if (password != null)
- {
- Encryption.Password = password;
- }
- return GetAsByteArray(true);
- }
- internal byte[] GetAsByteArray(bool save)
- {
- if (save)
- {
- Workbook.Save();
- _package.Close();
- _package.Save(_stream);
- }
- Byte[] byRet = new byte[Stream.Length];
- long pos = Stream.Position;
- Stream.Seek(0, SeekOrigin.Begin);
- Stream.Read(byRet, 0, (int)Stream.Length);
-
- //Encrypt Workbook?
- if (Encryption.IsEncrypted)
- {
-#if !MONO
- EncryptedPackageHandler eph=new EncryptedPackageHandler();
- var ms = eph.EncryptPackage(byRet, Encryption);
- byRet = ms.ToArray();
-#endif
- }
-
- Stream.Seek(pos, SeekOrigin.Begin);
- Stream.Close();
- return byRet;
- }
- /// <summary>
- /// Loads the specified package data from a stream.
- /// </summary>
- /// <param name="input">The input.</param>
- public void Load(Stream input)
- {
- Load(input, new MemoryStream(), null);
- }
- /// <summary>
- /// Loads the specified package data from a stream.
- /// </summary>
- /// <param name="input">The input.</param>
- /// <param name="Password">The password to decrypt the document</param>
- public void Load(Stream input, string Password)
- {
- Load(input, new MemoryStream(), Password);
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="input"></param>
- /// <param name="output"></param>
- /// <param name="Password"></param>
- private void Load(Stream input, Stream output, string Password)
- {
- //Release some resources:
- if (this._package != null)
- {
- this._package.Close();
- this._package = null;
- }
- if (this._stream != null)
- {
- this._stream.Close();
- this._stream.Dispose();
- this._stream = null;
- }
- _isExternalStream = true;
- if (input.Length == 0) // Template is blank, Construct new
- {
- _stream = output;
- ConstructNewFile(Password);
- }
- else
- {
- Stream ms;
- this._stream = output;
- if (Password != null)
- {
-#if !MONO
- Stream encrStream = new MemoryStream();
- CopyStream(input, ref encrStream);
- EncryptedPackageHandler eph = new EncryptedPackageHandler();
- Encryption.Password = Password;
- ms = eph.DecryptPackage((MemoryStream)encrStream, Encryption);
-#endif
-#if MONO
- throw new NotSupportedException("Encryption is not supported under Mono.");
-#endif
- }
- else
- {
- ms = new MemoryStream();
- CopyStream(input, ref ms);
- }
-
- try
- {
- //this._package = Package.Open(this._stream, FileMode.Open, FileAccess.ReadWrite);
- _package = new Packaging.ZipPackage(ms);
- }
- catch (Exception ex)
- {
-#if !MONO
- EncryptedPackageHandler eph = new EncryptedPackageHandler();
- if (Password == null && CompoundDocument.IsStorageILockBytes(CompoundDocument.GetLockbyte((MemoryStream)_stream)) == 0)
- {
- 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);
- }
- else
- {
- throw;
- }
-#endif
-#if MONO
- throw;
-#endif
- }
- }
- //Clear the workbook so that it gets reinitialized next time
- this._workbook = null;
- }
- static object _lock=new object();
- /// <summary>
- /// Copies the input stream to the output stream.
- /// </summary>
- /// <param name="inputStream">The input stream.</param>
- /// <param name="outputStream">The output stream.</param>
- internal static void CopyStream(Stream inputStream, ref Stream outputStream)
- {
- if (!inputStream.CanRead)
- {
- throw (new Exception("Can not read from inputstream"));
- }
- if (!outputStream.CanWrite)
- {
- throw (new Exception("Can not write to outputstream"));
- }
- if (inputStream.CanSeek)
- {
- inputStream.Seek(0, SeekOrigin.Begin);
- }
-
- const int bufferLength = 8096;
- var buffer = new Byte[bufferLength];
- lock (_lock)
- {
- int bytesRead = inputStream.Read(buffer, 0, bufferLength);
- // write the required bytes
- while (bytesRead > 0)
- {
- outputStream.Write(buffer, 0, bytesRead);
- bytesRead = inputStream.Read(buffer, 0, bufferLength);
- }
- outputStream.Flush();
- }
+ var result = new MemoryStream();
+ Workbook.Save();
+ Package.Save(result);
+ return result.ToArray();
}
}
}
\ No newline at end of file
diff --git a/EPPlus/ExcelProtectedRange.cs b/EPPlus/ExcelProtectedRange.cs
index 6a9d45c..bb66945 100644
--- a/EPPlus/ExcelProtectedRange.cs
+++ b/EPPlus/ExcelProtectedRange.cs
@@ -1,60 +1,8 @@
using OfficeOpenXml.Utils;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Security.Cryptography;
-using System.Text;
using System.Xml;
namespace OfficeOpenXml
{
- /// <summary>
- /// Algorithm for password hash
- /// </summary>
- internal enum eProtectedRangeAlgorithm
- {
- /// <summary>
- /// Specifies that the MD2 algorithm, as defined by RFC 1319, shall be used.
- /// </summary>
- MD2,
- /// <summary>
- /// Specifies that the MD4 algorithm, as defined by RFC 1319, shall be used.
- /// </summary>
- MD4,
- /// <summary>
- /// Specifies that the MD5 algorithm, as defined by RFC 1319, shall be used.
- /// </summary>
- MD5,
- /// <summary>
- /// Specifies that the RIPEMD-128 algorithm, as defined by RFC 1319, shall be used.
- /// </summary>
- RIPEMD128,
- /// <summary>
- /// Specifies that the RIPEMD-160 algorithm, as defined by ISO/IEC10118-3:2004 shall be used.
- /// </summary>
- RIPEMD160,
- /// <summary>
- /// Specifies that the SHA-1 algorithm, as defined by ISO/IEC 10118-3:2004 shall be used.
- /// </summary>
- SHA1,
- /// <summary>
- /// Specifies that the SHA-256 algorithm, as defined by ISO/IEC10118-3:2004 shall be used.
- /// </summary>
- SHA256,
- /// <summary>
- /// Specifies that the SHA-384 algorithm, as defined by ISO/IEC 10118-3:2004 shall be used.
- /// </summary>
- SHA384,
- /// <summary>
- /// Specifies that the SHA-512 algorithm, as defined by ISO/IEC10118-3:2004 shall be used.
- /// </summary>
- SHA512,
- /// <summary>
- /// Specifies that the WHIRLPOOL algorithm, as defined by ISO/IEC 10118-3:2004 shall be used.
- /// </summary>
- WHIRLPOOL
- }
public class ExcelProtectedRange : XmlHelper
{
public string Name
@@ -92,103 +40,5 @@
Name = name;
Address = address;
}
- /// <summary>
- /// Sets the password for the range
- /// </summary>
- /// <param name="password"></param>
- public void SetPassword(string password)
- {
- var byPwd = Encoding.Unicode.GetBytes(password);
- var rnd = RandomNumberGenerator.Create();
- var bySalt=new byte[16];
- rnd.GetBytes(bySalt);
-
- //Default SHA512 and 10000 spins
- Algorithm=eProtectedRangeAlgorithm.SHA512;
- SpinCount = SpinCount < 100000 ? 100000 : SpinCount;
-
- //Combine salt and password and calculate the initial hash
- var hp=new SHA512CryptoServiceProvider();
- var buffer=new byte[byPwd.Length + bySalt.Length];
- Array.Copy(bySalt, buffer, bySalt.Length);
- Array.Copy(byPwd, 0, buffer, 16, byPwd.Length);
- var hash = hp.ComputeHash(buffer);
-
- //Now iterate the number of spinns.
- for (var i = 0; i < SpinCount; i++)
- {
- buffer=new byte[hash.Length+4];
- Array.Copy(hash, buffer, hash.Length);
- Array.Copy(BitConverter.GetBytes(i), 0, buffer, hash.Length, 4);
- hash = hp.ComputeHash(buffer);
- }
- Salt = Convert.ToBase64String(bySalt);
- Hash = Convert.ToBase64String(hash);
- }
- public string SecurityDescriptor
- {
- get
- {
- return GetXmlNodeString("@securityDescriptor");
- }
- set
- {
- SetXmlNodeString("@securityDescriptor",value);
- }
- }
- internal int SpinCount
- {
- get
- {
- return GetXmlNodeInt("@spinCount");
- }
- set
- {
- SetXmlNodeString("@spinCount",value.ToString(CultureInfo.InvariantCulture));
- }
- }
- internal string Salt
- {
- get
- {
- return GetXmlNodeString("@saltValue");
- }
- set
- {
- SetXmlNodeString("@saltValue", value);
- }
- }
- internal string Hash
- {
- get
- {
- return GetXmlNodeString("@hashValue");
- }
- set
- {
- SetXmlNodeString("@hashValue", value);
- }
- }
- internal eProtectedRangeAlgorithm Algorithm
- {
- get
- {
- var v=GetXmlNodeString("@algorithmName");
- return (eProtectedRangeAlgorithm)Enum.Parse(typeof(eProtectedRangeAlgorithm), v.Replace("-", ""));
- }
- set
- {
- var v = value.ToString();
- if(v.StartsWith("SHA"))
- {
- v=v.Insert(3,"-");
- }
- else if(v.StartsWith("RIPEMD"))
- {
- v=v.Insert(6,"-");
- }
- SetXmlNodeString("@algorithmName", v);
- }
- }
}
}
diff --git a/EPPlus/ExcelProtection.cs b/EPPlus/ExcelProtection.cs
index 3bee61e..6e307a3 100644
--- a/EPPlus/ExcelProtection.cs
+++ b/EPPlus/ExcelProtection.cs
@@ -29,12 +29,7 @@
* Jan Källman Added 10-AUG-2010
* Jan Källman License changed GPL-->LGPL 2011-12-27
*******************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.Text;
using System.Xml;
-using OfficeOpenXml.Utils;
-using OfficeOpenXml.Encryption;
namespace OfficeOpenXml
{
/// <summary>
@@ -49,22 +44,6 @@
{
SchemaNodeOrder = wb.SchemaNodeOrder;
}
- const string workbookPasswordPath = "d:workbookProtection/@workbookPassword";
- /// <summary>
- /// Sets a password for the workbook. This does not encrypt the workbook.
- /// </summary>
- /// <param name="Password">The password. </param>
- public void SetPassword(string Password)
- {
- if(string.IsNullOrEmpty(Password))
- {
- DeleteNode(workbookPasswordPath);
- }
- else
- {
- SetXmlNodeString(workbookPasswordPath, ((int)EncryptedPackageHandler.CalculatePasswordHash(Password)).ToString("x"));
- }
- }
const string lockStructurePath = "d:workbookProtection/@lockStructure";
/// <summary>
/// Locks the structure,which prevents users from adding or deleting worksheets or from displaying hidden worksheets.
diff --git a/EPPlus/ExcelRangeBase.cs b/EPPlus/ExcelRangeBase.cs
index d3c3c20..a4cf198 100644
--- a/EPPlus/ExcelRangeBase.cs
+++ b/EPPlus/ExcelRangeBase.cs
@@ -736,7 +736,7 @@
toRow = addr._toRow > d._toRow ? d._toRow : addr._toRow;
toCol = addr._toCol > d._toCol ? d._toCol : addr._toCol;
- if (addr._fromCol == fromRow && addr._fromCol == addr._fromCol && addr._toRow == toRow && addr._toCol == _toCol)
+ if (addr._fromCol == fromRow && addr._toRow == toRow && addr._toCol == _toCol)
{
return addr;
}
@@ -2645,7 +2645,6 @@
public void Dispose()
{
- //_worksheet = null;
}
#endregion
diff --git a/EPPlus/ExcelSheetProtection.cs b/EPPlus/ExcelSheetProtection.cs
index 83c649c..2caa7b9 100644
--- a/EPPlus/ExcelSheetProtection.cs
+++ b/EPPlus/ExcelSheetProtection.cs
@@ -29,13 +29,7 @@
* Jan Källman Initial Release 2010-03-14
* Jan Källman License changed GPL-->LGPL 2011-12-27
*******************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.Text;
using System.Xml;
-using System.Security.Cryptography;
-using OfficeOpenXml.Utils;
-using OfficeOpenXml.Encryption;
namespace OfficeOpenXml
{
@@ -304,30 +298,5 @@
SetXmlNodeBool(_allowPivotTablesPath, !value, true);
}
}
-
- private const string _passwordPath = "d:sheetProtection/@password";
- /// <summary>
- /// Sets a password for the sheet.
- /// </summary>
- /// <param name="Password"></param>
- public void SetPassword(string Password)
- {
- if (IsProtected == false) IsProtected = true;
-
- Password = Password.Trim();
- if (Password == "")
- {
- var node = TopNode.SelectSingleNode(_passwordPath, NameSpaceManager);
- if (node != null)
- {
- (node as XmlAttribute).OwnerElement.Attributes.Remove(node as XmlAttribute);
- }
- return;
- }
-
- int hash = EncryptedPackageHandler.CalculatePasswordHash(Password);
- SetXmlNodeString(_passwordPath, ((int)hash).ToString("x"));
- }
-
}
}
diff --git a/EPPlus/ExcelStyles.cs b/EPPlus/ExcelStyles.cs
index 62df309..cfaed4d 100644
--- a/EPPlus/ExcelStyles.cs
+++ b/EPPlus/ExcelStyles.cs
@@ -4,7 +4,7 @@
* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
* See http://www.codeplex.com/EPPlus for details.
*
- * Copyright (C) 2011 Jan Källman
+ * Copyright (C) 2011 Jan K�llman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,15 +26,13 @@
*
* Author Change Date
* ******************************************************************************
- * Jan Källman Initial Release 2009-10-01
- * Jan Källman License changed GPL-->LGPL 2011-12-27
+ * Jan K�llman Initial Release 2009-10-01
+ * Jan K�llman License changed GPL-->LGPL 2011-12-27
*******************************************************************************/
using System;
using System.Xml;
using System.Linq;
using System.Collections.Generic;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-using draw=System.Drawing;
using OfficeOpenXml.Style;
using OfficeOpenXml.Style.XmlAccess;
using OfficeOpenXml.Style.Dxf;
@@ -340,7 +338,6 @@
}
}
ws.SetStyle(rowNum, 0, s);
- cse.Dispose();
}
if (styleCashe.ContainsKey(s))
{
diff --git a/EPPlus/ExcelWorkbook.cs b/EPPlus/ExcelWorkbook.cs
index ba02560..f529826 100644
--- a/EPPlus/ExcelWorkbook.cs
+++ b/EPPlus/ExcelWorkbook.cs
@@ -70,7 +70,7 @@
/// Represents the Excel workbook and provides access to all the
/// document properties and worksheets within the workbook.
/// </summary>
- public sealed class ExcelWorkbook : XmlHelper, IDisposable
+ public sealed class ExcelWorkbook : XmlHelper
{
internal class SharedStringItem
{
@@ -292,8 +292,6 @@
}
}
#region Workbook Properties
- decimal _standardFontWidth = decimal.MinValue;
- string _fontID = "";
internal FormulaParser FormulaParser
{
get
@@ -318,87 +316,6 @@
}
}
- /// <summary>
- /// Max font width for the workbook
- /// <remarks>This method uses GDI. If you use Asure or another environment that does not support GDI, you have to set this value manually if you don't use the standard Calibri font</remarks>
- /// </summary>
- public decimal MaxFontWidth
- {
- get
- {
- if (_standardFontWidth == decimal.MinValue || _fontID != Styles.Fonts[0].Id)
- {
- var font = Styles.Fonts[0];
- try
- {
- var f = new Font(font.Name, font.Size);
- _standardFontWidth = 0;
- _fontID = font.Id;
-
- //Remove the PresentaionCore Dependencey. This might effect components running under Azure not having support for GDI+
-
- //Typeface tf = new Typeface(new System.Windows.Media.FontFamily(font.Name),
- //// (font.Italic) ? FontStyles.Normal : FontStyles.Italic,
- // (font.Bold) ? FontWeights.Bold : FontWeights.Normal,
- // FontStretches.Normal);
- //for(int i=0;i<10;i++)
- //{
- // var ft = new System.Windows.Media.FormattedText("0123456789".Substring(i,1), CultureInfo.InvariantCulture, System.Windows.FlowDirection.LeftToRight, tf, font.Size * (96D / 72D), new DrawingBrush());
- // var width=(int)Math.Round(ft.Width,0);
- // if(width>_standardFontWidth)
- // {
- // _standardFontWidth = width;
- // }
- //}
-
- //var size = new System.Windows.Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
-
- _standardFontWidth = GetWidthPixels(f,"1234567890");
- if (_standardFontWidth <= 0) //No GDI?
- {
- _standardFontWidth = (int)(font.Size * (2D / 3D)); //Aprox. for Calibri.
- }
- }
- catch //Error, set default value
- {
- _standardFontWidth = (int)(font.Size * (2D / 3D)); //Aprox for Calibri.
- }
- }
- return _standardFontWidth;
- }
- set
- {
- _standardFontWidth = value;
- }
- }
-
- internal static decimal GetWidthPixels(Font f, string s)
- {
- var ret = 0M;
- using (var b = new Bitmap(1, 1))
- {
- using (Graphics g = Graphics.FromImage(b))
- {
- g.PageUnit = GraphicsUnit.Pixel;
-
- for (int i = 0; i < s.Length; i++)
- {
- var c = s[i];
- var width =
- (decimal)
- Math.Truncate(
- g.MeasureString(new string(c, 2), f, 1000, StringFormat.GenericTypographic).Width -
- g.MeasureString(new string(c, 1), f, 1000, StringFormat.GenericTypographic).Width);
- if (width > ret)
- {
- ret = width;
- }
- }
- }
- }
- return ret;
- }
-
ExcelProtection _protection = null;
/// <summary>
/// Access properties to protect or unprotect a workbook
@@ -545,7 +462,6 @@
StreamWriter stream = new StreamWriter(partWorkbook.GetStream(FileMode.Create, FileAccess.Write));
_workbookXml.Save(stream);
//stream.Close();
- _package.Package.Flush();
}
}
#endregion
@@ -587,11 +503,9 @@
_stylesXml.Save(stream);
//stream.Close();
- _package.Package.Flush();
// create the relationship between the workbook and the new shared strings part
_package.Workbook.Part.CreateRelationship(UriHelper.GetRelativeUri(WorkbookUri, StylesUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/styles");
- _package.Package.Flush();
}
}
return (_stylesXml);
@@ -1003,33 +917,7 @@
}
}
}
-
- public void Dispose()
- {
- if (_sharedStrings != null)
- {
- _sharedStrings.Clear();
- _sharedStrings = null;
- }
- if (_sharedStringsList != null)
- {
- _sharedStringsList.Clear();
- _sharedStringsList = null;
- }
- if (_worksheets != null)
- {
- _worksheets.Dispose();
- _worksheets = null;
- }
- _package = null;
- _properties = null;
- if (_formulaParser != null)
- {
- _formulaParser.Dispose();
- _formulaParser = null;
- }
- }
-
+
internal void ReadAllTables()
{
if (_nextTableID > 0) return;
diff --git a/EPPlus/ExcelWorksheet.cs b/EPPlus/ExcelWorksheet.cs
index f8b6aeb..c2bf6e7 100644
--- a/EPPlus/ExcelWorksheet.cs
+++ b/EPPlus/ExcelWorksheet.cs
@@ -90,7 +90,7 @@
/// <summary>
/// Represents an Excel worksheet and provides access to its properties and methods
/// </summary>
- public class ExcelWorksheet : XmlHelper, IEqualityComparer<ExcelWorksheet>, IDisposable
+ public class ExcelWorksheet : XmlHelper, IEqualityComparer<ExcelWorksheet>
{
internal class Formulas
{
@@ -4105,48 +4105,7 @@
}
return styleId;
}
-
- private void DisposeInternal(IDisposable candidateDisposable)
- {
- if (candidateDisposable != null)
- {
- candidateDisposable.Dispose();
- }
- }
-
-
- public void Dispose()
- {
- DisposeInternal(_values);
- DisposeInternal(_formulas);
- DisposeInternal(_flags);
- DisposeInternal(_hyperLinks);
- DisposeInternal(_styles);
- DisposeInternal(_types);
- DisposeInternal(_commentsStore);
- DisposeInternal(_formulaTokens);
-
- _values = null;
- _formulas = null;
- _flags = null;
- _hyperLinks = null;
- _styles = null;
- _types = null;
- _commentsStore = null;
- _formulaTokens = null;
-
- _package = null;
- _pivotTables = null;
- _protection = null;
- if(_sharedFormulas != null) _sharedFormulas.Clear();
- _sharedFormulas = null;
- _sheetView = null;
- _tables = null;
- _vmlDrawings = null;
- _conditionalFormatting = null;
- _dataValidation = null;
- }
-
+
/// <summary>
/// Get the ExcelColumn for column (span ColumnMin and ColumnMax)
/// </summary>
diff --git a/EPPlus/ExcelWorksheets.cs b/EPPlus/ExcelWorksheets.cs
index 475af58..18c2ecf 100644
--- a/EPPlus/ExcelWorksheets.cs
+++ b/EPPlus/ExcelWorksheets.cs
@@ -34,14 +34,13 @@
using System.Collections.Generic;
using System.Xml;
using System.IO;
-using System.Linq;
using OfficeOpenXml.Utils;
namespace OfficeOpenXml
{
/// <summary>
/// The collection of worksheets for the workbook
/// </summary>
- public class ExcelWorksheets : XmlHelper, IEnumerable<ExcelWorksheet>, IDisposable
+ public class ExcelWorksheets : XmlHelper, IEnumerable<ExcelWorksheet>
{
#region Private Properties
private ExcelPackage _pck;
@@ -154,7 +153,6 @@
StreamWriter streamWorksheet = new StreamWriter(worksheetPart.GetStream(FileMode.Create, FileAccess.Write));
XmlDocument worksheetXml = CreateNewWorksheet(false);
worksheetXml.Save(streamWorksheet);
- _pck.Package.Flush();
string rel = CreateWorkbookRel(Name, sheetID, uriWorksheet, false);
@@ -174,7 +172,6 @@
{
//Create the relationship between the workbook and the new worksheet
var rel = _pck.Workbook.Part.CreateRelationship(UriHelper.GetRelativeUri(_pck.Workbook.WorkbookUri, uriWorksheet), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/" + (isChart ? "chartsheet" : "worksheet"));
- _pck.Package.Flush();
//Create the new sheet node
XmlElement worksheetNode = _pck.Workbook.WorkbookXml.CreateElement("sheet", ExcelPackage.schemaMain);
@@ -527,14 +524,5 @@
}
#endregion
- public void Dispose()
- {
- foreach (var sheet in this._worksheets.Values)
- {
- ((IDisposable)sheet).Dispose();
- }
- _worksheets = null;
- _pck = null;
- }
} // end class Worksheets
}
diff --git a/EPPlus/FormulaParsing/CalculateExtentions.cs b/EPPlus/FormulaParsing/CalculateExtentions.cs
index 22637ac..69bc3ee 100644
--- a/EPPlus/FormulaParsing/CalculateExtentions.cs
+++ b/EPPlus/FormulaParsing/CalculateExtentions.cs
@@ -52,33 +52,7 @@
var dc = DependencyChainFactory.Create(workbook, options);
workbook.FormulaParser.InitNewCalc();
- if (workbook.FormulaParser.Logger != null)
- {
- var msg = string.Format("Starting... number of cells to parse: {0}", dc.list.Count);
- workbook.FormulaParser.Logger.Log(msg);
- }
-
- //TODO: Remove when tests are done. Outputs the dc to a text file.
- //var fileDc = new System.IO.StreamWriter("c:\\temp\\dc.txt");
-
- //for (int i = 0; i < dc.list.Count; i++)
- //{
- // fileDc.WriteLine(i.ToString() + "," + dc.list[i].Column.ToString() + "," + dc.list[i].Row.ToString() + "," + (dc.list[i].ws==null ? "" : dc.list[i].ws.Name) + "," + dc.list[i].Formula);
- //}
- //fileDc.Close();
- //fileDc = new System.IO.StreamWriter("c:\\temp\\dcorder.txt");
- //for (int i = 0; i < dc.CalcOrder.Count; i++)
- //{
- // fileDc.WriteLine(dc.CalcOrder[i].ToString());
- //}
- //fileDc.Close();
- //fileDc = null;
-
- //TODO: Add calculation here
-
CalcChain(workbook, workbook.FormulaParser, dc);
-
- //workbook._isCalculated = true;
}
public static void Calculate(this ExcelWorksheet worksheet)
{
@@ -96,11 +70,6 @@
var parser = worksheet.Workbook.FormulaParser;
parser.InitNewCalc();
- if (parser.Logger != null)
- {
- var msg = string.Format("Starting... number of cells to parse: {0}", dc.list.Count);
- parser.Logger.Log(msg);
- }
CalcChain(worksheet.Workbook, parser, dc);
}
@@ -175,7 +144,6 @@
}
private static void CalcChain(ExcelWorkbook wb, FormulaParser parser, DependencyChain dc)
{
- var debug = parser.Logger != null;
foreach (var ix in dc.CalcOrder)
{
var item = dc.list[ix];
@@ -184,22 +152,17 @@
var ws = wb.Worksheets.GetBySheetID(item.SheetID);
var v = parser.ParseCell(item.Tokens, ws == null ? "" : ws.Name, item.Row, item.Column);
SetValue(wb, item, v);
- if (debug)
- {
- parser.Logger.LogCellCounted();
- }
- Thread.Sleep(0);
}
- catch (OfficeOpenXml.FormulaParsing.Excel.Functions.FunctionException functionex)
+ catch (OfficeOpenXml.FormulaParsing.Excel.Functions.FunctionException)
{
// Excel function is not supported by EPPlus
- throw (functionex);
+ throw;
}
- catch (FormatException fe)
+ catch (FormatException)
{
- throw (fe);
+ throw;
}
- catch (Exception e)
+ catch (Exception)
{
var error = ExcelErrorValue.Parse(ExcelErrorValue.Values.Value);
SetValue(wb, item, error);
@@ -213,10 +176,6 @@
{
if (!(ws is ExcelChartsheet))
{
- if (ws._formulaTokens != null)
- {
- ws._formulaTokens.Dispose();
- }
ws._formulaTokens = new CellStore<List<Token>>();
}
}
diff --git a/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs b/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs
index 5e751ab..174f303 100644
--- a/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs
+++ b/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs
@@ -1,10 +1,6 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using OfficeOpenXml.FormulaParsing;
using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
using OfficeOpenXml.Utils;
using OfficeOpenXml.Style.XmlAccess;
@@ -96,9 +92,6 @@
public void Dispose()
{
- //_values = null;
- //_ws = null;
- //_cell = null;
}
object System.Collections.IEnumerator.Current
@@ -303,9 +296,9 @@
ExcelWorksheet ws;
if (string.IsNullOrEmpty(worksheet))
{
- if(_package._workbook.Names.ContainsKey(name))
+ if(_package.Workbook.Names.ContainsKey(name))
{
- nameItem = _package._workbook.Names[name];
+ nameItem = _package.Workbook.Names[name];
}
else
{
@@ -315,14 +308,14 @@
}
else
{
- ws = _package._workbook.Worksheets[worksheet];
+ ws = _package.Workbook.Worksheets[worksheet];
if (ws !=null && ws.Names.ContainsKey(name))
{
nameItem = ws.Names[name];
}
- else if (_package._workbook.Names.ContainsKey(name))
+ else if (_package.Workbook.Names.ContainsKey(name))
{
- nameItem = _package._workbook.Names[name];
+ nameItem = _package.Workbook.Names[name];
}
else
{
@@ -426,21 +419,6 @@
}
- //public override void SetCellValue(string address, object value)
- //{
- // var addressInfo = ExcelAddressInfo.Parse(address);
- // var ra = _rangeAddressFactory.Create(address);
- // SetCurrentWorksheet(addressInfo);
- // //var valueInfo = (ICalcEngineValueInfo)_currentWorksheet;
- // //valueInfo.SetFormulaValue(ra.FromRow + 1, ra.FromCol + 1, value);
- // _currentWorksheet.Cells[ra.FromRow + 1, ra.FromCol + 1].Value = value;
- //}
-
- public override void Dispose()
- {
- _package.Dispose();
- }
-
public override int ExcelMaxColumns
{
get { return ExcelPackage.MaxColumns; }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs
index 85908ac..522e810 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs
@@ -54,7 +54,6 @@
private void Initialize()
{
- var fo = 1;
for (var x = _fromCol; x <= _toCol; x++)
{
var fieldObj = _dataProvider.GetCellValue(_worksheet, _fieldRow, x);
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs
index 4b90546..818cc56 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs
@@ -94,10 +94,6 @@
{
// Report that Excel function is not supported by EPPlus
throw new FunctionException(string.Format("Excel function '{0}' is not supported in formulas.", name));
-
- //throw new InvalidOperationException("Non supported function: " + name);
- //throw new ExcelErrorValueException("Non supported function: " + name, ExcelErrorValue.Create(eErrorType.Name));
- return null;
}
return _functions[name.ToLower(CultureInfo.InvariantCulture)];
}
diff --git a/EPPlus/FormulaParsing/ExcelDataProvider.cs b/EPPlus/FormulaParsing/ExcelDataProvider.cs
index 42f996b..17f1257 100644
--- a/EPPlus/FormulaParsing/ExcelDataProvider.cs
+++ b/EPPlus/FormulaParsing/ExcelDataProvider.cs
@@ -1,8 +1,5 @@
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
namespace OfficeOpenXml.FormulaParsing
{
@@ -10,7 +7,7 @@
/// This class should be implemented to be able to deliver excel data
/// to the formula parser.
/// </summary>
- public abstract class ExcelDataProvider : IDisposable
+ public abstract class ExcelDataProvider
{
/// <summary>
/// A range of cells in a worksheet.
@@ -108,11 +105,6 @@
public abstract ExcelCellAddress GetDimensionEnd(string worksheet);
/// <summary>
- /// Use this method to free unmanaged resources.
- /// </summary>
- public abstract void Dispose();
-
- /// <summary>
/// Max number of columns in a worksheet that the Excel data provider can handle.
/// </summary>
public abstract int ExcelMaxColumns { get; }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
index d1959c6..7abc32e 100644
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
+++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
@@ -106,7 +106,7 @@
{
return double.Parse(Result.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture);
}
- catch (Exception ex)
+ catch (Exception)
{
return 0;
}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs
index 563c81b..a409632 100644
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs
+++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs
@@ -38,7 +38,7 @@
}
}
- catch (ExcelErrorValueException ex)
+ catch (ExcelErrorValueException)
{
args.Add(new FunctionArgument(lastChild.Compile().Result));
}
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs
index e316a79..ecfff31 100644
--- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs
+++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs
@@ -36,7 +36,7 @@
}
}
- catch (ExcelErrorValueException ex)
+ catch (ExcelErrorValueException)
{
args.Add(new FunctionArgument(lastChild.Compile().Result));
}
diff --git a/EPPlus/FormulaParsing/FormulaParser.cs b/EPPlus/FormulaParsing/FormulaParser.cs
index e025114..a7ad2d8 100644
--- a/EPPlus/FormulaParsing/FormulaParser.cs
+++ b/EPPlus/FormulaParsing/FormulaParser.cs
@@ -31,22 +31,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
using OfficeOpenXml.FormulaParsing.ExpressionGraph;
-using OfficeOpenXml.FormulaParsing;
-using OfficeOpenXml.FormulaParsing.Excel.Operators;
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
-using OfficeOpenXml.FormulaParsing.Excel;
using OfficeOpenXml.FormulaParsing.Excel.Functions;
using OfficeOpenXml.FormulaParsing.ExcelUtilities;
-using OfficeOpenXml.FormulaParsing.Logging;
using OfficeOpenXml.FormulaParsing.Utilities;
-using System.Diagnostics;
using OfficeOpenXml.FormulaParsing.Exceptions;
namespace OfficeOpenXml.FormulaParsing
{
- public class FormulaParser : IDisposable
+ public class FormulaParser
{
private readonly ParsingContext _parsingContext;
private readonly ExcelDataProvider _excelDataProvider;
@@ -228,18 +222,5 @@
return graph;
}
}
-
- public IFormulaParserLogger Logger
- {
- get { return _parsingContext.Configuration.Logger; }
- }
-
- public void Dispose()
- {
- if (_parsingContext.Debug)
- {
- _parsingContext.Configuration.Logger.Dispose();
- }
- }
}
}
diff --git a/EPPlus/FormulaParsing/FormulaParserManager.cs b/EPPlus/FormulaParsing/FormulaParserManager.cs
index aa9658b..51a5234 100644
--- a/EPPlus/FormulaParsing/FormulaParserManager.cs
+++ b/EPPlus/FormulaParsing/FormulaParserManager.cs
@@ -102,31 +102,5 @@
{
return _parser.ParseToGraph(formula);
}
-
- /// <summary>
- /// Attaches a logger to the <see cref="FormulaParser"/>.
- /// </summary>
- /// <param name="logger">An instance of <see cref="IFormulaParserLogger"/></param>
- /// <see cref="OfficeOpenXml.FormulaParsing.Logging.LoggerFactory"/>
- public void AttachLogger(IFormulaParserLogger logger)
- {
- _parser.Configure(c => c.AttachLogger(logger));
- }
-
- /// <summary>
- /// Attaches a logger to the formula parser that produces output to the supplied logfile.
- /// </summary>
- /// <param name="logfile"></param>
- public void AttachLogger(FileInfo logfile)
- {
- _parser.Configure(c => c.AttachLogger(LoggerFactory.CreateTextFileLogger(logfile)));
- }
- /// <summary>
- /// Detaches any attached logger from the formula parser.
- /// </summary>
- public void DetachLogger()
- {
- _parser.Configure(c => c.DetachLogger());
- }
}
}
diff --git a/EPPlus/FormulaParsing/Logging/LoggerFactory.cs b/EPPlus/FormulaParsing/Logging/LoggerFactory.cs
deleted file mode 100644
index 3b30e81..0000000
--- a/EPPlus/FormulaParsing/Logging/LoggerFactory.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-
-namespace OfficeOpenXml.FormulaParsing.Logging
-{
- /// <summary>
- /// Create loggers that can be used for logging the formula parser.
- /// </summary>
- public static class LoggerFactory
- {
- /// <summary>
- /// Creates a logger that logs to a simple textfile.
- /// </summary>
- /// <param name="file"></param>
- /// <returns></returns>
- public static IFormulaParserLogger CreateTextFileLogger(FileInfo file)
- {
- return new TextFileLogger(file);
- }
- }
-}
diff --git a/EPPlus/FormulaParsing/Logging/TextFileLogger.cs b/EPPlus/FormulaParsing/Logging/TextFileLogger.cs
deleted file mode 100644
index abc9f17..0000000
--- a/EPPlus/FormulaParsing/Logging/TextFileLogger.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
-
-namespace OfficeOpenXml.FormulaParsing.Logging
-{
- internal class TextFileLogger : IFormulaParserLogger
- {
- private StreamWriter _sw;
- private const string Separator = "=================================";
- private int _count;
- private DateTime _startTime = DateTime.Now;
- private Dictionary<string, int> _funcs = new Dictionary<string, int>();
- private Dictionary<string, long> _funcPerformance = new Dictionary<string, long>();
- internal TextFileLogger(FileInfo fileInfo)
- {
- _sw = new StreamWriter(fileInfo.FullName);
- }
-
- private void WriteSeparatorAndTimeStamp()
- {
- _sw.WriteLine(Separator);
- _sw.WriteLine("Timestamp: {0}", DateTime.Now);
- _sw.WriteLine();
- }
-
- private void WriteAddressInfo(ParsingContext context)
- {
- if (context.Scopes.Current != null && context.Scopes.Current.Address != null)
- {
- _sw.WriteLine("Worksheet: {0}", context.Scopes.Current.Address.Worksheet ?? "<not specified>");
- _sw.WriteLine("Address: {0}", context.Scopes.Current.Address.Address ?? "<not available>");
- }
- }
-
- public void Log(ParsingContext context, Exception ex)
- {
- WriteSeparatorAndTimeStamp();
- WriteAddressInfo(context);
- _sw.WriteLine(ex);
- _sw.WriteLine();
- }
-
- public void Log(ParsingContext context, string message)
- {
- WriteSeparatorAndTimeStamp();
- WriteAddressInfo(context);
- _sw.WriteLine(message);
- _sw.WriteLine();
- }
-
- public void Log(string message)
- {
- WriteSeparatorAndTimeStamp();
- _sw.WriteLine(message);
- _sw.WriteLine();
- }
-
- public void LogCellCounted()
- {
- _count++;
- if (_count%500 == 0)
- {
- _sw.WriteLine(Separator);
- var timeEllapsed = DateTime.Now.Subtract(_startTime);
- _sw.WriteLine("{0} cells parsed, time {1} seconds", _count, timeEllapsed.TotalSeconds);
-
- var funcs = _funcs.Keys.OrderByDescending(x => _funcs[x]).ToList();
- foreach (var func in funcs)
- {
- _sw.Write(func + " - " + _funcs[func]);
- if (_funcPerformance.ContainsKey(func))
- {
- _sw.Write(" - avg: " + _funcPerformance[func]/_funcs[func] + " milliseconds");
- }
- _sw.WriteLine();
- }
- _sw.WriteLine();
- _funcs.Clear();
-
- }
- }
-
- public void LogFunction(string func)
- {
- if (!_funcs.ContainsKey(func))
- {
- _funcs.Add(func, 0);
- }
- _funcs[func]++;
- }
-
- public void LogFunction(string func, long milliseconds)
- {
- if (!_funcPerformance.ContainsKey(func))
- {
- _funcPerformance[func] = 0;
- }
- _funcPerformance[func] += milliseconds;
- }
-
- public void Dispose()
- {
- _sw.Close();
- _sw.Dispose();
- }
- }
-}
diff --git a/EPPlus/OfficeProperties.cs b/EPPlus/OfficeProperties.cs
index 6e29d78..d9e83ba 100644
--- a/EPPlus/OfficeProperties.cs
+++ b/EPPlus/OfficeProperties.cs
@@ -4,7 +4,7 @@
* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
* See http://www.codeplex.com/EPPlus for details.
*
- * Copyright (C) 2011 Jan Källman
+ * Copyright (C) 2011 Jan K�llman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,9 +26,9 @@
*
* Author Change Date
* ******************************************************************************
- * Jan Källman Initial Release 2009-10-01
- * Jan Källman Total rewrite 2010-03-01
- * Jan Källman License changed GPL-->LGPL 2011-12-27
+ * Jan K�llman Initial Release 2009-10-01
+ * Jan K�llman Total rewrite 2010-03-01
+ * Jan K�llman License changed GPL-->LGPL 2011-12-27
* Raziq York Added Created & Modified 2014-08-20
*******************************************************************************/
using System;
@@ -117,11 +117,9 @@
StreamWriter stream = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
xmlDoc.Save(stream);
//stream.Close();
- _package.Package.Flush();
// create the relationship between the workbook and the new shared strings part
_package.Package.CreateRelationship(UriHelper.GetRelativeUri(new Uri("/xl", UriKind.Relative), uri), Packaging.TargetMode.Internal, relationship);
- _package.Package.Flush();
}
return xmlDoc;
}
diff --git a/EPPlus/Packaging/ZipPackage.cs b/EPPlus/Packaging/ZipPackage.cs
index c47d5ea..12e3431 100644
--- a/EPPlus/Packaging/ZipPackage.cs
+++ b/EPPlus/Packaging/ZipPackage.cs
@@ -94,7 +94,7 @@
{
var rels = new Dictionary<string, ZipArchiveEntry>();
stream.Seek(0, SeekOrigin.Begin);
- using var zip = new ZipArchive(stream);
+ using var zip = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true);
foreach (var e in zip.Entries)
{
if (e.Length > 0)
@@ -148,11 +148,7 @@
}
if (!hasContentTypeXml)
{
- throw (new InvalidDataException("The file is not an valid Package file. If the file is encrypted, please supply the password in the constructor."));
- }
- if (!hasContentTypeXml)
- {
- throw (new InvalidDataException("The file is not an valid Package file. If the file is encrypted, please supply the password in the constructor."));
+ throw new InvalidDataException("The file is not an valid Package file.");
}
}
}
@@ -252,7 +248,7 @@
}
internal void Save(Stream stream)
{
- using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create);
+ using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true);
/**** ContentType****/
var contentTypesEntry = zipArchive.CreateEntry("[Content_Types].xml");
using (var contentTypesWriter = new StreamWriter(contentTypesEntry.Open()))
@@ -298,14 +294,6 @@
xml.Append("</Types>");
return xml.ToString();
}
- internal void Flush()
- {
-
- }
- internal void Close()
- {
-
- }
CompressionLevel _compression = CompressionLevel.Default;
public CompressionLevel Compression
{
diff --git a/EPPlus/Utils/CompoundDocument.cs b/EPPlus/Utils/CompoundDocument.cs
deleted file mode 100644
index 33c4ce2..0000000
--- a/EPPlus/Utils/CompoundDocument.cs
+++ /dev/null
@@ -1,755 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011 Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- *
- * Code change notes:
- *
- * Author Change Date
- *******************************************************************************
- * Jan Källman Added 01-01-2012
- * Jan Källman Added compression support 27-03-2012
- *******************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Runtime.InteropServices;
-using comTypes = System.Runtime.InteropServices.ComTypes;
-using System.IO;
-using System.Security;
-
-namespace OfficeOpenXml.Utils
-{
-#if !MONO
- internal class CompoundDocument
- {
- internal class StoragePart
- {
- public StoragePart()
- {
-
- }
- internal Dictionary<string, StoragePart> SubStorage = new Dictionary<string, StoragePart>();
- internal Dictionary<string, byte[]> DataStreams = new Dictionary<string, byte[]>();
- }
- internal StoragePart Storage = null;
- internal CompoundDocument()
- {
- Storage = new CompoundDocument.StoragePart();
- }
- internal CompoundDocument(FileInfo fi)
- {
- Read(fi);
- }
- internal CompoundDocument(ILockBytes lb)
- {
- Read(lb);
- }
- internal CompoundDocument(byte[] doc)
- {
- Read(doc);
- }
- internal void Read(FileInfo fi)
- {
- var b = File.ReadAllBytes(fi.FullName);
- Read(b);
- }
- [SecuritySafeCritical]
- internal void Read(byte[] doc)
- {
- ILockBytes lb;
- var iret = CreateILockBytesOnHGlobal(IntPtr.Zero, true, out lb);
-
- IntPtr buffer = Marshal.AllocHGlobal(doc.Length);
- Marshal.Copy(doc, 0, buffer, doc.Length);
- UIntPtr readSize;
- lb.WriteAt(0, buffer, doc.Length, out readSize);
- Marshal.FreeHGlobal(buffer);
-
- Read(lb);
- }
-
- [SecuritySafeCritical]
- internal void Read(ILockBytes lb)
- {
- if (StgIsStorageILockBytes(lb) == 0)
- {
- IStorage storage = null;
- if (StgOpenStorageOnILockBytes(
- lb,
- null,
- STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE,
- IntPtr.Zero,
- 0,
- out storage) == 0)
- {
- Storage = new StoragePart();
- ReadParts(storage, Storage);
- Marshal.ReleaseComObject(storage);
- }
- }
- else
- {
- throw (new InvalidDataException(string.Format("Part is not a compound document")));
- }
- }
- #region Compression
- /// <summary>
- /// Compression using a run length encoding algorithm.
- /// See MS-OVBA Section 2.4
- /// </summary>
- /// <param name="part">Byte array to decompress</param>
- /// <returns></returns>
- internal static byte[] CompressPart(byte[] part)
- {
- MemoryStream ms = new MemoryStream(4096);
- BinaryWriter br = new BinaryWriter(ms);
- br.Write((byte)1);
-
- int compStart = 1;
- int compEnd = 4098;
- int decompStart = 0;
- int decompEnd = part.Length < 4096 ? part.Length : 4096;
-
- while (decompStart < decompEnd && compStart < compEnd)
- {
- byte[] chunk = CompressChunk(part, ref decompStart);
- ushort header;
- if (chunk == null || chunk.Length == 0)
- {
- header = 4096 | 0x600; //B=011 A=0
- }
- else
- {
- header = (ushort)(((chunk.Length - 1) & 0xFFF));
- header |= 0xB000; //B=011 A=1
- br.Write(header);
- br.Write(chunk);
- }
- decompEnd = part.Length < decompStart + 4096 ? part.Length : decompStart+4096;
- }
-
-
- br.Flush();
- return ms.ToArray();
- }
- private static byte[] CompressChunk(byte[] buffer, ref int startPos)
- {
- var comprBuffer=new byte[4096];
- int flagPos = 0;
- int cPos=1;
- int dPos = startPos;
- int dEnd=startPos+4096 < buffer.Length? startPos+4096 : buffer.Length;
- while(dPos<dEnd)
- {
- byte tokenFlags = 0;
- for (int i = 0; i < 8; i++)
- {
- if (dPos - startPos > 0)
- {
- int bestCandidate = -1;
- int bestLength = 0;
- int candidate = dPos - 1;
- int bitCount = GetLengthBits(dPos-startPos);
- int bits = (16 - bitCount);
- ushort lengthMask = (ushort)((0xFFFF) >> bits);
-
- while (candidate >= startPos)
- {
- if (buffer[candidate] == buffer[dPos])
- {
- int length = 1;
-
- while (buffer.Length > dPos + length && buffer[candidate + length] == buffer[dPos + length] && length < lengthMask && dPos+length < dEnd)
- {
- length++;
- }
- if (length > bestLength)
- {
- bestCandidate = candidate;
- bestLength = length;
- if (bestLength == lengthMask)
- {
- break;
- }
- }
- }
- candidate--;
- }
- if (bestLength >= 3) //Copy token
- {
- tokenFlags |= (byte)(1 << i);
-
- UInt16 offsetMask = (ushort)~lengthMask;
- ushort token = (ushort)(((ushort)(dPos - (bestCandidate+1))) << (bitCount) | (ushort)(bestLength - 3));
- Array.Copy(BitConverter.GetBytes(token), 0, comprBuffer, cPos, 2);
- dPos = dPos + bestLength;
- cPos += 2;
- //SetCopy Token
- }
- else
- {
- comprBuffer[cPos++] = buffer[dPos++];
- }
- }
-
- else
- {
- comprBuffer[cPos++] = buffer[dPos++];
- }
- if (dPos >= dEnd) break;
- }
- comprBuffer[flagPos] = tokenFlags;
- flagPos = cPos++;
- }
- var ret = new byte[cPos - 1];
- Array.Copy(comprBuffer, ret, ret.Length);
- startPos = dEnd;
- return ret;
- }
- internal static byte[] DecompressPart(byte[] part)
- {
- return DecompressPart(part, 0);
- }
- /// <summary>
- /// Decompression using a run length encoding algorithm.
- /// See MS-OVBA Section 2.4
- /// </summary>
- /// <param name="part">Byte array to decompress</param>
- /// <param name="startPos"></param>
- /// <returns></returns>
- internal static byte[] DecompressPart(byte[] part, int startPos)
- {
-
- if (part[startPos] != 1)
- {
- return null;
- }
- MemoryStream ms = new MemoryStream(4096);
- int compressPos = startPos + 1;
- while(compressPos < part.Length-1)
- {
- DecompressChunk(ms, part, ref compressPos);
- }
- return ms.ToArray();
- }
- private static void DecompressChunk(MemoryStream ms, byte[] compBuffer, ref int pos)
- {
- ushort header = BitConverter.ToUInt16(compBuffer, pos);
- int decomprPos=0;
- byte[] buffer = new byte[4198]; //Add an extra 100 byte. Some workbooks have overflowing worksheets.
- int size = (int)(header & 0xFFF)+3;
- int endPos = pos+size;
- int a = (int)(header & 0x7000) >> 12;
- int b = (int)(header & 0x8000) >> 15;
- pos += 2;
- if (b == 1) //Compressed chunk
- {
- while (pos < compBuffer.Length && pos < endPos)
- {
- //Decompress token
- byte token = compBuffer[pos++];
- if (pos >= endPos)
- break;
- for (int i = 0; i < 8; i++)
- {
- //Literal token
- if ((token & (1 << i)) == 0)
- {
- ms.WriteByte(compBuffer[pos]);
- buffer[decomprPos++] = compBuffer[pos++];
- }
- else //copy token
- {
- var t = BitConverter.ToUInt16(compBuffer, pos);
- int bitCount = GetLengthBits(decomprPos);
- int bits = (16 - bitCount);
- ushort lengthMask = (ushort)((0xFFFF) >> bits);
- UInt16 offsetMask = (ushort)~lengthMask;
- var length = (lengthMask & t) + 3;
- var offset = (offsetMask & t) >> (bitCount);
- int source = decomprPos - offset - 1;
- if (decomprPos + length >= buffer.Length)
- {
- // Be lenient on decompression, so extend our decompression
- // buffer. Excel generated VBA projects do encounter this issue.
- // One would think (not surprisingly that the VBA project spec)
- // over emphasizes the size restrictions of a DecompressionChunk.
- var largerBuffer = new byte[buffer.Length + 4098];
- Array.Copy(buffer, largerBuffer, decomprPos);
- buffer = largerBuffer;
- }
-
- // Even though we've written to the MemoryStream,
- // We still should decompress the token into this buffer
- // in case a later token needs to use the bytes we're
- // about to decompress.
- for (int c = 0; c < length; c++)
- {
- ms.WriteByte(buffer[source]); //Must copy byte-wise because copytokens can overlap compressed buffer.
- buffer[decomprPos++] = buffer[source++];
- }
-
- pos += 2;
-
- }
- if (pos >= endPos)
- break;
- }
- }
- return;
- }
- else //Raw chunk
- {
- ms.Write(compBuffer, pos, size);
- pos += size;
- return;
- }
- }
- private static int GetLengthBits(int decompPos)
- {
- if (decompPos <= 16)
- {
- return 12;
- }
- else if (decompPos <= 32)
- {
- return 11;
- }
- else if (decompPos <= 64)
- {
- return 10;
- }
- else if (decompPos <= 128)
- {
- return 9;
- }
- else if (decompPos <= 256)
- {
- return 8;
- }
- else if (decompPos <= 512)
- {
- return 7;
- }
- else if (decompPos <= 1024)
- {
- return 6;
- }
- else if (decompPos <= 2048)
- {
- return 5;
- }
- else if (decompPos <= 4096)
- {
- return 4;
- }
- else
- {
- //We should never end up here, but if so this is the formula to calculate the bits...
- return 12 - (int)Math.Truncate(Math.Log(decompPos - 1 >> 4, 2) + 1);
- }
- }
- #endregion
- #region "API declare"
- [ComImport]
- [Guid("0000000d-0000-0000-C000-000000000046")]
- [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal interface IEnumSTATSTG
- {
- // The user needs to allocate an STATSTG array whose size is celt.
- [PreserveSig]
- uint Next(
- uint celt,
- [MarshalAs(UnmanagedType.LPArray), Out]
- System.Runtime.InteropServices.ComTypes.STATSTG[] rgelt,
- out uint pceltFetched
- );
-
- void Skip(uint celt);
-
- void Reset();
-
- [return: MarshalAs(UnmanagedType.Interface)]
- IEnumSTATSTG Clone();
- }
-
- [ComImport]
- [Guid("0000000b-0000-0000-C000-000000000046")]
- [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- interface IStorage
- {
- void CreateStream(
- /* [string][in] */ string pwcsName,
- /* [in] */ uint grfMode,
- /* [in] */ uint reserved1,
- /* [in] */ uint reserved2,
- /* [out] */ out comTypes.IStream ppstm);
-
- void OpenStream(
- /* [string][in] */ string pwcsName,
- /* [unique][in] */ IntPtr reserved1,
- /* [in] */ uint grfMode,
- /* [in] */ uint reserved2,
- /* [out] */ out comTypes.IStream ppstm);
-
- void CreateStorage(
- /* [string][in] */ string pwcsName,
- /* [in] */ uint grfMode,
- /* [in] */ uint reserved1,
- /* [in] */ uint reserved2,
- /* [out] */ out IStorage ppstg);
-
- void OpenStorage(
- /* [string][unique][in] */ string pwcsName,
- /* [unique][in] */ IStorage pstgPriority,
- /* [in] */ STGM grfMode,
- /* [unique][in] */ IntPtr snbExclude,
- /* [in] */ uint reserved,
- /* [out] */ out IStorage ppstg);
-
- void CopyTo(
- [InAttribute] uint ciidExclude,
- [InAttribute] Guid[] rgiidExclude,
- [InAttribute] IntPtr snbExclude,
- [InAttribute] IStorage pstgDest
- );
-
- void MoveElementTo(
- /* [string][in] */ string pwcsName,
- /* [unique][in] */ IStorage pstgDest,
- /* [string][in] */ string pwcsNewName,
- /* [in] */ uint grfFlags);
-
- void Commit(
- /* [in] */ uint grfCommitFlags);
-
- void Revert();
-
- void EnumElements(
- /* [in] */ uint reserved1,
- /* [size_is][unique][in] */ IntPtr reserved2,
- /* [in] */ uint reserved3,
- /* [out] */ out IEnumSTATSTG ppenum);
-
- void DestroyElement(
- /* [string][in] */ string pwcsName);
-
- void RenameElement(
- /* [string][in] */ string pwcsOldName,
- /* [string][in] */ string pwcsNewName);
-
- void SetElementTimes(
- /* [string][unique][in] */ string pwcsName,
- /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME pctime,
- /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME patime,
- /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME pmtime);
-
- void SetClass(
- /* [in] */ Guid clsid);
-
- void SetStateBits(
- /* [in] */ uint grfStateBits,
- /* [in] */ uint grfMask);
-
- void Stat(
- /* [out] */ out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg,
- /* [in] */ uint grfStatFlag);
-
- }
- [ComVisible(false)]
- [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000A-0000-0000-C000-000000000046")]
- internal interface ILockBytes
- {
- void ReadAt(long ulOffset, System.IntPtr pv, int cb, out UIntPtr pcbRead);
- void WriteAt(long ulOffset, System.IntPtr pv, int cb, out UIntPtr pcbWritten);
- void Flush();
- void SetSize(long cb);
- void LockRegion(long libOffset, long cb, int dwLockType);
- void UnlockRegion(long libOffset, long cb, int dwLockType);
- void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag);
- }
- [Flags]
- internal enum STGM : int
- {
- DIRECT = 0x00000000,
- TRANSACTED = 0x00010000,
- SIMPLE = 0x08000000,
- READ = 0x00000000,
- WRITE = 0x00000001,
- READWRITE = 0x00000002,
- SHARE_DENY_NONE = 0x00000040,
- SHARE_DENY_READ = 0x00000030,
- SHARE_DENY_WRITE = 0x00000020,
- SHARE_EXCLUSIVE = 0x00000010,
- PRIORITY = 0x00040000,
- DELETEONRELEASE = 0x04000000,
- NOSCRATCH = 0x00100000,
- CREATE = 0x00001000,
- CONVERT = 0x00020000,
- FAILIFTHERE = 0x00000000,
- NOSNAPSHOT = 0x00200000,
- DIRECT_SWMR = 0x00400000,
- }
-
- internal enum STATFLAG : uint
- {
- STATFLAG_DEFAULT = 0,
- STATFLAG_NONAME = 1,
- STATFLAG_NOOPEN = 2
- }
-
- internal enum STGTY : int
- {
- STGTY_STORAGE = 1,
- STGTY_STREAM = 2,
- STGTY_LOCKBYTES = 3,
- STGTY_PROPERTY = 4
- }
-
- [DllImport("ole32.dll")]
- private static extern int StgIsStorageFile(
- [MarshalAs(UnmanagedType.LPWStr)] string pwcsName);
- [DllImport("ole32.dll")]
- private static extern int StgIsStorageILockBytes(
- ILockBytes plkbyt);
-
-
- [DllImport("ole32.dll")]
- static extern int StgOpenStorage(
- [MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
- IStorage pstgPriority,
- STGM grfMode,
- IntPtr snbExclude,
- uint reserved,
- out IStorage ppstgOpen);
-
- [DllImport("ole32.dll")]
- static extern int StgOpenStorageOnILockBytes(
- ILockBytes plkbyt,
- IStorage pStgPriority,
- STGM grfMode,
- IntPtr snbEnclude,
- uint reserved,
- out IStorage ppstgOpen);
- [DllImport("ole32.dll")]
- static extern int CreateILockBytesOnHGlobal(
- IntPtr hGlobal,
- bool fDeleteOnRelease,
- out ILockBytes ppLkbyt);
-
- [DllImport("ole32.dll")]
- static extern int StgCreateDocfileOnILockBytes(ILockBytes plkbyt, STGM grfMode, int reserved, out IStorage ppstgOpen);
-
- #endregion
- [SecuritySafeCritical]
- internal static int IsStorageFile(string Name)
- {
- return StgIsStorageFile(Name);
- }
- [SecuritySafeCritical]
- internal static int IsStorageILockBytes(ILockBytes lb)
- {
- return StgIsStorageILockBytes(lb);
- }
- [SecuritySafeCritical]
- internal static ILockBytes GetLockbyte(MemoryStream stream)
- {
- ILockBytes lb;
- var iret = CreateILockBytesOnHGlobal(IntPtr.Zero, true, out lb);
- byte[] docArray = stream.GetBuffer();
-
- IntPtr buffer = Marshal.AllocHGlobal(docArray.Length);
- Marshal.Copy(docArray, 0, buffer, docArray.Length);
- UIntPtr readSize;
- lb.WriteAt(0, buffer, docArray.Length, out readSize);
- Marshal.FreeHGlobal(buffer);
-
- return lb;
- }
- [SecuritySafeCritical]
- private MemoryStream ReadParts(IStorage storage, StoragePart storagePart)
- {
- MemoryStream ret = null;
- comTypes.STATSTG statstg;
-
- storage.Stat(out statstg, (uint)STATFLAG.STATFLAG_DEFAULT);
-
- IEnumSTATSTG pIEnumStatStg = null;
- storage.EnumElements(0, IntPtr.Zero, 0, out pIEnumStatStg);
-
- comTypes.STATSTG[] regelt = { statstg };
- uint fetched = 0;
- uint res = pIEnumStatStg.Next(1, regelt, out fetched);
-
- //if (regelt[0].pwcsName == "DataSpaces")
- //{
- // PrintStorage(storage, regelt[0],"");
- //}
- while (res != 1)
- {
- foreach (var item in regelt)
- {
- if (item.type == 1)
- {
- IStorage subStorage;
- storage.OpenStorage(item.pwcsName, null, STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE, IntPtr.Zero, 0, out subStorage);
- StoragePart subStoragePart=new StoragePart();
- storagePart.SubStorage.Add(item.pwcsName, subStoragePart);
- ReadParts(subStorage, subStoragePart);
- }
- else
- {
- storagePart.DataStreams.Add(item.pwcsName, GetOleStream(storage, item));
- }
- }
- res = pIEnumStatStg.Next(1, regelt, out fetched);
- }
- Marshal.ReleaseComObject(pIEnumStatStg);
- return ret;
- }
- // Help method to print a storage part binary to c:\temp
- //private void PrintStorage(IStorage storage, System.Runtime.InteropServices.ComTypes.STATSTG sTATSTG, string topName)
- //{
- // IStorage ds;
- // if (topName.Length > 0)
- // {
- // topName = topName[0] < 'A' ? topName.Substring(1, topName.Length - 1) : topName;
- // }
- // storage.OpenStorage(sTATSTG.pwcsName,
- // null,
- // (uint)(STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE),
- // IntPtr.Zero,
- // 0,
- // out ds);
-
- // System.Runtime.InteropServices.ComTypes.STATSTG statstgSub;
- // ds.Stat(out statstgSub, (uint)STATFLAG.STATFLAG_DEFAULT);
-
- // IEnumSTATSTG pIEnumStatStgSub = null;
- // System.Runtime.InteropServices.ComTypes.STATSTG[] regeltSub = { statstgSub };
- // ds.EnumElements(0, IntPtr.Zero, 0, out pIEnumStatStgSub);
-
- // uint fetched = 0;
- // while (pIEnumStatStgSub.Next(1, regeltSub, out fetched) == 0)
- // {
- // string sName = regeltSub[0].pwcsName[0] < 'A' ? regeltSub[0].pwcsName.Substring(1, regeltSub[0].pwcsName.Length - 1) : regeltSub[0].pwcsName;
- // if (regeltSub[0].type == 1)
- // {
- // PrintStorage(ds, regeltSub[0], topName + sName + "_");
- // }
- // else if(regeltSub[0].type==2)
- // {
- // File.WriteAllBytes(@"c:\temp\" + topName + sName + ".bin", GetOleStream(ds, regeltSub[0]));
- // }
- // }
- //} }
- /// <summary>
- /// Read the stream and return it as a byte-array
- /// </summary>
- /// <param name="storage"></param>
- /// <param name="statstg"></param>
- /// <returns></returns>
- [SecuritySafeCritical]
- private byte[] GetOleStream(IStorage storage, comTypes.STATSTG statstg)
- {
- comTypes.IStream pIStream;
- storage.OpenStream(statstg.pwcsName,
- IntPtr.Zero,
- (uint)(STGM.READ | STGM.SHARE_EXCLUSIVE),
- 0,
- out pIStream);
-
- byte[] data = new byte[statstg.cbSize];
- pIStream.Read(data, (int)statstg.cbSize, IntPtr.Zero);
- Marshal.ReleaseComObject(pIStream);
-
- return data;
- }
-
- [SecuritySafeCritical]
- internal byte[] Save()
- {
- ILockBytes lb;
- var iret = CreateILockBytesOnHGlobal(IntPtr.Zero, true, out lb);
-
- IStorage storage = null;
- byte[] ret = null;
-
- //Create the document in-memory
- if (StgCreateDocfileOnILockBytes(lb,
- STGM.CREATE | STGM.READWRITE | STGM.SHARE_EXCLUSIVE | STGM.TRANSACTED,
- 0,
- out storage)==0)
- {
- foreach(var store in this.Storage.SubStorage)
- {
- CreateStore(store.Key, store.Value, storage);
- }
- CreateStreams(this.Storage, storage);
- lb.Flush();
-
- //Now copy the unmanaged stream to a byte array --> memory stream
- var statstg = new comTypes.STATSTG();
- lb.Stat(out statstg, 0);
- int size = (int)statstg.cbSize;
- IntPtr buffer = Marshal.AllocHGlobal(size);
- UIntPtr readSize;
- ret=new byte[size];
- lb.ReadAt(0, buffer, size, out readSize);
- Marshal.Copy(buffer, ret, 0, size);
- Marshal.FreeHGlobal(buffer);
- }
- Marshal.ReleaseComObject(storage);
- Marshal.ReleaseComObject(lb);
-
- return ret;
- }
-
- private void CreateStore(string name, StoragePart subStore, IStorage storage)
- {
- IStorage subStorage;
- storage.CreateStorage(name, (uint)(STGM.CREATE | STGM.WRITE | STGM.DIRECT | STGM.SHARE_EXCLUSIVE), 0, 0, out subStorage);
- storage.Commit(0);
- foreach (var store in subStore.SubStorage)
- {
- CreateStore(store.Key, store.Value, subStorage);
- }
-
- CreateStreams(subStore, subStorage);
- }
-
- private void CreateStreams(StoragePart subStore, IStorage subStorage)
- {
- foreach (var ds in subStore.DataStreams)
- {
- comTypes.IStream stream;
- subStorage.CreateStream(ds.Key, (uint)(STGM.CREATE | STGM.WRITE | STGM.DIRECT | STGM.SHARE_EXCLUSIVE), 0, 0, out stream);
- stream.Write(ds.Value, ds.Value.Length, IntPtr.Zero);
- }
- subStorage.Commit(0);
- }
-
- }
-#endif
-}
\ No newline at end of file
diff --git a/EPPlus/Utils/EncryptedPackageHandler.cs b/EPPlus/Utils/EncryptedPackageHandler.cs
deleted file mode 100644
index 00b4c0e..0000000
--- a/EPPlus/Utils/EncryptedPackageHandler.cs
+++ /dev/null
@@ -1,200 +0,0 @@
-/*******************************************************************************
- * You may amend and distribute as you like, but don't remove this header!
- *
- * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
- * See http://www.codeplex.com/EPPlus for details.
- *
- * Copyright (C) 2011 Jan Källman
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
-
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Lesser General Public License for more details.
- *
- * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
- * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
- *
- * All code and executables are provided "as is" with no warranty either express or implied.
- * The author accepts no liability for any damage or loss of business that this product may cause.
- **************************************************************************************
- * This class is created with the help of the MS-OFFCRYPTO PDF documentation... http://msdn.microsoft.com/en-us/library/cc313071(office.12).aspx
- * Decryption library for Office Open XML files(Lyquidity) and Sminks very nice example
- * on "Reading compound documents in c#" on Stackoverflow. Many thanks!
- ***************************************************************************************
- * Code change notes:
- *
- * Author Change Date
- *******************************************************************************
- * Jan Källman Added 10-AUG-2010
- * Jan Källman License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Runtime.InteropServices;
-using comTypes=System.Runtime.InteropServices.ComTypes;
-using System.IO;
-using System.Security.Cryptography;
-using System.Xml;
-namespace OfficeOpenXml.Utils
-{
- [ComImport]
- [Guid("0000000d-0000-0000-C000-000000000046")]
- [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- internal interface IEnumSTATSTG
- {
- // The user needs to allocate an STATSTG array whose size is celt.
- [PreserveSig]
- uint Next(
- uint celt,
- [MarshalAs(UnmanagedType.LPArray), Out]
- System.Runtime.InteropServices.ComTypes.STATSTG[] rgelt,
- out uint pceltFetched
- );
-
- void Skip(uint celt);
-
- void Reset();
-
- [return: MarshalAs(UnmanagedType.Interface)]
- IEnumSTATSTG Clone();
- }
-
- [ComImport]
- [Guid("0000000b-0000-0000-C000-000000000046")]
- [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- interface IStorage
- {
- void CreateStream(
- /* [string][in] */ string pwcsName,
- /* [in] */ uint grfMode,
- /* [in] */ uint reserved1,
- /* [in] */ uint reserved2,
- /* [out] */ out comTypes.IStream ppstm);
-
- void OpenStream(
- /* [string][in] */ string pwcsName,
- /* [unique][in] */ IntPtr reserved1,
- /* [in] */ uint grfMode,
- /* [in] */ uint reserved2,
- /* [out] */ out comTypes.IStream ppstm);
-
- void CreateStorage(
- /* [string][in] */ string pwcsName,
- /* [in] */ uint grfMode,
- /* [in] */ uint reserved1,
- /* [in] */ uint reserved2,
- /* [out] */ out IStorage ppstg);
-
- void OpenStorage(
- /* [string][unique][in] */ string pwcsName,
- /* [unique][in] */ IStorage pstgPriority,
- /* [in] */ uint grfMode,
- /* [unique][in] */ IntPtr snbExclude,
- /* [in] */ uint reserved,
- /* [out] */ out IStorage ppstg);
-
- void CopyTo(
- [InAttribute] uint ciidExclude,
- [InAttribute] Guid[] rgiidExclude,
- [InAttribute] IntPtr snbExclude,
- [InAttribute] IStorage pstgDest
- );
-
- void MoveElementTo(
- /* [string][in] */ string pwcsName,
- /* [unique][in] */ IStorage pstgDest,
- /* [string][in] */ string pwcsNewName,
- /* [in] */ uint grfFlags);
-
- void Commit(
- /* [in] */ uint grfCommitFlags);
-
- void Revert();
-
- void EnumElements(
- /* [in] */ uint reserved1,
- /* [size_is][unique][in] */ IntPtr reserved2,
- /* [in] */ uint reserved3,
- /* [out] */ out IEnumSTATSTG ppenum);
-
- void DestroyElement(
- /* [string][in] */ string pwcsName);
-
- void RenameElement(
- /* [string][in] */ string pwcsOldName,
- /* [string][in] */ string pwcsNewName);
-
- void SetElementTimes(
- /* [string][unique][in] */ string pwcsName,
- /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME pctime,
- /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME patime,
- /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME pmtime);
-
- void SetClass(
- /* [in] */ Guid clsid);
-
- void SetStateBits(
- /* [in] */ uint grfStateBits,
- /* [in] */ uint grfMask);
-
- void Stat(
- /* [out] */ out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg,
- /* [in] */ uint grfStatFlag);
-
- }
- [ComVisible(false)]
- [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000A-0000-0000-C000-000000000046")]
- internal interface ILockBytes
- {
- void ReadAt(long ulOffset, System.IntPtr pv, int cb, out UIntPtr pcbRead);
- void WriteAt(long ulOffset, System.IntPtr pv, int cb, out UIntPtr pcbWritten);
- void Flush();
- void SetSize(long cb);
- void LockRegion(long libOffset, long cb, int dwLockType);
- void UnlockRegion(long libOffset, long cb, int dwLockType);
- void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag);
- }
- [Flags]
- internal enum STGM : int
- {
- DIRECT = 0x00000000,
- TRANSACTED = 0x00010000,
- SIMPLE = 0x08000000,
- READ = 0x00000000,
- WRITE = 0x00000001,
- READWRITE = 0x00000002,
- SHARE_DENY_NONE = 0x00000040,
- SHARE_DENY_READ = 0x00000030,
- SHARE_DENY_WRITE = 0x00000020,
- SHARE_EXCLUSIVE = 0x00000010,
- PRIORITY = 0x00040000,
- DELETEONRELEASE = 0x04000000,
- NOSCRATCH = 0x00100000,
- CREATE = 0x00001000,
- CONVERT = 0x00020000,
- FAILIFTHERE = 0x00000000,
- NOSNAPSHOT = 0x00200000,
- DIRECT_SWMR = 0x00400000,
- }
-
- internal enum STATFLAG : uint
- {
- STATFLAG_DEFAULT = 0,
- STATFLAG_NONAME = 1,
- STATFLAG_NOOPEN = 2
- }
-
- internal enum STGTY : int
- {
- STGTY_STORAGE = 1,
- STGTY_STREAM = 2,
- STGTY_LOCKBYTES = 3,
- STGTY_PROPERTY = 4
- }
-}
diff --git a/NetCoreTests/ExcelPackageTest.cs b/NetCoreTests/ExcelPackageTest.cs
new file mode 100644
index 0000000..e59278f
--- /dev/null
+++ b/NetCoreTests/ExcelPackageTest.cs
@@ -0,0 +1,30 @@
+using System.IO;
+using System.Linq;
+using FluentAssertions;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using OfficeOpenXml;
+
+namespace NetCoreTests;
+
+[TestClass]
+public class ExcelPackageTest
+{
+ [TestMethod]
+ public void TestGetAsByteArray()
+ {
+ var package = new ExcelPackage(new FileInfo(GetTestWorkbookPath("Times.xlsx")));
+ var data = package.GetAsByteArray();
+
+ // Verify that we can reload
+ var newPackage = new ExcelPackage(new MemoryStream(data, false));
+ newPackage.Workbook.Worksheets.Count.Should().Be(1);
+ var worksheet = newPackage.Workbook.Worksheets.First();
+ worksheet.Name.Should().Be("Times_csv");
+ }
+
+ private static string GetTestWorkbookPath(string filename)
+ {
+ var assemblyPath = Path.GetDirectoryName(typeof(ExcelPackageTest).Assembly.Location)!;
+ return Path.Combine(assemblyPath, "TestWorkbooks", filename);
+ }
+}
\ No newline at end of file
diff --git a/NetCoreTests/TimeTest.cs b/NetCoreTests/TimeTest.cs
index 39cc038..b207ff0 100644
--- a/NetCoreTests/TimeTest.cs
+++ b/NetCoreTests/TimeTest.cs
@@ -37,7 +37,7 @@
[TestMethod]
public void TestDateParse()
{
- using var package = new ExcelPackage(new FileInfo(GetTestWorkbookPath("Times.xlsx")));
+ var package = new ExcelPackage(new FileInfo(GetTestWorkbookPath("Times.xlsx")));
var sheet = package.Workbook.Worksheets.First();
sheet.Cells["B3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 30));