Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PausableBasicAlgorithm/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/HeuristicLab.EPPlus-4.0.3/epplus-4.0.3-Mono.patch @ 13371

Last change on this file since 13371 was 12715, checked in by mkommend, 9 years ago

#2341: Reverse merged r12714 because one file change relates to another ticket (#2399).

File size: 92.1 KB
  • ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs

     
    1 ï»¿/*******************************************************************************
    2  * You may amend and distribute as you like, but don't remove this header!
    3  *
    4  * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
    5  * See http://www.codeplex.com/EPPlus for details.
    6  *
    7  * Copyright (C) 2011  Jan KÀllman
    8  *
    9  * This library is free software; you can redistribute it and/or
    10  * modify it under the terms of the GNU Lesser General Public
    11  * License as published by the Free Software Foundation; either
    12  * version 2.1 of the License, or (at your option) any later version.
    13 
    14  * This library is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
    17  * See the GNU Lesser General Public License for more details.
    18  *
    19  * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
    20  * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
    21  *
    22  * All code and executables are provided "as is" with no warranty either express or implied.
    23  * The author accepts no liability for any damage or loss of business that this product may cause.
    24  *
    25  * Code change notes:
    26  *
    27  * Author             Change            Date
    28  * ******************************************************************************
    29  * Eyal Seagull        Added            2012-04-03
    30  *******************************************************************************/
    31 using System;
    32 using System.Collections.Generic;
    33 using System.Linq;
    34 using System.Text;
    35 using System.Drawing;
    36 using System.Xml;
    37 using OfficeOpenXml.Utils;
    38 using System.Text.RegularExpressions;
    39 using System.Globalization;
    40 using System.Security;
    41 
    42 namespace OfficeOpenXml.ConditionalFormatting
    43 {
    44   /// <summary>
    45   /// 18.3.1.11 cfvo (Conditional Format Value Object)
    46   /// Describes the values of the interpolation points in a gradient scale.
    47   /// </summary>
    48   public class ExcelConditionalFormattingIconDataBarValue
    49     : XmlHelper
    50   {
    51     /****************************************************************************************/
    52 
    53     #region Private Properties
    54     private eExcelConditionalFormattingRuleType _ruleType;
    55     private ExcelWorksheet _worksheet;
    56     #endregion Private Properties
    57 
    58     /****************************************************************************************/
    59 
    60     #region Constructors
    61     /// <summary>
    62     /// Initialize the cfvo (§18.3.1.11) node
    63     /// </summary>
    64     /// <param name="type"></param>
    65     /// <param name="value"></param>
    66     /// <param name="formula"></param>
    67     /// <param name="ruleType"></param>
    68     /// <param name="address"></param>
    69     /// <param name="priority"></param>
    70     /// <param name="worksheet"></param>
    71     /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following:
    72     /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param>
    73     /// <param name="namespaceManager"></param>
    74     internal ExcelConditionalFormattingIconDataBarValue(
    75       eExcelConditionalFormattingValueObjectType type,
    76       double value,
    77       string formula,
    78       eExcelConditionalFormattingRuleType ruleType,
    79             ExcelAddress address,
    80             int priority,
    81       ExcelWorksheet worksheet,
    82       XmlNode itemElementNode,
    83       XmlNamespaceManager namespaceManager)
    84       : this(
    85             ruleType,
    86             address,
    87             worksheet,
    88             itemElementNode,
    89       namespaceManager)
    90     {
    91       Require.Argument(priority).IsInRange(1, int.MaxValue, "priority");
    92 
    93             // Check if the parent does not exists
    94       if (itemElementNode == null)
    95       {
    96         // Get the parent node path by the rule type
    97         string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType(
    98           ruleType);
    99 
    100         // Check for en error (rule type does not have <cfvo>)
    101         if (parentNodePath == string.Empty)
    102         {
    103           throw new Exception(
    104             ExcelConditionalFormattingConstants.Errors.MissingCfvoParentNode);
    105         }
    106 
    107         // Point to the <cfvo> parent node
    108         itemElementNode = _worksheet.WorksheetXml.SelectSingleNode(
    109           string.Format(
    110             "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}",
    111           // {0}
    112             ExcelConditionalFormattingConstants.Paths.ConditionalFormatting,
    113           // {1}
    114             ExcelConditionalFormattingConstants.Paths.SqrefAttribute,
    115           // {2}
    116             address.Address,
    117           // {3}
    118             ExcelConditionalFormattingConstants.Paths.CfRule,
    119           // {4}
    120             ExcelConditionalFormattingConstants.Paths.PriorityAttribute,
    121           // {5}
    122             priority,
    123           // {6}
    124             parentNodePath),
    125           _worksheet.NameSpaceManager);
    126 
    127         // Check for en error (rule type does not have <cfvo>)
    128                 if (itemElementNode == null)
    129         {
    130           throw new Exception(
    131             ExcelConditionalFormattingConstants.Errors.MissingCfvoParentNode);
    132         }
    133       }
    134 
    135             TopNode = itemElementNode;
    136 
    137       // Save the attributes
    138       RuleType = ruleType;
    139       Type = type;
    140       Value = value;
    141       Formula = formula;
    142     }
    143     /// <summary>
    144     /// Initialize the cfvo (§18.3.1.11) node
    145     /// </summary>
    146     /// <param name="ruleType"></param>
    147     /// <param name="address"></param>
    148     /// <param name="worksheet"></param>
    149     /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following:
    150     /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param>
    151     /// <param name="namespaceManager"></param>
    152         internal ExcelConditionalFormattingIconDataBarValue(
    153             eExcelConditionalFormattingRuleType ruleType,
    154             ExcelAddress address,
    155             ExcelWorksheet worksheet,
    156             XmlNode itemElementNode,
    157             XmlNamespaceManager namespaceManager)
    158             : base(
    159                 namespaceManager,
    160                 itemElementNode)
    161         {
    162             Require.Argument(address).IsNotNull("address");
    163             Require.Argument(worksheet).IsNotNull("worksheet");
    164 
    165             // Save the worksheet for private methods to use
    166             _worksheet = worksheet;
    167 
    168             // Schema order list
    169             SchemaNodeOrder = new string[]
    170       {
    171                 ExcelConditionalFormattingConstants.Nodes.Cfvo,
    172       };
    173 
    174             //Check if the parent does not exists
    175             if (itemElementNode == null)
    176             {
    177                 // Get the parent node path by the rule type
    178                 string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType(
    179                     ruleType);
    180 
    181                 // Check for en error (rule type does not have <cfvo>)
    182                 if (parentNodePath == string.Empty)
    183                 {
    184                     throw new Exception(
    185                         ExcelConditionalFormattingConstants.Errors.MissingCfvoParentNode);
    186                 }
    187             }
    188             RuleType = ruleType;           
    189         }
    190     /// <summary>
    191     /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
    192     /// </summary>
    193     /// <param name="type"></param>
    194     /// <param name="value"></param>
    195     /// <param name="formula"></param>
    196     /// <param name="ruleType"></param>
    197     /// <param name="priority"></param>
    198     /// <param name="address"></param>
    199     /// <param name="worksheet"></param>
    200     /// <param name="namespaceManager"></param>
    201     internal ExcelConditionalFormattingIconDataBarValue(
    202       eExcelConditionalFormattingValueObjectType type,
    203       double value,
    204       string formula,
    205       eExcelConditionalFormattingRuleType ruleType,
    206             ExcelAddress address,
    207             int priority,
    208       ExcelWorksheet worksheet,
    209       XmlNamespaceManager namespaceManager)
    210       : this(
    211         type,
    212         value,
    213         formula,
    214         ruleType,
    215                 address,
    216                 priority,
    217         worksheet,
    218         null,
    219         namespaceManager)
    220     {
    221            
    222     }
    223     /// <summary>
    224     /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/>
    225     /// </summary>
    226     /// <param name="type"></param>
    227     /// <param name="color"></param>
    228     /// <param name="ruleType"></param>
    229     /// <param name="priority"></param>
    230     /// <param name="address"></param>
    231     /// <param name="worksheet"></param>
    232     /// <param name="namespaceManager"></param>
    233     internal ExcelConditionalFormattingIconDataBarValue(
    234       eExcelConditionalFormattingValueObjectType type,
    235       Color color,
    236       eExcelConditionalFormattingRuleType ruleType,
    237             ExcelAddress address,
    238             int priority,
    239       ExcelWorksheet worksheet,
    240       XmlNamespaceManager namespaceManager)
    241       : this(
    242         type,
    243         0,
    244         null,
    245         ruleType,
    246                 address,
    247                 priority,
    248         worksheet,
    249         null,
    250         namespaceManager)
    251     {
    252     }
    253     #endregion Constructors
    254 
    255     /****************************************************************************************/
    256 
    257     #region Methods
    258         #endregion
    259 
    260         /****************************************************************************************/
    261 
    262     #region Exposed Properties
    263 
    264     /// <summary>
    265     ///
    266     /// </summary>
    267     internal eExcelConditionalFormattingRuleType RuleType
    268     {
    269       get { return _ruleType; }
    270       set { _ruleType = value; }
    271     }
    272 
    273     /// <summary>
    274     ///
    275     /// </summary>
    276     public eExcelConditionalFormattingValueObjectType Type
    277     {
    278       get
    279       {
    280         var typeAttribute = GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.TypeAttribute);
    281 
    282         return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute);
    283       }
    284       set
    285       {
    286                 if ((_ruleType==eExcelConditionalFormattingRuleType.ThreeIconSet || _ruleType==eExcelConditionalFormattingRuleType.FourIconSet || _ruleType==eExcelConditionalFormattingRuleType.FiveIconSet) &&
    287                     (value == eExcelConditionalFormattingValueObjectType.Min || value == eExcelConditionalFormattingValueObjectType.Max))
    288                 {
    289                     throw(new ArgumentException("Value type can't be Min or Max for icon sets"));
    290                 }
    291                 SetXmlNodeString(ExcelConditionalFormattingConstants.Paths.TypeAttribute, value.ToString().ToLower(CultureInfo.InvariantCulture));               
    292       }
    293     }
    294 
    295     /// <summary>
    296     /// Get/Set the 'cfvo' node @val attribute
    297     /// </summary>
    298     public Double Value
    299     {
    300       get
    301       {
    302                 if ((Type == eExcelConditionalFormattingValueObjectType.Num)
    303                     || (Type == eExcelConditionalFormattingValueObjectType.Percent)
    304                     || (Type == eExcelConditionalFormattingValueObjectType.Percentile))
    305                 {
    306                     return GetXmlNodeDouble(ExcelConditionalFormattingConstants.Paths.ValAttribute);
    307                 }
    308                 else
    309                 {
    310                     return 0;
    311                 }
    312             }
    313       set
    314       {
    315         string valueToStore = string.Empty;
    316 
    317         // Only some types use the @val attribute
    318         if ((Type == eExcelConditionalFormattingValueObjectType.Num)
    319           || (Type == eExcelConditionalFormattingValueObjectType.Percent)
    320           || (Type == eExcelConditionalFormattingValueObjectType.Percentile))
    321         {
    322           valueToStore = value.ToString(CultureInfo.InvariantCulture);
    323         }
    324 
    325                 SetXmlNodeString(ExcelConditionalFormattingConstants.Paths.ValAttribute, valueToStore);
    326       }
    327     }
    328 
    329     /// <summary>
    330     /// Get/Set the Formula of the Object Value (uses the same attribute as the Value)
    331     /// </summary>
    332     public string Formula
    333     {
    334       get
    335       {
    336         // Return empty if the Object Value type is not Formula
    337         if (Type != eExcelConditionalFormattingValueObjectType.Formula)
    338         {
    339           return string.Empty;
    340         }
    341 
    342         // Excel stores the formula in the @val attribute
    343         return GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.ValAttribute);
    344       }
    345       set
    346       {
    347         // Only store the formula if the Object Value type is Formula
    348         if (Type == eExcelConditionalFormattingValueObjectType.Formula)
    349         {
    350                     SetXmlNodeString(ExcelConditionalFormattingConstants.Paths.ValAttribute, value);
    351         }
    352       }
    353     }
    354     #endregion Exposed Properties
    355 
    356     /****************************************************************************************/
    357   }
    358 }
    359  No newline at end of file
  • ExcelWorkbook.cs

     
    336336                if (_standardFontWidth == decimal.MinValue || _fontID != Styles.Fonts[0].Id)
    337337        {
    338338          var font = Styles.Fonts[0];
     339#if __MonoCS__
     340    _standardFontWidth = (int)(font.Size * (2D / 3D)); //Aprox for Calibri.
     341#else
    339342                    try
    340343                    {
    341344                        //Font f = new Font(font.Name, font.Size);
     
    373376                    {
    374377                        _standardFontWidth = (int)(font.Size * (2D / 3D)); //Aprox for Calibri.
    375378                    }
     379#endif
    376380        }
    377381        return _standardFontWidth;
    378382      }
  • VBA/ExcelVBAModuleCollection.cs

     
    1 ï»¿/*******************************************************************************
    2  * You may amend and distribute as you like, but don't remove this header!
    3  *
    4  * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
    5  * See http://www.codeplex.com/EPPlus for details.
    6  *
    7  * Copyright (C) 2011  Jan KÀllman
    8  *
    9  * This library is free software; you can redistribute it and/or
    10  * modify it under the terms of the GNU Lesser General Public
    11  * License as published by the Free Software Foundation; either
    12  * version 2.1 of the License, or (at your option) any later version.
    13 
    14  * This library is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
    17  * See the GNU Lesser General Public License for more details.
    18  *
    19  * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
    20  * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
    21  *
    22  * All code and executables are provided "as is" with no warranty either express or implied.
    23  * The author accepts no liability for any damage or loss of business that this product may cause.
    24  *
    25  * Code change notes:
    26  *
    27  * Author             Change            Date
    28  *******************************************************************************
    29  * Jan KÀllman   Added   12-APR-2012
    30  *******************************************************************************/
    31 using System;
    32 using System.Collections.Generic;
    33 using System.Linq;
    34 using System.Text;
    35 
    36 namespace OfficeOpenXml.VBA
    37 {
    38     /// <summary>
    39     /// Base class for VBA collections
    40     /// </summary>
    41     /// <typeparam name="T"></typeparam>
    42     public class ExcelVBACollectionBase<T> : IEnumerable<T>
    43     {
    44         internal protected List<T> _list=new List<T>();       
    45         public IEnumerator<T> GetEnumerator()
    46         {
    47             return _list.GetEnumerator();
    48         }
    49 
    50         System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    51         {
    52             return _list.GetEnumerator();
    53         }
    54         /// <summary>
    55         /// Indexer
    56         /// </summary>
    57         /// <param name="Name">Name</param>
    58         /// <returns></returns>
    59         public T this [string Name]
    60         {
    61             get
    62             {
    63                 return _list.Find((f) => f.GetType().GetProperty("Name").GetValue(f, null).ToString().Equals(Name,StringComparison.InvariantCultureIgnoreCase));
    64             }
    65         }
    66         /// <summary>
    67         /// Indexer
    68         /// </summary>
    69         /// <param name="Index">Position</param>
    70         /// <returns></returns>
    71         public T this[int Index]
    72         {
    73             get
    74             {
    75                 return _list[Index];
    76             }
    77         }
    78         /// <summary>
    79         /// Number of items in the collection
    80         /// </summary>
    81         public int Count
    82         {
    83             get { return _list.Count; }
    84         }
    85         /// <summary>
    86         /// If a specific name exists in the collection
    87         /// </summary>
    88         /// <param name="Name">The name</param>
    89         /// <returns>True if the name exists</returns>
    90         public bool Exists(string Name)
    91         {
    92             return _list.Exists((f) => f.GetType().GetProperty("Name").GetValue(f, null).ToString().Equals(Name,StringComparison.InvariantCultureIgnoreCase));
    93         }
    94         /// <summary>
    95         /// Removes the item
    96         /// </summary>
    97         /// <param name="Item"></param>
    98         public void Remove(T Item)
    99         {
    100             _list.Remove(Item);
    101         }
    102         /// <summary>
    103         /// Removes the item at the specified index
    104         /// </summary>
    105         /// <param name="index">THe index</param>
    106         public void RemoveAt(int index)
    107         {
    108             _list.RemoveAt(index);
    109         }
    110        
    111         internal void Clear()
    112         {
    113             _list.Clear();
    114         }
    115     }
    116     /// <summary>
    117     /// Collection class for VBA modules
    118     /// </summary>
    119     public class ExcelVbaModuleCollection : ExcelVBACollectionBase<ExcelVBAModule>
    120     {
    121         ExcelVbaProject _project;
    122         internal ExcelVbaModuleCollection (ExcelVbaProject project)
    123       {
    124             _project=project;
    125       }
    126         internal void Add(ExcelVBAModule Item)
    127         {
    128             _list.Add(Item);
    129         }
    130         /// <summary>
    131         /// Adds a new VBA Module
    132         /// </summary>
    133         /// <param name="Name">The name of the module</param>
    134         /// <returns>The module object</returns>
    135         public ExcelVBAModule AddModule(string Name)
    136         {
    137             if (this[Name] != null)
    138             {
    139                 throw(new ArgumentException("Vba modulename already exist."));
    140             }
    141             var m = new ExcelVBAModule();
    142             m.Name = Name;
    143             m.Type = eModuleType.Module;
    144             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Name", Value = Name, DataType = eAttributeDataType.String });
    145             m.Type = eModuleType.Module;
    146             _list.Add(m);
    147             return m;
    148         }
    149         /// <summary>
    150         /// Adds a new VBA class
    151         /// </summary>
    152         /// <param name="Name">The name of the class</param>
    153         /// <param name="Exposed">Private or Public not createble</param>
    154         /// <returns>The class object</returns>
    155         public ExcelVBAModule AddClass(string Name, bool Exposed)
    156         {
    157             var m = new ExcelVBAModule();
    158             m.Name = Name;           
    159             m.Type = eModuleType.Class;
    160             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Name", Value = Name, DataType = eAttributeDataType.String });
    161             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Base", Value = "0{FCFB3D2A-A0FA-1068-A738-08002B3371B5}", DataType = eAttributeDataType.String });
    162             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_GlobalNameSpace", Value = "False", DataType = eAttributeDataType.NonString });
    163             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Creatable", Value = "False", DataType = eAttributeDataType.NonString });
    164             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_PredeclaredId", Value = "False", DataType = eAttributeDataType.NonString });
    165             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Exposed", Value = Exposed ? "True" : "False", DataType = eAttributeDataType.NonString });
    166             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_TemplateDerived", Value = "False", DataType = eAttributeDataType.NonString });
    167             m.Attributes._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Customizable", Value = "False", DataType = eAttributeDataType.NonString });
    168 
    169             //m.Code = _project.GetBlankClassModule(Name, Exposed);
    170             m.Private = !Exposed;
    171             //m.ClassID=
    172             _list.Add(m);
    173             return m;
    174         }
    175     }
    176     /// <summary>
    177     /// A collection of the vba projects references
    178     /// </summary>
    179     public class ExcelVbaReferenceCollection : ExcelVBACollectionBase<ExcelVbaReference>
    180     {       
    181         internal ExcelVbaReferenceCollection()
    182         {
    183 
    184         }
    185         /// <summary>
    186         /// Adds a new reference
    187         /// </summary>
    188         /// <param name="Item">The reference object</param>
    189         public void Add(ExcelVbaReference Item)
    190         {
    191             _list.Add(Item);
    192         }
    193     }
    194     /// <summary>
    195     /// A collection of the module level attributes
    196     /// </summary>
    197     public class ExcelVbaModuleAttributesCollection : ExcelVBACollectionBase<ExcelVbaModuleAttribute>
    198     {
    199         internal string GetAttributeText()
    200         {
    201             StringBuilder sb=new StringBuilder();
    202 
    203             foreach (var attr in this)
    204             {
    205                 sb.AppendFormat("Attribute {0} = {1}\r\n", attr.Name, attr.DataType==eAttributeDataType.String ? "\"" + attr.Value + "\"" : attr.Value);
    206             }
    207             return sb.ToString();
    208         }
    209     }
    210 }
  • VBA/ExcelVBAProject.cs

     
    1 ï»¿/*******************************************************************************
    2  * You may amend and distribute as you like, but don't remove this header!
    3  *
    4  * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
    5  * See http://www.codeplex.com/EPPlus for details.
    6  *
    7  * Copyright (C) 2011  Jan KÀllman
    8  *
    9  * All code and executables are provided "as is" with no warranty either express or implied.
    10  * The author accepts no liability for any damage or loss of business that this product may cause.
    11  *
    12  * If you want to understand this code have a look at the Office VBA File Format Structure Specification (MS-OVBA.PDF) or
    13  * http://msdn.microsoft.com/en-us/library/cc313094(v=office.12).aspx
    14  *
    15  * * Code change notes:
    16  *
    17  * Author             Change            Date
    18  *******************************************************************************
    19  * Jan KÀllman   Added   26-MAR-2012
    20  *******************************************************************************/
    21 using System;
    22 using System.Collections.Generic;
    23 using System.Globalization;
    24 using System.Linq;
    25 using System.Text;
    26 using System.IO;
    27 using OfficeOpenXml.Utils;
    28 using System.Security.Cryptography.Pkcs;
    29 using System.Security.Cryptography.X509Certificates;
    30 using System.Security.Cryptography;
    31 using System.Text.RegularExpressions;
    32 
    33 namespace OfficeOpenXml.VBA
    34 {
    35     /// <summary>
    36     /// Represents the VBA project part of the package
    37     /// </summary>
    38     public class ExcelVbaProject
    39     {
    40         const string schemaRelVba = "http://schemas.microsoft.com/office/2006/relationships/vbaProject";
    41         internal const string PartUri = @"/xl/vbaProject.bin";
    42         #region Classes & Enums
    43         /// <summary>
    44         /// Type of system where the VBA project was created.
    45         /// </summary>
    46         public enum eSyskind
    47         {
    48             Win16 = 0,
    49             Win32 = 1,
    50             Macintosh = 2,
    51             Win64 = 3
    52         }
    53 
    54         #endregion
    55         internal ExcelVbaProject(ExcelWorkbook wb)
    56         {
    57             _wb = wb;
    58             _pck = _wb._package.Package;
    59             References = new ExcelVbaReferenceCollection();
    60             Modules = new ExcelVbaModuleCollection(this);
    61             var rel = _wb.Part.GetRelationshipsByType(schemaRelVba).FirstOrDefault();
    62             if (rel != null)
    63             {
    64                 Uri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
    65                 Part = _pck.GetPart(Uri);
    66 #if !MONO
    67                 GetProject();               
    68 #endif
    69             }
    70             else
    71             {
    72                 Lcid = 0;
    73                 Part = null;
    74             }
    75         }
    76         internal ExcelWorkbook _wb;
    77         internal Packaging.ZipPackage _pck;
    78         #region Dir Stream Properties
    79         /// <summary>
    80         /// System kind. Default Win32.
    81         /// </summary>
    82         public eSyskind SystemKind { get; set; }
    83         /// <summary>
    84         /// Name of the project
    85         /// </summary>
    86         public string Name { get; set; }
    87         /// <summary>
    88         /// A description of the project
    89         /// </summary>
    90         public string Description { get; set; }
    91         /// <summary>
    92         /// A helpfile
    93         /// </summary>
    94         public string HelpFile1 { get; set; }
    95         /// <summary>
    96         /// Secondary helpfile
    97         /// </summary>
    98         public string HelpFile2 { get; set; }
    99         /// <summary>
    100         /// Context if refering the helpfile
    101         /// </summary>
    102         public int HelpContextID { get; set; }
    103         /// <summary>
    104         /// Conditional compilation constants
    105         /// </summary>
    106         public string Constants { get; set; }
    107         /// <summary>
    108         /// Codepage for encoding. Default is current regional setting.
    109         /// </summary>
    110         public int CodePage { get; internal set; }
    111         internal int LibFlags { get; set; }
    112         internal int MajorVersion { get; set; }
    113         internal int MinorVersion { get; set; }
    114         internal int Lcid { get; set; }
    115         internal int LcidInvoke { get; set; }
    116         internal string ProjectID { get; set; }
    117         internal string ProjectStreamText { get; set; }
    118         /// <summary>
    119         /// Project references
    120         /// </summary>       
    121         public ExcelVbaReferenceCollection References { get; set; }
    122         /// <summary>
    123         /// Code Modules (Modules, classes, designer code)
    124         /// </summary>
    125         public ExcelVbaModuleCollection Modules { get; set; }
    126         ExcelVbaSignature _signature = null;
    127         /// <summary>
    128         /// The digital signature
    129         /// </summary>
    130         public ExcelVbaSignature Signature
    131         {
    132             get
    133             {
    134                 if (_signature == null)
    135                 {
    136                     _signature=new ExcelVbaSignature(Part);
    137                 }
    138                 return _signature;
    139             }
    140         }
    141         ExcelVbaProtection _protection=null;
    142         /// <summary>
    143         /// VBA protection
    144         /// </summary>
    145         public ExcelVbaProtection Protection
    146         {
    147             get
    148             {
    149                 if (_protection == null)
    150                 {
    151                     _protection = new ExcelVbaProtection(this);
    152                 }
    153                 return _protection;
    154             }
    155         }
    156         #endregion
    157 #if !MONO
    158         #region Read Project
    159         private void GetProject()
    160         {
    161 
    162             var stream = Part.GetStream();
    163             byte[] vba;
    164             vba = new byte[stream.Length];
    165             stream.Read(vba, 0, (int)stream.Length);
    166             Document = new CompoundDocument(vba);
    167 
    168             ReadDirStream();
    169             ProjectStreamText = Encoding.GetEncoding(CodePage).GetString(Document.Storage.DataStreams["PROJECT"]);
    170             ReadModules();
    171             ReadProjectProperties();
    172         }
    173         private void ReadModules()
    174         {
    175             foreach (var modul in Modules)
    176             {
    177                 var stream = Document.Storage.SubStorage["VBA"].DataStreams[modul.streamName];
    178                 var byCode = CompoundDocument.DecompressPart(stream, (int)modul.ModuleOffset);
    179                 string code = Encoding.GetEncoding(CodePage).GetString(byCode);
    180                 int pos=0;
    181                 while(pos+9<code.Length && code.Substring(pos,9)=="Attribute")
    182                 {
    183                     int linePos=code.IndexOf("\r\n",pos);
    184                     string[] lineSplit;
    185                     if(linePos>0)
    186                     {
    187                         lineSplit = code.Substring(pos + 9, linePos - pos - 9).Split('=');
    188                     }
    189                     else
    190                     {
    191                         lineSplit=code.Substring(pos+9).Split(new char[]{'='},1);
    192                     }
    193                     if (lineSplit.Length > 1)
    194                     {
    195                         lineSplit[1] = lineSplit[1].Trim();
    196                         var attr =
    197                             new ExcelVbaModuleAttribute()
    198                         {
    199                             Name = lineSplit[0].Trim(),
    200                             DataType = lineSplit[1].StartsWith("\"") ? eAttributeDataType.String : eAttributeDataType.NonString,
    201                             Value = lineSplit[1].StartsWith("\"") ? lineSplit[1].Substring(1, lineSplit[1].Length - 2) : lineSplit[1]
    202                         };
    203                         modul.Attributes._list.Add(attr);
    204                     }
    205                     pos = linePos + 2;
    206                 }
    207                 modul.Code=code.Substring(pos);
    208             }
    209         }
    210 
    211         private void ReadProjectProperties()
    212         {
    213             _protection = new ExcelVbaProtection(this);
    214             string prevPackage = "";
    215             var lines = Regex.Split(ProjectStreamText, "\r\n");
    216             foreach (string line in lines)
    217             {
    218                 if (line.StartsWith("["))
    219                 {
    220 
    221                 }
    222                 else
    223                 {
    224                     var split = line.Split('=');
    225                     if (split.Length > 1 && split[1].Length > 1 && split[1].StartsWith("\"")) //Remove any double qouates
    226                     {
    227                         split[1] = split[1].Substring(1, split[1].Length - 2);
    228                     }
    229                     switch (split[0])
    230                     {
    231                         case "ID":
    232                             ProjectID = split[1];
    233                             break;
    234                         case "Document":
    235                             string mn = split[1].Substring(0, split[1].IndexOf("/&H"));
    236                             Modules[mn].Type = eModuleType.Document;
    237                             break;
    238                         case "Package":
    239                             prevPackage = split[1];
    240                             break;
    241                         case "BaseClass":
    242                             Modules[split[1]].Type = eModuleType.Designer;
    243                             Modules[split[1]].ClassID = prevPackage;
    244                             break;
    245                         case "Module":
    246                             Modules[split[1]].Type = eModuleType.Module;
    247                             break;
    248                         case "Class":
    249                             Modules[split[1]].Type = eModuleType.Class;
    250                             break;
    251                         case "HelpFile":
    252                         case "Name":
    253                         case "HelpContextID":
    254                         case "Description":
    255                         case "VersionCompatible32":
    256                             break;
    257                         //393222000"
    258                         case "CMG":
    259                             byte[] cmg = Decrypt(split[1]);
    260                             _protection.UserProtected = (cmg[0] & 1) != 0;
    261                             _protection.HostProtected = (cmg[0] & 2) != 0;
    262                             _protection.VbeProtected = (cmg[0] & 4) != 0;
    263                             break;
    264                         case "DPB":
    265                             byte[] dpb = Decrypt(split[1]);
    266                             if (dpb.Length >= 28)
    267                             {
    268                                 byte reserved = dpb[0];
    269                                 var flags = new byte[3];
    270                                 Array.Copy(dpb, 1, flags, 0, 3);
    271                                 var keyNoNulls = new byte[4];
    272                                 _protection.PasswordKey = new byte[4];
    273                                 Array.Copy(dpb, 4, keyNoNulls, 0, 4);
    274                                 var hashNoNulls = new byte[20];
    275                                 _protection.PasswordHash = new byte[20];
    276                                 Array.Copy(dpb, 8, hashNoNulls, 0, 20);
    277                                 //Handle 0x00 bitwise 2.4.4.3
    278                                 for (int i = 0; i < 24; i++)
    279                                 {
    280                                     int bit = 128 >> (int)((i % 8));
    281                                     if (i < 4)
    282                                     {
    283                                         if ((int)(flags[0] & bit) == 0)
    284                                         {
    285                                             _protection.PasswordKey[i] = 0;
    286                                         }
    287                                         else
    288                                         {
    289                                             _protection.PasswordKey[i] = keyNoNulls[i];
    290                                         }
    291                                     }
    292                                     else
    293                                     {
    294                                         int flagIndex = (i - i % 8) / 8;
    295                                         if ((int)(flags[flagIndex] & bit) == 0)
    296                                         {
    297                                             _protection.PasswordHash[i - 4] = 0;
    298                                         }
    299                                         else
    300                                         {
    301                                             _protection.PasswordHash[i - 4] = hashNoNulls[i - 4];
    302                                         }
    303                                     }
    304                                 }
    305                             }
    306                             break;
    307                         case "GC":
    308                             _protection.VisibilityState = Decrypt(split[1])[0] == 0xFF;
    309 
    310                             break;
    311                     }
    312                 }
    313             }
    314         }
    315 
    316         /// <summary>
    317         /// 2.4.3.3 Decryption
    318         /// </summary>
    319         /// <param name="value">Byte hex string</param>
    320         /// <returns>The decrypted value</returns>
    321         private byte[] Decrypt(string value)
    322         {
    323             byte[] enc = GetByte(value);
    324             byte[] dec = new byte[(value.Length - 1)];
    325             byte seed, version, projKey, ignoredLength;
    326             seed = enc[0];
    327             dec[0] = (byte)(enc[1] ^ seed);
    328             dec[1] = (byte)(enc[2] ^ seed);
    329             for (int i = 2; i < enc.Length - 1; i++)
    330             {
    331                 dec[i] = (byte)(enc[i + 1] ^ (enc[i - 1] + dec[i - 1]));
    332             }
    333             version = dec[0];
    334             projKey = dec[1];
    335             ignoredLength = (byte)((seed & 6) / 2);
    336             int datalength = BitConverter.ToInt32(dec, ignoredLength + 2);
    337             var data = new byte[datalength];
    338             Array.Copy(dec, 6 + ignoredLength, data, 0, datalength);
    339             return data;
    340         }
    341         /// <summary>
    342         /// 2.4.3.2 Encryption
    343         /// </summary>
    344         /// <param name="value"></param>
    345         /// <returns>Byte hex string</returns>
    346         private string Encrypt(byte[] value)
    347         {
    348             byte[] seed = new byte[1];
    349             var rn = RandomNumberGenerator.Create();
    350             rn.GetBytes(seed);
    351             BinaryWriter br = new BinaryWriter(new MemoryStream());
    352             byte[] enc = new byte[value.Length + 10];
    353             enc[0] = seed[0];
    354             enc[1] = (byte)(2 ^ seed[0]);
    355 
    356             byte projKey = 0;
    357 
    358             foreach (var c in ProjectID)
    359             {
    360                 projKey += (byte)c;
    361             }
    362             enc[2] = (byte)(projKey ^ seed[0]);
    363             var ignoredLength = (seed[0] & 6) / 2;
    364             for (int i = 0; i < ignoredLength; i++)
    365             {
    366                 br.Write(seed[0]);
    367             }
    368             br.Write(value.Length);
    369             br.Write(value);
    370 
    371             int pos = 3;
    372             byte pb = projKey;
    373             foreach (var b in ((MemoryStream)br.BaseStream).ToArray())
    374             {
    375                 enc[pos] = (byte)(b ^ (enc[pos - 2] + pb));
    376                 pos++;
    377                 pb = b;
    378             }
    379 
    380             return GetString(enc, pos - 1);
    381         }
    382         private string GetString(byte[] value, int max)
    383         {
    384             string ret = "";
    385             for (int i = 0; i <= max; i++)
    386             {
    387                 if (value[i] < 16)
    388                 {
    389                     ret += "0" + value[i].ToString("x");
    390                 }
    391                 else
    392                 {
    393                     ret += value[i].ToString("x");
    394                 }
    395             }
    396             return ret.ToUpper(CultureInfo.InvariantCulture);
    397         }
    398         private byte[] GetByte(string value)
    399         {
    400             byte[] ret = new byte[value.Length / 2];
    401             for (int i = 0; i < ret.Length; i++)
    402             {
    403                 ret[i] = byte.Parse(value.Substring(i * 2, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
    404             }
    405             return ret;
    406         }
    407         private void ReadDirStream()
    408         {
    409             byte[] dir = CompoundDocument.DecompressPart(Document.Storage.SubStorage["VBA"].DataStreams["dir"]);
    410             MemoryStream ms = new MemoryStream(dir);
    411             BinaryReader br = new BinaryReader(ms);
    412             ExcelVbaReference currentRef = null;
    413             string referenceName = "";
    414             ExcelVBAModule currentModule = null;
    415             bool terminate = false;
    416             while (br.BaseStream.Position < br.BaseStream.Length && terminate == false)
    417             {
    418                 ushort id = br.ReadUInt16();
    419                 uint size = br.ReadUInt32();
    420                 switch (id)
    421                 {
    422                     case 0x01:
    423                         SystemKind = (eSyskind)br.ReadUInt32();
    424                         break;
    425                     case 0x02:
    426                         Lcid = (int)br.ReadUInt32();
    427                         break;
    428                     case 0x03:
    429                         CodePage = (int)br.ReadUInt16();
    430                         break;
    431                     case 0x04:
    432                         Name = GetString(br, size);
    433                         break;
    434                     case 0x05:
    435                         Description = GetUnicodeString(br, size);
    436                         break;
    437                     case 0x06:
    438                         HelpFile1 = GetString(br, size);
    439                         break;
    440                     case 0x3D:
    441                         HelpFile2 = GetString(br, size);
    442                         break;
    443                     case 0x07:
    444                         HelpContextID = (int)br.ReadUInt32();
    445                         break;
    446                     case 0x08:
    447                         LibFlags = (int)br.ReadUInt32();
    448                         break;
    449                     case 0x09:
    450                         MajorVersion = (int)br.ReadUInt32();
    451                         MinorVersion = (int)br.ReadUInt16();
    452                         break;
    453                     case 0x0C:
    454                         Constants = GetUnicodeString(br, size);
    455                         break;
    456                     case 0x0D:
    457                         uint sizeLibID = br.ReadUInt32();
    458                         var regRef = new ExcelVbaReference();
    459                         regRef.Name = referenceName;
    460                         regRef.ReferenceRecordID = id;
    461                         regRef.Libid = GetString(br, sizeLibID);
    462                         uint reserved1 = br.ReadUInt32();
    463                         ushort reserved2 = br.ReadUInt16();
    464                         References.Add(regRef);
    465                         break;
    466                     case 0x0E:
    467                         var projRef = new ExcelVbaReferenceProject();
    468                         projRef.ReferenceRecordID = id;
    469                         projRef.Name = referenceName;
    470                         sizeLibID = br.ReadUInt32();
    471                         projRef.Libid = GetString(br, sizeLibID);
    472                         sizeLibID = br.ReadUInt32();
    473                         projRef.LibIdRelative = GetString(br, sizeLibID);
    474                         projRef.MajorVersion = br.ReadUInt32();
    475                         projRef.MinorVersion = br.ReadUInt16();
    476                         References.Add(projRef);
    477                         break;
    478                     case 0x0F:
    479                         ushort modualCount = br.ReadUInt16();
    480                         break;
    481                     case 0x13:
    482                         ushort cookie = br.ReadUInt16();
    483                         break;
    484                     case 0x14:
    485                         LcidInvoke = (int)br.ReadUInt32();
    486                         break;
    487                     case 0x16:
    488                         referenceName = GetUnicodeString(br, size);
    489                         break;
    490                     case 0x19:
    491                         currentModule = new ExcelVBAModule();
    492                         currentModule.Name = GetUnicodeString(br, size);
    493                         Modules.Add(currentModule);
    494                         break;
    495                     case 0x1A:
    496                         currentModule.streamName = GetUnicodeString(br, size);
    497                         break;
    498                     case 0x1C:
    499                         currentModule.Description = GetUnicodeString(br, size);
    500                         break;
    501                     case 0x1E:
    502                         currentModule.HelpContext = (int)br.ReadUInt32();
    503                         break;
    504                     case 0x21:
    505                     case 0x22:
    506                         break;
    507                     case 0x2B:      //Modul Terminator
    508                         break;
    509                     case 0x2C:
    510                         currentModule.Cookie = br.ReadUInt16();
    511                         break;
    512                     case 0x31:
    513                         currentModule.ModuleOffset = br.ReadUInt32();
    514                         break;
    515                     case 0x10:
    516                         terminate = true;
    517                         break;
    518                     case 0x30:
    519                         var extRef = (ExcelVbaReferenceControl)currentRef;
    520                         var sizeExt = br.ReadUInt32();
    521                         extRef.LibIdExternal = GetString(br, sizeExt);
    522 
    523                         uint reserved4 = br.ReadUInt32();
    524                         ushort reserved5 = br.ReadUInt16();
    525                         extRef.OriginalTypeLib = new Guid(br.ReadBytes(16));
    526                         extRef.Cookie = br.ReadUInt32();
    527                         break;
    528                     case 0x33:
    529                         currentRef = new ExcelVbaReferenceControl();
    530                         currentRef.ReferenceRecordID = id;
    531                         currentRef.Name = referenceName;
    532                         currentRef.Libid = GetString(br, size);
    533                         References.Add(currentRef);
    534                         break;
    535                     case 0x2F:
    536                         var contrRef = (ExcelVbaReferenceControl)currentRef;
    537                         contrRef.ReferenceRecordID = id;
    538 
    539                         var sizeTwiddled = br.ReadUInt32();
    540                         contrRef.LibIdTwiddled = GetString(br, sizeTwiddled);
    541                         var r1 = br.ReadUInt32();
    542                         var r2 = br.ReadUInt16();
    543 
    544                         break;
    545                     case 0x25:
    546                         currentModule.ReadOnly = true;
    547                         break;
    548                     case 0x28:
    549                         currentModule.Private = true;
    550                         break;
    551                     default:
    552                         break;
    553                 }
    554             }
    555         }
    556         #endregion
    557 
    558         #region Save Project
    559         internal void Save()
    560         {
    561             if (Validate())
    562             {
    563                 CompoundDocument doc = new CompoundDocument();
    564                 doc.Storage = new CompoundDocument.StoragePart();
    565                 var store = new CompoundDocument.StoragePart();
    566                 doc.Storage.SubStorage.Add("VBA", store);
    567 
    568                 store.DataStreams.Add("_VBA_PROJECT", CreateVBAProjectStream());
    569                 store.DataStreams.Add("dir", CreateDirStream());
    570                 foreach (var module in Modules)
    571                 {
    572                     store.DataStreams.Add(module.Name, CompoundDocument.CompressPart(Encoding.GetEncoding(CodePage).GetBytes(module.Attributes.GetAttributeText() + module.Code)));
    573                 }
    574 
    575                 //Copy streams from the template, if used.
    576                 if (Document != null)
    577                 {
    578                     foreach (var ss in Document.Storage.SubStorage)
    579                     {
    580                         if (ss.Key != "VBA")
    581                         {
    582                             doc.Storage.SubStorage.Add(ss.Key, ss.Value);
    583                         }
    584                     }
    585                     foreach (var s in Document.Storage.DataStreams)
    586                     {
    587                         if (s.Key != "dir" && s.Key != "PROJECT" && s.Key != "PROJECTwm")
    588                         {
    589                             doc.Storage.DataStreams.Add(s.Key, s.Value);
    590                         }
    591                     }
    592                 }
    593 
    594                 doc.Storage.DataStreams.Add("PROJECT", CreateProjectStream());
    595                 doc.Storage.DataStreams.Add("PROJECTwm", CreateProjectwmStream());
    596 
    597                 if (Part == null)
    598                 {
    599                     Uri = new Uri(PartUri, UriKind.Relative);
    600                     Part = _pck.CreatePart(Uri, ExcelPackage.schemaVBA);
    601                     var rel = _wb.Part.CreateRelationship(Uri, Packaging.TargetMode.Internal, schemaRelVba);
    602                 }
    603                 var vbaBuffer=doc.Save();
    604                 var st = Part.GetStream(FileMode.Create);
    605                 st.Write(vbaBuffer, 0, vbaBuffer.Length);
    606                 st.Flush();
    607                 //Save the digital signture
    608                 Signature.Save(this);
    609             }
    610         }
    611 
    612         private bool Validate()
    613         {
    614             Description = Description ?? "";
    615             HelpFile1 = HelpFile1 ?? "";
    616             HelpFile2 = HelpFile2 ?? "";
    617             Constants = Constants ?? "";
    618             return true;
    619         }
    620 
    621         /// <summary>
    622         /// MS-OVBA 2.3.4.1
    623         /// </summary>
    624         /// <returns></returns>
    625         private byte[] CreateVBAProjectStream()
    626         {
    627             BinaryWriter bw = new BinaryWriter(new MemoryStream());
    628             bw.Write((ushort)0x61CC); //Reserved1
    629             bw.Write((ushort)0xFFFF); //Version
    630             bw.Write((byte)0x0); //Reserved3
    631             bw.Write((ushort)0x0); //Reserved4
    632             return ((MemoryStream)bw.BaseStream).ToArray();
    633         }
    634         /// <summary>
    635         /// MS-OVBA 2.3.4.1
    636         /// </summary>
    637         /// <returns></returns>
    638         private byte[] CreateDirStream()
    639         {
    640             BinaryWriter bw = new BinaryWriter(new MemoryStream());
    641 
    642             /****** PROJECTINFORMATION Record ******/
    643             bw.Write((ushort)1);        //ID
    644             bw.Write((uint)4);          //Size
    645             bw.Write((uint)SystemKind); //SysKind
    646 
    647             bw.Write((ushort)2);        //ID
    648             bw.Write((uint)4);          //Size
    649             bw.Write((uint)Lcid);       //Lcid
    650 
    651             bw.Write((ushort)0x14);     //ID
    652             bw.Write((uint)4);          //Size
    653             bw.Write((uint)LcidInvoke); //Lcid Invoke
    654 
    655             bw.Write((ushort)3);        //ID
    656             bw.Write((uint)2);          //Size
    657             bw.Write((ushort)CodePage);   //Codepage
    658 
    659             //ProjectName
    660             bw.Write((ushort)4);                                            //ID
    661             bw.Write((uint)Name.Length);                             //Size
    662             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(Name)); //Project Name
    663 
    664             //Description
    665             bw.Write((ushort)5);                                            //ID
    666             bw.Write((uint)Description.Length);                             //Size
    667             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(Description)); //Project Name
    668             bw.Write((ushort)0x40);                                           //ID
    669             bw.Write((uint)Description.Length*2);                           //Size
    670             bw.Write(Encoding.Unicode.GetBytes(Description));               //Project Description
    671 
    672             //Helpfiles
    673             bw.Write((ushort)6);                                           //ID
    674             bw.Write((uint)HelpFile1.Length);                              //Size
    675             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(HelpFile1));  //HelpFile1           
    676             bw.Write((ushort)0x3D);                                           //ID
    677             bw.Write((uint)HelpFile2.Length);                              //Size
    678             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(HelpFile2));  //HelpFile2
    679 
    680             //Help context id
    681             bw.Write((ushort)7);            //ID
    682             bw.Write((uint)4);              //Size
    683             bw.Write((uint)HelpContextID);  //Help context id
    684 
    685             //Libflags
    686             bw.Write((ushort)8);            //ID
    687             bw.Write((uint)4);              //Size
    688             bw.Write((uint)0);  //Help context id
    689 
    690             //Vba Version
    691             bw.Write((ushort)9);            //ID
    692             bw.Write((uint)4);              //Reserved
    693             bw.Write((uint)MajorVersion);   //Reserved
    694             bw.Write((ushort)MinorVersion); //Help context id
    695 
    696             //Constants
    697             bw.Write((ushort)0x0C);           //ID
    698             bw.Write((uint)Constants.Length);              //Size
    699             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(Constants));              //Help context id
    700             bw.Write((ushort)0x3C);                                           //ID
    701             bw.Write((uint)Constants.Length/2);                              //Size
    702             bw.Write(Encoding.Unicode.GetBytes(Constants));  //HelpFile2
    703 
    704             /****** PROJECTREFERENCES Record ******/
    705             foreach (var reference in References)
    706             {
    707                 WriteNameReference(bw, reference);
    708 
    709                 if (reference.ReferenceRecordID == 0x2F)
    710                 {
    711                     WriteControlReference(bw, reference);
    712                 }
    713                 else if (reference.ReferenceRecordID == 0x33)
    714                 {
    715                     WriteOrginalReference(bw, reference);
    716                 }
    717                 else if (reference.ReferenceRecordID == 0x0D)
    718                 {
    719                     WriteRegisteredReference(bw, reference);
    720                 }
    721                 else if (reference.ReferenceRecordID == 0x0E)
    722                 {
    723                     WriteProjectReference(bw, reference);
    724                 }
    725             }
    726 
    727             bw.Write((ushort)0x0F);
    728             bw.Write((uint)0x02);
    729             bw.Write((ushort)Modules.Count);
    730             bw.Write((ushort)0x13);
    731             bw.Write((uint)0x02);
    732             bw.Write((ushort)0xFFFF);
    733 
    734             foreach (var module in Modules)
    735             {
    736                 WriteModuleRecord(bw, module);
    737             }
    738             bw.Write((ushort)0x10);             //Terminator
    739             bw.Write((uint)0);             
    740 
    741             return CompoundDocument.CompressPart(((MemoryStream)bw.BaseStream).ToArray());
    742         }
    743 
    744         private void WriteModuleRecord(BinaryWriter bw, ExcelVBAModule module)
    745         {
    746             bw.Write((ushort)0x19);
    747             bw.Write((uint)module.Name.Length);
    748             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(module.Name));     //Name
    749 
    750             bw.Write((ushort)0x47);
    751             bw.Write((uint)module.Name.Length*2);
    752             bw.Write(Encoding.Unicode.GetBytes(module.Name));                   //Name
    753 
    754             bw.Write((ushort)0x1A);
    755             bw.Write((uint)module.Name.Length);
    756             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(module.Name));     //Stream Name 
    757 
    758             bw.Write((ushort)0x32);
    759             bw.Write((uint)module.Name.Length*2);
    760             bw.Write(Encoding.Unicode.GetBytes(module.Name));                   //Stream Name
    761 
    762             module.Description = module.Description ?? "";
    763             bw.Write((ushort)0x1C);
    764             bw.Write((uint)module.Description.Length);
    765             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(module.Description));     //Description
    766 
    767             bw.Write((ushort)0x48);
    768             bw.Write((uint)module.Description.Length*2);
    769             bw.Write(Encoding.Unicode.GetBytes(module.Description));                   //Description
    770 
    771             bw.Write((ushort)0x31);
    772             bw.Write((uint)4);
    773             bw.Write((uint)0);                              //Module Stream Offset (No PerformanceCache)
    774 
    775             bw.Write((ushort)0x1E);
    776             bw.Write((uint)4);
    777             bw.Write((uint)module.HelpContext);            //Help context ID
    778 
    779             bw.Write((ushort)0x2C);
    780             bw.Write((uint)2);
    781             bw.Write((ushort)0xFFFF);            //Help context ID
    782 
    783             bw.Write((ushort)(module.Type == eModuleType.Module ? 0x21 : 0x22));
    784             bw.Write((uint)0);
    785 
    786             if (module.ReadOnly)
    787             {
    788                 bw.Write((ushort)0x25);
    789                 bw.Write((uint)0);              //Readonly
    790             }
    791 
    792             if (module.Private)
    793             {
    794                 bw.Write((ushort)0x28);
    795                 bw.Write((uint)0);              //Private
    796             }
    797 
    798             bw.Write((ushort)0x2B);             //Terminator
    799             bw.Write((uint)0);             
    800         }
    801 
    802         private void WriteNameReference(BinaryWriter bw, ExcelVbaReference reference)
    803         {
    804             //Name record
    805             bw.Write((ushort)0x16);                                             //ID
    806             bw.Write((uint)reference.Name.Length);                              //Size
    807             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(reference.Name));  //HelpFile1
    808             bw.Write((ushort)0x3E);                                             //ID
    809             bw.Write((uint)reference.Name.Length * 2);                            //Size
    810             bw.Write(Encoding.Unicode.GetBytes(reference.Name));                //HelpFile2
    811         }
    812         private void WriteControlReference(BinaryWriter bw, ExcelVbaReference reference)
    813         {
    814             WriteOrginalReference(bw, reference);
    815 
    816             bw.Write((ushort)0x2F);
    817             var controlRef=(ExcelVbaReferenceControl)reference;
    818             bw.Write((uint)(4 + controlRef.LibIdTwiddled.Length + 4 + 2));    // Size of SizeOfLibidTwiddled, LibidTwiddled, Reserved1, and Reserved2.
    819             bw.Write((uint)controlRef.LibIdTwiddled.Length);                              //Size           
    820             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(controlRef.LibIdTwiddled));  //LibID
    821             bw.Write((uint)0);      //Reserved1
    822             bw.Write((ushort)0);    //Reserved2
    823             WriteNameReference(bw, reference);  //Name record again
    824             bw.Write((ushort)0x30); //Reserved3
    825             bw.Write((uint)(4 + controlRef.LibIdExternal.Length + 4 + 2 + 16 + 4));    //Size of SizeOfLibidExtended, LibidExtended, Reserved4, Reserved5, OriginalTypeLib, and Cookie
    826             bw.Write((uint)controlRef.LibIdExternal.Length);                              //Size           
    827             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(controlRef.LibIdExternal));  //LibID
    828             bw.Write((uint)0);      //Reserved4
    829             bw.Write((ushort)0);    //Reserved5
    830             bw.Write(controlRef.OriginalTypeLib.ToByteArray());
    831             bw.Write((uint)controlRef.Cookie);      //Cookie
    832         }
    833 
    834         private void WriteOrginalReference(BinaryWriter bw, ExcelVbaReference reference)
    835         {
    836             bw.Write((ushort)0x33);
    837             bw.Write((uint)reference.Libid.Length);
    838             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(reference.Libid));  //LibID
    839         }
    840         private void WriteProjectReference(BinaryWriter bw, ExcelVbaReference reference)
    841         {
    842             bw.Write((ushort)0x0E);
    843             var projRef = (ExcelVbaReferenceProject)reference;
    844             bw.Write((uint)(4 + projRef.Libid.Length + 4 + projRef.LibIdRelative.Length+4+2));
    845             bw.Write((uint)projRef.Libid.Length);
    846             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(projRef.Libid));  //LibAbsolute
    847             bw.Write((uint)projRef.LibIdRelative.Length);
    848             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(projRef.LibIdRelative));  //LibIdRelative
    849             bw.Write(projRef.MajorVersion);
    850             bw.Write(projRef.MinorVersion);
    851         }
    852 
    853         private void WriteRegisteredReference(BinaryWriter bw, ExcelVbaReference reference)
    854         {
    855             bw.Write((ushort)0x0D);
    856             bw.Write((uint)(4+reference.Libid.Length+4+2));
    857             bw.Write((uint)reference.Libid.Length);
    858             bw.Write(Encoding.GetEncoding(CodePage).GetBytes(reference.Libid));  //LibID           
    859             bw.Write((uint)0);      //Reserved1
    860             bw.Write((ushort)0);    //Reserved2
    861         }
    862 
    863         private byte[] CreateProjectwmStream()
    864         {
    865             BinaryWriter bw = new BinaryWriter(new MemoryStream());
    866 
    867             foreach (var module in Modules)
    868             {
    869                 bw.Write(Encoding.GetEncoding(CodePage).GetBytes(module.Name));     //Name
    870                 bw.Write((byte)0); //Null
    871                 bw.Write(Encoding.Unicode.GetBytes(module.Name));                   //Name
    872                 bw.Write((ushort)0); //Null
    873             }
    874             bw.Write((ushort)0); //Null
    875             return CompoundDocument.CompressPart(((MemoryStream)bw.BaseStream).ToArray());
    876         }       
    877         private byte[] CreateProjectStream()
    878         {
    879             StringBuilder sb = new StringBuilder();
    880             sb.AppendFormat("ID=\"{0}\"\r\n", ProjectID);
    881             foreach(var module in Modules)
    882             {
    883                 if (module.Type == eModuleType.Document)
    884                 {
    885                     sb.AppendFormat("Document={0}/&H00000000\r\n", module.Name);
    886                 }
    887                 else if (module.Type == eModuleType.Module)
    888                 {
    889                     sb.AppendFormat("Module={0}\r\n", module.Name);
    890                 }
    891                 else if (module.Type == eModuleType.Class)
    892                 {
    893                     sb.AppendFormat("Class={0}\r\n", module.Name);
    894                 }
    895                 else
    896                 {
    897                     //Designer
    898                     sb.AppendFormat("Package={0}\r\n", module.ClassID);
    899                     sb.AppendFormat("BaseClass={0}\r\n", module.Name);
    900                 }
    901             }
    902             if (HelpFile1 != "")
    903             {
    904                 sb.AppendFormat("HelpFile={0}\r\n", HelpFile1);
    905             }
    906             sb.AppendFormat("Name=\"{0}\"\r\n", Name);
    907             sb.AppendFormat("HelpContextID={0}\r\n", HelpContextID);
    908 
    909             if (!string.IsNullOrEmpty(Description))
    910             {
    911                 sb.AppendFormat("Description=\"{0}\"\r\n", Description);
    912             }
    913             sb.AppendFormat("VersionCompatible32=\"393222000\"\r\n");
    914 
    915             sb.AppendFormat("CMG=\"{0}\"\r\n", WriteProtectionStat());
    916             sb.AppendFormat("DPB=\"{0}\"\r\n", WritePassword());
    917             sb.AppendFormat("GC=\"{0}\"\r\n\r\n", WriteVisibilityState());
    918 
    919             sb.Append("[Host Extender Info]\r\n");
    920             sb.Append("&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000\r\n");
    921             sb.Append("\r\n");
    922             sb.Append("[Workspace]\r\n");
    923             foreach(var module in Modules)
    924             {
    925                 sb.AppendFormat("{0}=0, 0, 0, 0, C \r\n",module.Name);             
    926             }
    927             string s = sb.ToString();
    928             return Encoding.GetEncoding(CodePage).GetBytes(s);
    929         }
    930         private string WriteProtectionStat()
    931         {
    932             int stat=(_protection.UserProtected ? 1:0) | 
    933                      (_protection.HostProtected ? 2:0) |
    934                      (_protection.VbeProtected ? 4:0);
    935 
    936             return Encrypt(BitConverter.GetBytes(stat));   
    937         }
    938         private string WritePassword()
    939         {
    940             byte[] nullBits=new byte[3];
    941             byte[] nullKey = new byte[4];
    942             byte[] nullHash = new byte[20];
    943             if (Protection.PasswordKey == null)
    944             {
    945                 return Encrypt(new byte[] { 0 });
    946             }
    947             else
    948             {
    949                 Array.Copy(Protection.PasswordKey, nullKey, 4);
    950                 Array.Copy(Protection.PasswordHash, nullHash, 20);
    951 
    952                 //Set Null bits
    953                 for (int i = 0; i < 24; i++)
    954                 {
    955                     byte bit = (byte)(128 >> (int)((i % 8)));
    956                     if (i < 4)
    957                     {
    958                         if (nullKey[i] == 0)
    959                         {
    960                             nullKey[i] = 1;
    961                         }
    962                         else
    963                         {
    964                             nullBits[0] |= bit;
    965                         }
    966                     }
    967                     else
    968                     {
    969                         if (nullHash[i - 4] == 0)
    970                         {
    971                             nullHash[i - 4] = 1;
    972                         }
    973                         else
    974                         {
    975                             int byteIndex = (i - i % 8) / 8;
    976                             nullBits[byteIndex] |= bit;
    977                         }
    978                     }
    979                 }
    980                 //Write the Password Hash Data Structure (2.4.4.1)
    981                 BinaryWriter bw = new BinaryWriter(new MemoryStream());
    982                 bw.Write((byte)0xFF);
    983                 bw.Write(nullBits);
    984                 bw.Write(nullKey);
    985                 bw.Write(nullHash);
    986                 bw.Write((byte)0);
    987                 return Encrypt(((MemoryStream)bw.BaseStream).ToArray());
    988             }
    989         }
    990         private string WriteVisibilityState()
    991         {
    992             return Encrypt(new byte[] { (byte)(Protection.VisibilityState ? 0xFF : 0) });
    993         }
    994         #endregion
    995         private string GetString(BinaryReader br, uint size)
    996         {
    997             return GetString(br, size, System.Text.Encoding.GetEncoding(CodePage));
    998         }
    999         private string GetString(BinaryReader br, uint size, Encoding enc)
    1000         {
    1001             if (size > 0)
    1002             {
    1003                 byte[] byteTemp = new byte[size];
    1004                 byteTemp = br.ReadBytes((int)size);
    1005                 return enc.GetString(byteTemp);
    1006             }
    1007             else
    1008             {
    1009                 return "";
    1010             }
    1011         }
    1012         private string GetUnicodeString(BinaryReader br, uint size)
    1013         {
    1014             string s = GetString(br, size);
    1015             int reserved = br.ReadUInt16();
    1016             uint sizeUC = br.ReadUInt32();
    1017             string sUC = GetString(br, sizeUC, System.Text.Encoding.Unicode);
    1018             return sUC.Length == 0 ? s : sUC;
    1019         }
    1020         internal CompoundDocument Document { get; set; }
    1021 #endif
    1022         internal Packaging.ZipPackagePart Part { get; set; }
    1023         internal Uri Uri { get; private set; }
    1024 #if !MONO
    1025         /// <summary>
    1026         /// Create a new VBA Project
    1027         /// </summary>
    1028         internal void Create()
    1029         {
    1030             if(Lcid>0)
    1031             {
    1032                 throw (new InvalidOperationException("Package already contains a VBAProject"));
    1033             }
    1034             ProjectID = "{5DD90D76-4904-47A2-AF0D-D69B4673604E}";
    1035             Name = "VBAProject";
    1036             SystemKind = eSyskind.Win32;            //Default
    1037             Lcid = 1033;                            //English - United States
    1038             LcidInvoke = 1033;                      //English - United States
    1039             CodePage = Encoding.Default.CodePage;
    1040             MajorVersion = 1361024421;
    1041             MinorVersion = 6;
    1042             HelpContextID = 0;
    1043             Modules.Add(new ExcelVBAModule(_wb.CodeNameChange) { Name = "ThisWorkbook", Code = "", Attributes=GetDocumentAttributes("ThisWorkbook", "0{00020819-0000-0000-C000-000000000046}"), Type = eModuleType.Document, HelpContext = 0 });
    1044             foreach (var sheet in _wb.Worksheets)
    1045             {
    1046                 var name = GetModuleNameFromWorksheet(sheet);
    1047                 if (!Modules.Exists(name))
    1048                 {
    1049                     Modules.Add(new ExcelVBAModule(sheet.CodeNameChange) { Name = name, Code = "", Attributes = GetDocumentAttributes(sheet.Name, "0{00020820-0000-0000-C000-000000000046}"), Type = eModuleType.Document, HelpContext = 0 });
    1050                 }
    1051             }
    1052             _protection = new ExcelVbaProtection(this) { UserProtected = false, HostProtected = false, VbeProtected = false, VisibilityState = true };
    1053         }
    1054 
    1055         internal string GetModuleNameFromWorksheet(ExcelWorksheet sheet)
    1056         {
    1057             var name = sheet.Name;
    1058             if (name.Any(c => c > 255) || this.Modules[name] != null)
    1059             {
    1060                 int i = sheet.PositionID;
    1061                 name = "Sheet" + i.ToString();
    1062                 while (this.Modules[name] != null)
    1063                 {
    1064                     name = "Sheet" + (++i).ToString(); ;
    1065                 }
    1066             }           
    1067             return name;
    1068         }
    1069         internal ExcelVbaModuleAttributesCollection GetDocumentAttributes(string name, string clsid)
    1070         {
    1071             var attr = new ExcelVbaModuleAttributesCollection();
    1072             attr._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Name", Value = name, DataType = eAttributeDataType.String });
    1073             attr._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Base", Value = clsid, DataType = eAttributeDataType.String });
    1074             attr._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_GlobalNameSpace", Value = "False", DataType = eAttributeDataType.NonString });
    1075             attr._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Creatable", Value = "False", DataType = eAttributeDataType.NonString });
    1076             attr._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_PredeclaredId", Value = "True", DataType = eAttributeDataType.NonString });
    1077             attr._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Exposed", Value = "False", DataType = eAttributeDataType.NonString });
    1078             attr._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_TemplateDerived", Value = "False", DataType = eAttributeDataType.NonString });
    1079             attr._list.Add(new ExcelVbaModuleAttribute() { Name = "VB_Customizable", Value = "True", DataType = eAttributeDataType.NonString });
    1080 
    1081             return attr;
    1082         }
    1083 
    1084 
    1085         //internal string GetBlankDocumentModule(string name, string clsid)
    1086         //{
    1087         //    string ret=string.Format("Attribute VB_Name = \"{0}\"\r\n",name);
    1088         //    ret += string.Format("Attribute VB_Base = \"{0}\"\r\n", clsid);  //Microsoft.Office.Interop.Excel.WorksheetClass
    1089         //    ret += "Attribute VB_GlobalNameSpace = False\r\n";
    1090         //    ret += "Attribute VB_Creatable = False\r\n";
    1091         //    ret += "Attribute VB_PredeclaredId = True\r\n";
    1092         //    ret += "Attribute VB_Exposed = True\r\n";
    1093         //    ret += "Attribute VB_TemplateDerived = False\r\n";
    1094         //    ret += "Attribute VB_Customizable = True";
    1095         //    return ret;
    1096         //}
    1097         //internal string GetBlankModule(string name)
    1098         //{
    1099         //    return string.Format("Attribute VB_Name = \"{0}\"\r\n", name);
    1100         //}
    1101         //internal string GetBlankClassModule(string name, bool exposed)
    1102         //{
    1103         //    string ret=string.Format("Attribute VB_Name = \"{0}\"\r\n",name);
    1104         //    ret += string.Format("Attribute VB_Base = \"{0}\"\r\n", "0{FCFB3D2A-A0FA-1068-A738-08002B3371B5}"); 
    1105         //    ret += "Attribute VB_GlobalNameSpace = False\r\n";
    1106         //    ret += "Attribute VB_Creatable = False\r\n";
    1107         //    ret += "Attribute VB_PredeclaredId = False\r\n";
    1108         //    ret += string.Format("Attribute VB_Exposed = {0}\r\n", exposed ? "True" : "False");
    1109         //    ret += "Attribute VB_TemplateDerived = False\r\n";
    1110         //    ret += "Attribute VB_Customizable = False\r\n";
    1111         //    return ret;
    1112         //}
    1113 #endif
    1114         /// <summary>
    1115         /// Remove the project from the package
    1116         /// </summary>
    1117         public void Remove()
    1118         {
    1119             if (Part == null) return;
    1120 
    1121             foreach (var rel in Part.GetRelationships())
    1122             {
    1123                 _pck.DeleteRelationship(rel.Id);
    1124             }
    1125             if (_pck.PartExists(Uri))
    1126             {
    1127                 _pck.DeletePart(Uri);
    1128             }
    1129             Part = null;
    1130             Modules.Clear();
    1131             References.Clear();
    1132             Lcid = 0;
    1133             LcidInvoke = 0;
    1134             CodePage = 0;
    1135             MajorVersion = 0;
    1136             MinorVersion = 0;
    1137             HelpContextID = 0;
    1138         }
    1139         public override string ToString()
    1140         {
    1141             return Name;
    1142         }
    1143     }
    1144 }
  • VBA/ExcelVBAReference.cs

     
    1 ï»¿/*******************************************************************************
    2  * You may amend and distribute as you like, but don't remove this header!
    3  *
    4  * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
    5  * See http://www.codeplex.com/EPPlus for details.
    6  *
    7  * Copyright (C) 2011  Jan KÀllman
    8  *
    9  * This library is free software; you can redistribute it and/or
    10  * modify it under the terms of the GNU Lesser General Public
    11  * License as published by the Free Software Foundation; either
    12  * version 2.1 of the License, or (at your option) any later version.
    13 
    14  * This library is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
    17  * See the GNU Lesser General Public License for more details.
    18  *
    19  * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
    20  * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
    21  *
    22  * All code and executables are provided "as is" with no warranty either express or implied.
    23  * The author accepts no liability for any damage or loss of business that this product may cause.
    24  *
    25  * Code change notes:
    26  *
    27  * Author             Change            Date
    28  *******************************************************************************
    29  * Jan KÀllman   Added   26-MAR-2012
    30  *******************************************************************************/
    31 using System;
    32 using System.Collections.Generic;
    33 using System.Linq;
    34 using System.Text;
    35 
    36 namespace OfficeOpenXml.VBA
    37 {
    38     /// <summary>
    39     /// A VBA reference
    40     /// </summary>
    41     public class ExcelVbaReference
    42     {
    43         /// <summary>
    44         /// Constructor.
    45         /// Defaults ReferenceRecordID to 0xD
    46         /// </summary>
    47         public ExcelVbaReference()
    48         {
    49             ReferenceRecordID = 0xD;
    50         }
    51         /// <summary>
    52         /// The reference record ID. See MS-OVBA documentation for more info.
    53         /// </summary>
    54         public int ReferenceRecordID { get; internal set; }
    55         /// <summary>
    56         /// The name of the reference
    57         /// </summary>
    58         public string Name { get; set; }
    59         /// <summary>
    60         /// LibID
    61         /// For more info check MS-OVBA 2.1.1.8 LibidReference and 2.3.4.2.2 PROJECTREFERENCES
    62         /// </summary>
    63         public string Libid { get; set; }
    64         /// <summary>
    65         /// A string representation of the object (the Name)
    66         /// </summary>
    67         /// <returns></returns>
    68         public override string ToString()
    69         {
    70             return Name;
    71         }
    72     }
    73     /// <summary>
    74     /// A reference to a twiddled type library
    75     /// </summary>
    76     public class ExcelVbaReferenceControl : ExcelVbaReference
    77     {
    78         /// <summary>
    79         /// Constructor.
    80         /// Sets ReferenceRecordID to 0x2F
    81         /// </summary>
    82         public ExcelVbaReferenceControl()
    83         {
    84             ReferenceRecordID = 0x2F;
    85         }
    86         /// <summary>
    87         /// LibIdExternal
    88         /// For more info check MS-OVBA 2.1.1.8 LibidReference and 2.3.4.2.2 PROJECTREFERENCES
    89         /// </summary>
    90         public string LibIdExternal { get; set; }
    91         /// <summary>
    92         /// LibIdTwiddled
    93         /// For more info check MS-OVBA 2.1.1.8 LibidReference and 2.3.4.2.2 PROJECTREFERENCES
    94         /// </summary>
    95         public string LibIdTwiddled { get; set; }
    96         /// <summary>
    97         /// A GUID that specifies the Automation type library the extended type library was generated from.
    98         /// </summary>
    99         public Guid OriginalTypeLib { get; set; }
    100         internal uint Cookie { get; set; }
    101     }
    102     /// <summary>
    103     /// A reference to an external VBA project
    104     /// </summary>
    105     public class ExcelVbaReferenceProject : ExcelVbaReference
    106     {
    107         /// <summary>
    108         /// Constructor.
    109         /// Sets ReferenceRecordID to 0x0E
    110         /// </summary>
    111         public ExcelVbaReferenceProject()
    112         {
    113             ReferenceRecordID = 0x0E;
    114         }
    115         /// <summary>
    116         /// LibIdRelative
    117         /// For more info check MS-OVBA 2.1.1.8 LibidReference and 2.3.4.2.2 PROJECTREFERENCES
    118         /// </summary>
    119         public string LibIdRelative { get; set; }
    120         /// <summary>
    121         /// Major version of the referenced VBA project
    122         /// </summary>
    123         public uint MajorVersion { get; set; }
    124         /// <summary>
    125         /// Minor version of the referenced VBA project
    126         /// </summary>
    127         public ushort MinorVersion { get; set; }
    128     }
    129 }
  • VBA/ExcelVBASignature.cs

     
    1 ï»¿/*******************************************************************************
    2  * You may amend and distribute as you like, but don't remove this header!
    3  *
    4  * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
    5  * See http://www.codeplex.com/EPPlus for details.
    6  *
    7  * Copyright (C) 2011  Jan KÀllman
    8  *
    9  * This library is free software; you can redistribute it and/or
    10  * modify it under the terms of the GNU Lesser General Public
    11  * License as published by the Free Software Foundation; either
    12  * version 2.1 of the License, or (at your option) any later version.
    13 
    14  * This library is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
    17  * See the GNU Lesser General Public License for more details.
    18  *
    19  * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
    20  * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
    21  *
    22  * All code and executables are provided "as is" with no warranty either express or implied.
    23  * The author accepts no liability for any damage or loss of business that this product may cause.
    24  *
    25  * Code change notes:
    26  *
    27  * Author             Change            Date
    28  *******************************************************************************
    29  * Jan KÀllman   Added   26-MAR-2012
    30  *******************************************************************************/
    31 using System;
    32 using System.Collections.Generic;
    33 using System.Linq;
    34 using System.Text;
    35 using System.Security.Cryptography.X509Certificates;
    36 using System.Security.Cryptography.Pkcs;
    37 using OfficeOpenXml.Utils;
    38 using System.IO;
    39 
    40 namespace OfficeOpenXml.VBA
    41 {
    42     /// <summary>
    43     /// The code signature properties of the project
    44     /// </summary>
    45     public class ExcelVbaSignature
    46     {
    47         const string schemaRelVbaSignature = "http://schemas.microsoft.com/office/2006/relationships/vbaProjectSignature";
    48         Packaging.ZipPackagePart _vbaPart = null;
    49         internal ExcelVbaSignature(Packaging.ZipPackagePart vbaPart)
    50         {
    51             _vbaPart = vbaPart;
    52             GetSignature();
    53         }
    54         private void GetSignature()
    55         {
    56             if (_vbaPart == null) return;
    57             var rel = _vbaPart.GetRelationshipsByType(schemaRelVbaSignature).FirstOrDefault();
    58             if (rel != null)
    59             {
    60                 Uri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
    61                 Part = _vbaPart.Package.GetPart(Uri);
    62 
    63                 var stream = Part.GetStream();
    64                 BinaryReader br = new BinaryReader(stream);
    65                 uint cbSignature = br.ReadUInt32();       
    66                 uint signatureOffset = br.ReadUInt32();     //44 ??
    67                 uint cbSigningCertStore = br.ReadUInt32(); 
    68                 uint certStoreOffset = br.ReadUInt32();     
    69                 uint cbProjectName = br.ReadUInt32();       
    70                 uint projectNameOffset = br.ReadUInt32();   
    71                 uint fTimestamp = br.ReadUInt32();
    72                 uint cbTimestampUrl = br.ReadUInt32();
    73                 uint timestampUrlOffset = br.ReadUInt32(); 
    74                 byte[] signature = br.ReadBytes((int)cbSignature);
    75                 uint version = br.ReadUInt32();
    76                 uint fileType = br.ReadUInt32();
    77 
    78                 uint id = br.ReadUInt32();
    79                 while (id != 0)
    80                 {
    81                     uint encodingType = br.ReadUInt32();
    82                     uint length = br.ReadUInt32();
    83                     if (length > 0)
    84                     {
    85                         byte[] value = br.ReadBytes((int)length);
    86                         switch (id)
    87                         {
    88                             //Add property values here...
    89                             case 0x20:
    90                                 Certificate = new X509Certificate2(value);
    91                                 break;
    92                             default:
    93                                 break;
    94                         }
    95                     }
    96                     id = br.ReadUInt32();
    97                 }
    98                 uint endel1 = br.ReadUInt32();  //0
    99                 uint endel2 = br.ReadUInt32();  //0
    100                 ushort rgchProjectNameBuffer = br.ReadUInt16();
    101                 ushort rgchTimestampBuffer = br.ReadUInt16();
    102                 Verifier = new SignedCms();
    103                 Verifier.Decode(signature);
    104             }
    105             else
    106             {
    107                 Certificate = null;
    108                 Verifier = null;
    109             }
    110         }
    111         //Create Oid from a bytearray
    112         //private string ReadHash(byte[] content)
    113         //{
    114         //    StringBuilder builder = new StringBuilder();
    115         //    int offset = 0x6;
    116         //    if (0 < (content.Length))
    117         //    {
    118         //        byte num = content[offset];
    119         //        byte num2 = (byte)(num / 40);
    120         //        builder.Append(num2.ToString(null, null));
    121         //        builder.Append(".");
    122         //        num2 = (byte)(num % 40);
    123         //        builder.Append(num2.ToString(null, null));
    124         //        ulong num3 = 0L;
    125         //        for (int i = offset + 1; i < content.Length; i++)
    126         //        {
    127         //            num2 = content[i];
    128         //            num3 = (ulong)(ulong)(num3 << 7) + ((byte)(num2 & 0x7f));
    129         //            if ((num2 & 0x80) == 0)
    130         //            {
    131         //                builder.Append(".");
    132         //                builder.Append(num3.ToString(null, null));
    133         //                num3 = 0L;
    134         //            }
    135         //            //1.2.840.113549.2.5
    136         //        }
    137         //    }
    138 
    139 
    140         //    string oId = builder.ToString();
    141 
    142         //    return oId;
    143         //}
    144         internal void Save(ExcelVbaProject proj)
    145         {
    146             if (Certificate == null)
    147             {
    148                 return;
    149             }
    150            
    151             if (Certificate.HasPrivateKey==false)    //No signature. Remove any Signature part
    152             {
    153                 var storeCert = GetCertFromStore(StoreLocation.CurrentUser);
    154                 if (storeCert == null)
    155                 {
    156                     storeCert = GetCertFromStore(StoreLocation.LocalMachine);
    157                 }
    158                 if (storeCert != null && storeCert.HasPrivateKey == true)
    159                 {
    160                     Certificate = storeCert;
    161                 }
    162                 else
    163                 {
    164                     foreach (var r in Part.GetRelationships())
    165                     {
    166                         Part.DeleteRelationship(r.Id);
    167                     }
    168                     Part.Package.DeletePart(Part.Uri);
    169                     return;
    170                 }
    171             }
    172             var ms = new MemoryStream();
    173             var bw = new BinaryWriter(ms);
    174 
    175             byte[] certStore = GetCertStore();
    176 
    177             byte[] cert = SignProject(proj);
    178             bw.Write((uint)cert.Length);
    179             bw.Write((uint)44);                  //?? 36 ref inside cert ??
    180             bw.Write((uint)certStore.Length);    //cbSigningCertStore
    181             bw.Write((uint)(cert.Length + 44));  //certStoreOffset
    182             bw.Write((uint)0);                   //cbProjectName
    183             bw.Write((uint)(cert.Length + certStore.Length + 44));    //projectNameOffset
    184             bw.Write((uint)0);    //fTimestamp
    185             bw.Write((uint)0);    //cbTimestampUrl
    186             bw.Write((uint)(cert.Length + certStore.Length + 44 + 2));    //timestampUrlOffset
    187             bw.Write(cert);
    188             bw.Write(certStore);
    189             bw.Write((ushort)0);//rgchProjectNameBuffer
    190             bw.Write((ushort)0);//rgchTimestampBuffer
    191             bw.Write((ushort)0);
    192             bw.Flush();
    193 
    194             var rel = proj.Part.GetRelationshipsByType(schemaRelVbaSignature).FirstOrDefault();
    195             if (Part == null)
    196             {
    197 
    198                 if (rel != null)
    199                 {
    200                     Uri = rel.TargetUri;
    201                     Part = proj._pck.GetPart(rel.TargetUri);
    202                 }
    203                 else
    204                 {
    205                     Uri = new Uri("/xl/vbaProjectSignature.bin", UriKind.Relative);
    206                     Part = proj._pck.CreatePart(Uri, ExcelPackage.schemaVBASignature);
    207                 }
    208             }
    209             if (rel == null)
    210             {
    211                 proj.Part.CreateRelationship(UriHelper.ResolvePartUri(proj.Uri, Uri), Packaging.TargetMode.Internal, schemaRelVbaSignature);               
    212             }
    213             var b = ms.ToArray();
    214             Part.GetStream(FileMode.Create).Write(b, 0, b.Length);           
    215         }
    216 
    217         private X509Certificate2 GetCertFromStore(StoreLocation loc)
    218         {
    219             try
    220             {
    221                 X509Store store = new X509Store(loc);
    222                 store.Open(OpenFlags.ReadOnly);
    223                 try
    224                 {
    225                     var storeCert = store.Certificates.Find(
    226                                     X509FindType.FindByThumbprint,
    227                                     Certificate.Thumbprint,
    228                                     true
    229                                     ).OfType<X509Certificate2>().FirstOrDefault();
    230                     return storeCert;
    231                 }
    232                 finally
    233                 {
    234                     store.Close();
    235                 }
    236             }
    237             catch
    238             {
    239                 return null;
    240             }
    241         }
    242 
    243         private byte[] GetCertStore()
    244         {
    245             var ms = new MemoryStream();
    246             var bw = new BinaryWriter(ms);
    247 
    248             bw.Write((uint)0); //Version
    249             bw.Write((uint)0x54524543); //fileType
    250 
    251             //SerializedCertificateEntry
    252             var certData = Certificate.RawData;
    253             bw.Write((uint)0x20);
    254             bw.Write((uint)1);
    255             bw.Write((uint)certData.Length);
    256             bw.Write(certData);
    257 
    258             //EndElementMarkerEntry
    259             bw.Write((uint)0);
    260             bw.Write((ulong)0);
    261 
    262             bw.Flush();
    263             return ms.ToArray();
    264         }
    265 
    266         private void WriteProp(BinaryWriter bw, int id, byte[] data)
    267         {
    268             bw.Write((uint)id);
    269             bw.Write((uint)1);
    270             bw.Write((uint)data.Length);
    271             bw.Write(data);
    272         }
    273         internal byte[] SignProject(ExcelVbaProject proj)
    274         {
    275             if (!Certificate.HasPrivateKey)
    276             {
    277                 //throw (new InvalidOperationException("The certificate doesn't have a private key"));
    278                 Certificate = null;
    279                 return null;
    280             }
    281             var hash = GetContentHash(proj);
    282 
    283             BinaryWriter bw = new BinaryWriter(new MemoryStream());
    284             bw.Write((byte)0x30); //Constructed Type
    285             bw.Write((byte)0x32); //Total length
    286             bw.Write((byte)0x30); //Constructed Type
    287             bw.Write((byte)0x0E); //Length SpcIndirectDataContent
    288             bw.Write((byte)0x06); //Oid Tag Indentifier
    289             bw.Write((byte)0x0A); //Lenght OId
    290             bw.Write(new byte[] { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x1D }); //Encoded Oid 1.3.6.1.4.1.311.2.1.29
    291             bw.Write((byte)0x04);   //Octet String Tag Identifier
    292             bw.Write((byte)0x00);   //Zero length
    293 
    294             bw.Write((byte)0x30); //Constructed Type (DigestInfo)
    295             bw.Write((byte)0x20); //Length DigestInfo
    296             bw.Write((byte)0x30); //Constructed Type (Algorithm)
    297             bw.Write((byte)0x0C); //length AlgorithmIdentifier
    298             bw.Write((byte)0x06); //Oid Tag Indentifier
    299             bw.Write((byte)0x08); //Lenght OId
    300             bw.Write(new byte[] { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05 }); //Encoded Oid for 1.2.840.113549.2.5 (AlgorithmIdentifier MD5)
    301             bw.Write((byte)0x05);   //Null type identifier
    302             bw.Write((byte)0x00);   //Null length
    303             bw.Write((byte)0x04);   //Octet String Identifier
    304             bw.Write((byte)hash.Length);   //Hash length
    305             bw.Write(hash);                //Content hash
    306 
    307             ContentInfo contentInfo = new ContentInfo(((MemoryStream)bw.BaseStream).ToArray());
    308             contentInfo.ContentType.Value = "1.3.6.1.4.1.311.2.1.4";
    309             Verifier = new SignedCms(contentInfo);
    310             var signer = new CmsSigner(Certificate);
    311             Verifier.ComputeSignature(signer, false);
    312             return Verifier.Encode();
    313         }
    314 
    315         private byte[] GetContentHash(ExcelVbaProject proj)
    316         {
    317             //MS-OVBA 2.4.2
    318             var enc = System.Text.Encoding.GetEncoding(proj.CodePage);
    319             BinaryWriter bw = new BinaryWriter(new MemoryStream());
    320             bw.Write(enc.GetBytes(proj.Name));
    321             bw.Write(enc.GetBytes(proj.Constants));
    322             foreach (var reference in proj.References)
    323             {
    324                 if (reference.ReferenceRecordID == 0x0D)
    325                 {
    326                     bw.Write((byte)0x7B);
    327                 }
    328                 if (reference.ReferenceRecordID == 0x0E)
    329                 {
    330                     //var r = (ExcelVbaReferenceProject)reference;
    331                     //BinaryWriter bwTemp = new BinaryWriter(new MemoryStream());
    332                     //bwTemp.Write((uint)r.Libid.Length);
    333                     //bwTemp.Write(enc.GetBytes(r.Libid));             
    334                     //bwTemp.Write((uint)r.LibIdRelative.Length);
    335                     //bwTemp.Write(enc.GetBytes(r.LibIdRelative));
    336                     //bwTemp.Write(r.MajorVersion);
    337                     //bwTemp.Write(r.MinorVersion);
    338                     foreach (byte b in BitConverter.GetBytes((uint)reference.Libid.Length))  //Length will never be an UInt with 4 bytes that aren't 0 (> 0x00FFFFFF), so no need for the rest of the properties.
    339                     {
    340                         if (b != 0)
    341                         {
    342                             bw.Write(b);
    343                         }
    344                         else
    345                         {
    346                             break;
    347                         }
    348                     }
    349                 }
    350             }
    351             foreach (var module in proj.Modules)
    352             {
    353                 var lines = module.Code.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
    354                 foreach (var line in lines)
    355                 {
    356                     if (!line.StartsWith("attribute", true, null))
    357                     {
    358                         bw.Write(enc.GetBytes(line));
    359                     }
    360                 }
    361             }
    362             var buffer = (bw.BaseStream as MemoryStream).ToArray();
    363             var hp = System.Security.Cryptography.MD5CryptoServiceProvider.Create();
    364             return hp.ComputeHash(buffer);
    365         }
    366         /// <summary>
    367         /// The certificate to sign the VBA project.
    368         /// <remarks>
    369         /// This certificate must have a private key.
    370         /// There is no validation that the certificate is valid for codesigning, so make sure it's valid to sign Excel files (Excel 2010 is more strict that prior versions).
    371         /// </remarks>
    372         /// </summary>
    373         public X509Certificate2 Certificate { get; set; }
    374         /// <summary>
    375         /// The verifier
    376         /// </summary>
    377         public SignedCms Verifier { get; internal set; }
    378 #if !MONO
    379         internal CompoundDocument Signature { get; set; }
    380 #endif
    381         internal Packaging.ZipPackagePart Part { get; set; }
    382         internal Uri Uri { get; private set; }
    383     }
    384 }
Note: See TracBrowser for help on using the repository browser.