NanoXLSX.Reader 3.1.0
Loading...
Searching...
No Matches
Internal/Readers/WorkbookReader.cs
1/*
2 * NanoXLSX is a small .NET library to generate and read XLSX (Microsoft Excel 2007 or newer) files in an easy and native way
3 * Copyright Raphael Stoeckli © 2026
4 * This library is licensed under the MIT License.
5 * You find a copy of the license in project folder or on: http://opensource.org/licenses/MIT
6 */
7
8using System;
9using System.IO;
10using System.Xml;
11using NanoXLSX.Exceptions;
12using NanoXLSX.Interfaces;
13using NanoXLSX.Interfaces.Reader;
14using NanoXLSX.Registry;
15using NanoXLSX.Registry.Attributes;
16using NanoXLSX.Utils;
17using NanoXLSX.Utils.Xml;
18using static NanoXLSX.Enums.Password;
19using IOException = NanoXLSX.Exceptions.IOException;
20
22{
26 [NanoXlsxPlugIn(PlugInUUID = PlugInUUID.WorkbookReader)]
27 public partial class WorkbookReader : IPluginBaseReader
28 {
29 private Stream stream;
30 private IPasswordReader passwordReader;
31 // private ReaderOptions readerOptions;
32
33 #region properties
37 public Workbook Workbook { get; set; }
41 public IOptions Options { get; set; }
45 public Action<Stream, Workbook, string, IOptions, int?> InlinePluginHandler { get; set; }
46 #endregion
47
48 #region constructors
52 internal WorkbookReader()
53 {
54 }
55 #endregion
56
57 #region methods
65 public void Init(Stream stream, Workbook workbook, IOptions readerOptions, Action<Stream, Workbook, string, IOptions, int?> inlinePluginHandler)
66 {
67 this.stream = stream;
68 this.Workbook = workbook;
69 this.Options = readerOptions;
70 this.InlinePluginHandler = inlinePluginHandler;
71 this.passwordReader = PlugInLoader.GetPlugIn<IPasswordReader>(PlugInUUID.PasswordReader, new LegacyPasswordReader());
72 this.passwordReader.Init(PasswordType.WorkbookProtection, (ReaderOptions)readerOptions);
73 }
74
79 public void Execute()
80 {
81 try
82 {
83 using (stream) // Close after processing
84 {
85 using (XmlReader reader = XmlReader.Create(stream, XmlStreamUtils.CreateSettings()))
86 {
87 while (reader.Read())
88 {
89 if (reader.NodeType != XmlNodeType.Element)
90 {
91 continue;
92 }
93 if (XmlStreamUtils.IsElement(reader, "sheets"))
94 {
95 GetWorksheetInformation(reader);
96 }
97 else if (XmlStreamUtils.IsElement(reader, "bookViews"))
98 {
99 GetViewInformation(reader);
100 }
101 else if (XmlStreamUtils.IsElement(reader, "workbookProtection"))
102 {
103 GetProtectionInformation(reader);
104 }
105 }
106 InlinePluginHandler?.Invoke(stream, Workbook, PlugInUUID.WorkbookInlineReader, Options, null);
107 }
108 }
109 }
110 catch (NotSupportedContentException)
111 {
112 throw; // rethrow
113 }
114 catch (Exception ex)
115 {
116 throw new IOException("The XML entry could not be read from the input stream. Please see the inner exception:", ex);
117 }
118 }
119
126 private void GetProtectionInformation(XmlReader reader)
127 {
128 bool lockStructure = false;
129 bool lockWindows = false;
130 string attribute = reader.GetAttribute("lockWindows");
131 if (attribute != null)
132 {
133 lockWindows = ParserUtils.ParseBinaryBool(attribute) == 1;
134 }
135 attribute = reader.GetAttribute("lockStructure");
136 if (attribute != null)
137 {
138 lockStructure = ParserUtils.ParseBinaryBool(attribute) == 1;
139 }
140 Workbook.SetWorkbookProtection(true, lockWindows, lockStructure, null);
141 string outerXml;
142 using (XmlReader subtree = reader.ReadSubtree())
143 {
144 subtree.MoveToContent();
145 outerXml = subtree.ReadOuterXml();
146 }
147 XmlDocument miniDoc = new XmlDocument { XmlResolver = null };
148 miniDoc.LoadXml(outerXml);
149 passwordReader.ReadXmlAttributes(miniDoc.DocumentElement);
150 if (passwordReader.PasswordIsSet())
151 {
152 Workbook.WorkbookProtectionPassword.CopyFrom(passwordReader);
153 }
154 }
155
160 private void GetViewInformation(XmlReader reader)
161 {
162 using (XmlReader subtree = reader.ReadSubtree())
163 {
164 subtree.Read(); // consume the bookViews open tag
165 while (subtree.Read())
166 {
167 if (!XmlStreamUtils.IsElement(subtree, "workbookView"))
168 {
169 continue;
170 }
171 string attribute = subtree.GetAttribute("visibility");
172 if (attribute != null && ParserUtils.ToLower(attribute) == "hidden")
173 {
174 Workbook.Hidden = true;
175 }
176 attribute = subtree.GetAttribute("activeTab");
177 if (!string.IsNullOrEmpty(attribute))
178 {
179 Workbook.AuxiliaryData.SetData(PlugInUUID.WorkbookReader, PlugInUUID.SelectedWorksheetEntity, ParserUtils.ParseInt(attribute));
180 }
181 }
182 }
183 }
184
189 private void GetWorksheetInformation(XmlReader reader)
190 {
191 int visibleWorksheetOrder = 0;
192 using (XmlReader subtree = reader.ReadSubtree())
193 {
194 subtree.Read(); // consume the sheets open tag
195 while (subtree.Read())
196 {
197 if (!XmlStreamUtils.IsElement(subtree, "sheet"))
198 {
199 continue;
200 }
201 try
202 {
203 string sheetName = subtree.GetAttribute("name") ?? "worksheet1";
204 int id = ParserUtils.ParseInt(subtree.GetAttribute("sheetId")); // null will rightly throw
205 string relId = subtree.GetAttribute("r:id");
206 string state = subtree.GetAttribute("state");
207 bool hidden = state != null && ParserUtils.ToLower(state) == "hidden";
208 WorksheetDefinition definition = new WorksheetDefinition(id, sheetName, relId)
209 {
210 Hidden = hidden
211 };
212 Workbook.AuxiliaryData.SetData(PlugInUUID.WorkbookReader, PlugInUUID.WorksheetDefinitionEntity, visibleWorksheetOrder, definition);
213 visibleWorksheetOrder++;
214 }
215 catch (Exception e)
216 {
217 throw new IOException("The workbook information could not be resolved. Please see the inner exception:", e);
218 }
219 }
220 }
221 }
222 #endregion
223 }
224}
Class representing a reader for legacy passwords.
Class representing a reader to decompile a workbook in an XLSX files.
Workbook Workbook
Workbook reference where read data is stored (should not be null).
void Execute()
Method to execute the main logic of the plug-in (interface implementation).
void Init(Stream stream, Workbook workbook, IOptions readerOptions, Action< Stream, Workbook, string, IOptions, int?> inlinePluginHandler)
Initialization method (interface implementation).
Action< Stream, Workbook, string, IOptions, int?> InlinePluginHandler
Reference to the ReaderPlugInHandler, to be used for post operations in the Execute method.
Exceptions.IOException IOException