30 private readonly
string filePath;
31 private readonly Stream inputStream;
33 private MemoryStream memoryStream;
52 readerOptions = options;
63 readerOptions = options;
79 using (memoryStream =
new MemoryStream())
81 ReadInternal().GetAwaiter().GetResult();
84 catch (NotSupportedContentException)
94 throw new IOException(
"There was an error while reading an XLSX file. Please see the inner exception:", ex);
109 using (memoryStream =
new MemoryStream())
111 await ReadInternal();
120 throw new IOException(
"There was an error while reading an XLSX file. Please see the inner exception:", ex);
128 private async Task ReadInternal()
131 if (inputStream ==
null && !
string.IsNullOrEmpty(filePath))
133 using (FileStream fs =
new FileStream(filePath, FileMode.Open))
135 await fs.CopyToAsync(memoryStream);
138 else if (inputStream !=
null)
142 await inputStream.CopyToAsync(memoryStream);
147 throw new IOException(
"No valid stream or file path was provided to open");
150 memoryStream.Position = 0;
151 zf =
new ZipArchive(memoryStream, ZipArchiveMode.Read);
156 }).ConfigureAwait(
false);
163 private void ReadZip(ZipArchive zf)
168 importInProgress =
true
170 HandleQueuePlugIns(PlugInUUID.ReaderPrependingQueue, zf, ref wb);
172 ISharedStringReader sharedStringsReader = PlugInLoader.GetPlugIn<ISharedStringReader>(PlugInUUID.SharedStringsReader,
new SharedStringsReader());
173 ms = GetEntryStream(
"xl/sharedStrings.xml", zf);
174 if (ms !=
null && ms.Length > 0)
176 sharedStringsReader.Init(ms, wb, readerOptions);
177 sharedStringsReader.Execute();
179 Dictionary<int, string> themeStreamNames = GetSequentialStreamNames(
"xl/theme/theme", zf);
180 if (themeStreamNames.Count > 0)
185 foreach (KeyValuePair<int, string> streamName
in themeStreamNames)
187 IPlugInReader themeReader = PlugInLoader.GetPlugIn<IPlugInReader>(PlugInUUID.ThemeReader,
new ThemeReader());
188 ms = GetEntryStream(streamName.Value, zf);
189 themeReader.Init(ms, wb, readerOptions);
190 themeReader.Execute();
194 StyleRepository.Instance.ImportInProgress =
true;
195 IPlugInReader styleReader = PlugInLoader.GetPlugIn<IPlugInReader>(PlugInUUID.StyleReader,
new StyleReader());
196 ms = GetEntryStream(
"xl/styles.xml", zf);
197 styleReader.Init(ms, wb, readerOptions);
198 styleReader.Execute();
199 StyleRepository.Instance.ImportInProgress =
false;
201 ms = GetEntryStream(
"xl/workbook.xml", zf);
202 IPlugInReader workbookReader = PlugInLoader.GetPlugIn<IPlugInReader>(PlugInUUID.WorkbookReader,
new WorkbookReader());
203 workbookReader.Init(ms, wb, readerOptions);
204 workbookReader.Execute();
206 ms = GetEntryStream(
"docProps/app.xml", zf);
207 if (ms !=
null && ms.Length > 0)
209 IPlugInReader metadataAppReader = PlugInLoader.GetPlugIn<IPlugInReader>(PlugInUUID.MetadataAppReader,
new MetadataAppReader());
210 metadataAppReader.Init(ms, wb, readerOptions);
211 metadataAppReader.Execute();
213 ms = GetEntryStream(
"docProps/core.xml", zf);
214 if (ms !=
null && ms.Length > 0)
216 IPlugInReader metadataCoreReader = PlugInLoader.GetPlugIn<IPlugInReader>(PlugInUUID.MetadataCoreReader,
new MetadataCoreReader());
217 metadataCoreReader.Init(ms, wb, readerOptions);
218 metadataCoreReader.Execute();
221 IPlugInReader relationships = PlugInLoader.GetPlugIn<IPlugInReader>(PlugInUUID.RelationshipReader,
new RelationshipReader());
222 ms = GetEntryStream(
"xl/_rels/workbook.xml.rels", zf);
223 relationships.Init(ms, wb, readerOptions);
224 relationships.Execute();
226 IWorksheetReader worksheetReader = PlugInLoader.GetPlugIn<IWorksheetReader>(PlugInUUID.WorksheetReader,
new WorksheetReader());
227 worksheetReader.SharedStrings = sharedStringsReader.SharedStrings;
228 List<WorksheetDefinition> workshetDefinitions = wb.AuxiliaryData.GetDataList<WorksheetDefinition>(PlugInUUID.WorkbookReader, PlugInUUID.WorksheetDefinitionEntity);
229 List<Relationship> relationshipDefinitions = wb.AuxiliaryData.GetDataList<Relationship>(PlugInUUID.RelationshipReader, PlugInUUID.RelationshipEntity);
230 foreach (WorksheetDefinition definition
in workshetDefinitions)
232 Relationship relationship = relationshipDefinitions.SingleOrDefault(r => r.RID == definition.RelId);
233 if (relationship ==
null)
235 throw new IOException(
"There was an error while reading an XLSX file. The relationship target of the worksheet with the RelID " + definition.RelId +
" was not found");
237 ms = GetEntryStream(relationship.Target, zf);
238 worksheetReader.Init(ms, wb, readerOptions);
239 worksheetReader.CurrentWorksheetID = definition.SheetID;
240 worksheetReader.Execute();
242 if (wb.Worksheets.Count == 0)
244 throw new IOException(
"No worksheet was found in the workbook");
246 HandleQueuePlugIns(PlugInUUID.ReaderAppendingQueue, zf, ref wb);
247 wb.importInProgress =
false;
248 wb.AuxiliaryData.ClearTemporaryData();
258 private static MemoryStream GetEntryStream(
string name, ZipArchive archive)
260 MemoryStream stream =
null;
261 for (
int i = 0; i < archive.Entries.Count; i++)
263 if (archive.Entries[i].FullName == name)
265 MemoryStream ms =
new MemoryStream();
266 archive.Entries[i].Open().CopyTo(ms);
281 private static Dictionary<int, string> GetSequentialStreamNames(
string namePrefix, ZipArchive archive)
283 Dictionary<int, string> files =
new Dictionary<int, string>();
287 string name = namePrefix + ParserUtils.ToString(index) +
".xml";
288 var ms = GetEntryStream(name, archive);
291 files.Add(index, name);
308 private void HandleQueuePlugIns(
string queueUuid, ZipArchive zf, ref
Workbook workbook)
310 string lastUuid =
null;
311 IPlugInReader queueReader;
315 queueReader = PlugInLoader.GetNextQueuePlugIn<IPlugInReader>(queueUuid, lastUuid, out currentUuid);
316 MemoryStream ms =
null;
317 if (queueReader !=
null)
319 if (queueReader is IPlugInPackageReader)
321 string streamPartName = (queueReader as IPlugInPackageReader).StreamEntryName;
322 if (!
string.IsNullOrEmpty(streamPartName))
324 ms = GetEntryStream(streamPartName, zf);
327 lastUuid = currentUuid;
332 queueReader.Init(ms, workbook, this.readerOptions);
333 queueReader.Execute();
334 lastUuid = currentUuid;
341 }
while (queueReader !=
null);
349 this.inputStream?.Dispose();
350 GC.SuppressFinalize(
this);