31 private MemoryStream stream;
32 private List<string> dateStyles;
33 private List<string> timeStyles;
34 private Dictionary<string, Style> resolvedStyles;
35 private IPasswordReader passwordReader;
80 public void Init(MemoryStream stream,
Workbook workbook, IOptions readerOptions, Action<MemoryStream, Workbook, string, IOptions, int?> inlinePluginHandler)
83 this.Workbook = workbook;
84 this.Options = readerOptions;
85 this.InlinePluginHandler = inlinePluginHandler;
87 if (dateStyles ==
null || timeStyles ==
null || this.resolvedStyles ==
null)
90 ProcessStyles(styleReaderContainer);
92 if (this.passwordReader ==
null)
94 this.passwordReader = PlugInLoader.GetPlugIn<IPasswordReader>(PlugInUUID.PasswordReader,
new LegacyPasswordReader());
95 this.passwordReader.Init(PasswordType.WorksheetProtection, (ReaderOptions)readerOptions);
107 WorksheetDefinition worksheetDefinition =
Workbook.AuxiliaryData.GetData<WorksheetDefinition>(PlugInUUID.WorkbookReader, PlugInUUID.WorksheetDefinitionEntity,
CurrentWorksheetID);
110 Hidden = worksheetDefinition.Hidden
114 ReaderOptions readerOptions = this.Options as ReaderOptions;
115 XmlDocument document =
new XmlDocument() { XmlResolver =
null };
116 using (XmlReader reader = XmlReader.Create(stream,
new XmlReaderSettings() { XmlResolver =
null }))
118 document.Load(reader);
119 GetRows(document, worksheet, readerOptions);
120 GetSheetView(document, worksheet);
121 GetMergedCells(document, worksheet);
122 GetSheetFormats(document, worksheet);
123 GetAutoFilters(document, worksheet);
124 GetColumns(document, worksheet, readerOptions);
125 GetSheetProtection(document, worksheet);
126 SetWorkbookRelation(worksheet);
131 catch (NotSupportedContentException)
137 throw new IOException(
"The XML entry could not be read from the input stream. Please see the inner exception:", ex);
145 private void SetWorkbookRelation(Worksheet worksheet)
148 int selectedWorksheetId =
Workbook.AuxiliaryData.GetData<
int>(PlugInUUID.WorkbookReader, PlugInUUID.SelectedWorksheetEntity);
151 Workbook.SetSelectedWorksheet(worksheet);
159 private void ProcessStyles(StyleReaderContainer styleReaderContainer)
161 this.dateStyles =
new List<string>();
162 this.timeStyles =
new List<string>();
163 this.resolvedStyles =
new Dictionary<string, Style>();
164 for (
int i = 0; i < styleReaderContainer.StyleCount; i++)
168 string index = ParserUtils.ToString(i);
169 Style style = styleReaderContainer.GetStyle(i, out isDate, out isTime);
172 this.dateStyles.Add(index);
176 this.timeStyles.Add(index);
178 this.resolvedStyles.Add(index, style);
188 private void GetRows(XmlDocument document, Worksheet worksheet, ReaderOptions readerOptions)
190 XmlNodeList rows = document.GetElementsByTagName(
"row");
191 foreach (XmlNode row
in rows)
193 string rowAttribute = ReaderUtils.GetAttribute(row,
"r");
194 if (rowAttribute !=
null)
196 int rowNumber = ParserUtils.ParseInt(rowAttribute) - 1;
197 string hiddenAttribute = ReaderUtils.GetAttribute(row,
"hidden");
198 if (hiddenAttribute !=
null)
200 int value = ParserUtils.ParseBinaryBool(hiddenAttribute);
203 worksheet.AddHiddenRow(rowNumber);
206 string heightAttribute = ReaderUtils.GetAttribute(row,
"ht");
207 if (heightAttribute !=
null)
209 worksheet.RowHeights.Add(rowNumber, GetValidatedHeight(ParserUtils.ParseFloat(heightAttribute), readerOptions));
212 if (row.HasChildNodes)
214 foreach (XmlNode rowChild
in row.ChildNodes)
216 ReadCell(rowChild, worksheet);
227 private static void GetSheetView(XmlDocument xmlDocument, Worksheet worksheet)
229 XmlNodeList sheetViewsNodes = xmlDocument.GetElementsByTagName(
"sheetViews");
230 if (sheetViewsNodes !=
null && sheetViewsNodes.Count > 0)
232 XmlNodeList sheetViewNodes = sheetViewsNodes[0].ChildNodes;
235 foreach (XmlNode sheetView
in sheetViewNodes)
237 attribute = ReaderUtils.GetAttribute(sheetView,
"view",
string.Empty);
238 worksheet.ViewType = Worksheet.GetSheetViewTypeEnum(attribute);
239 attribute = ReaderUtils.GetAttribute(sheetView,
"zoomScale");
240 if (attribute !=
null)
242 worksheet.ZoomFactor = ParserUtils.ParseInt(attribute);
244 attribute = ReaderUtils.GetAttribute(sheetView,
"zoomScaleNormal");
245 if (attribute !=
null)
247 int scale = ParserUtils.ParseInt(attribute);
248 worksheet.ZoomFactors[Worksheet.SheetViewType.Normal] = scale;
250 attribute = ReaderUtils.GetAttribute(sheetView,
"zoomScalePageLayoutView");
251 if (attribute !=
null)
253 int scale = ParserUtils.ParseInt(attribute);
254 worksheet.ZoomFactors[Worksheet.SheetViewType.PageLayout] = scale;
256 attribute = ReaderUtils.GetAttribute(sheetView,
"zoomScaleSheetLayoutView");
257 if (attribute !=
null)
259 int scale = ParserUtils.ParseInt(attribute);
260 worksheet.ZoomFactors[Worksheet.SheetViewType.PageBreakPreview] = scale;
262 attribute = ReaderUtils.GetAttribute(sheetView,
"showGridLines");
263 if (attribute !=
null)
265 worksheet.ShowGridLines = ParserUtils.ParseBinaryBool(attribute) == 1;
267 attribute = ReaderUtils.GetAttribute(sheetView,
"showRowColHeaders");
268 if (attribute !=
null)
270 worksheet.ShowRowColumnHeaders = ParserUtils.ParseBinaryBool(attribute) == 1;
272 attribute = ReaderUtils.GetAttribute(sheetView,
"showRuler");
273 if (attribute !=
null)
275 worksheet.ShowRuler = ParserUtils.ParseBinaryBool(attribute) == 1;
277 if (sheetView.LocalName.Equals(
"sheetView", StringComparison.OrdinalIgnoreCase))
279 XmlNodeList selectionNodes = sheetView.ChildNodes;
280 if (selectionNodes !=
null && selectionNodes.Count > 0)
282 foreach (XmlNode selectionNode
in selectionNodes)
284 attribute = ReaderUtils.GetAttribute(selectionNode,
"sqref");
285 if (attribute !=
null)
287 if (attribute.Contains(
" "))
290 string[] ranges = attribute.Split(
' ');
291 foreach (
string range
in ranges)
293 CollectSelectedCells(range, worksheet);
298 CollectSelectedCells(attribute, worksheet);
304 XmlNode paneNode = ReaderUtils.GetChildNode(sheetView,
"pane");
305 if (paneNode !=
null)
307 SetPaneSplit(paneNode, worksheet);
319 private static void CollectSelectedCells(
string attribute, Worksheet worksheet)
321 if (attribute.Contains(
":"))
324 worksheet.AddSelectedCells(
new Range(attribute));
329 worksheet.AddSelectedCells(
new Range(attribute +
":" + attribute));
338 private static void SetPaneSplit(XmlNode paneNode, Worksheet worksheet)
340 string attribute = ReaderUtils.GetAttribute(paneNode,
"state");
341 bool useNumbers =
false;
342 bool frozenState =
false;
343 bool ySplitDefined =
false;
344 bool xSplitDefined =
false;
345 int? paneSplitRowIndex =
null;
346 int? paneSplitColumnIndex =
null;
347 float? paneSplitHeight =
null;
348 float? paneSplitWidth =
null;
349 Address topLeftCell =
new Address(0, 0);
350 Worksheet.WorksheetPane? activePane =
null;
351 if (attribute !=
null)
353 if (ParserUtils.ToLower(attribute) ==
"frozen" || ParserUtils.ToLower(attribute) ==
"frozensplit")
357 useNumbers = frozenState;
359 attribute = ReaderUtils.GetAttribute(paneNode,
"ySplit");
360 if (attribute !=
null)
362 ySplitDefined =
true;
365 paneSplitRowIndex = ParserUtils.ParseInt(attribute);
369 paneSplitHeight = DataUtils.GetPaneSplitHeight(ParserUtils.ParseFloat(attribute));
372 attribute = ReaderUtils.GetAttribute(paneNode,
"xSplit");
373 if (attribute !=
null)
375 xSplitDefined =
true;
378 paneSplitColumnIndex = ParserUtils.ParseInt(attribute);
382 paneSplitWidth = DataUtils.GetPaneSplitWidth(ParserUtils.ParseFloat(attribute));
385 attribute = ReaderUtils.GetAttribute(paneNode,
"topLeftCell");
386 if (attribute !=
null)
388 topLeftCell =
new Address(attribute);
390 attribute = ReaderUtils.GetAttribute(paneNode,
"activePane",
string.Empty);
391 activePane = Worksheet.GetWorksheetPaneEnum(attribute);
394 if (ySplitDefined && !xSplitDefined)
396 worksheet.SetHorizontalSplit(paneSplitRowIndex.Value, frozenState, topLeftCell, activePane);
398 if (!ySplitDefined && xSplitDefined)
400 worksheet.SetVerticalSplit(paneSplitColumnIndex.Value, frozenState, topLeftCell, activePane);
402 else if (ySplitDefined && xSplitDefined)
404 worksheet.SetSplit(paneSplitColumnIndex.Value, paneSplitRowIndex.Value, frozenState, topLeftCell, activePane);
409 if (ySplitDefined && !xSplitDefined)
411 worksheet.SetHorizontalSplit(paneSplitHeight.Value, topLeftCell, activePane);
413 if (!ySplitDefined && xSplitDefined)
415 worksheet.SetVerticalSplit(paneSplitWidth.Value, topLeftCell, activePane);
417 else if (ySplitDefined && xSplitDefined)
419 worksheet.SetSplit(paneSplitWidth, paneSplitHeight, topLeftCell, activePane);
429 private void GetSheetProtection(XmlDocument xmlDocument, Worksheet worksheet)
431 ReaderOptions readerOptions = this.Options as ReaderOptions;
432 XmlNodeList sheetProtectionNodes = xmlDocument.GetElementsByTagName(
"sheetProtection");
433 if (sheetProtectionNodes !=
null && sheetProtectionNodes.Count > 0)
435 int hasProtection = 0;
436 XmlNode sheetProtectionNode = sheetProtectionNodes[0];
437 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.AutoFilter, worksheet);
438 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.DeleteColumns, worksheet);
439 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.DeleteRows, worksheet);
440 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.FormatCells, worksheet);
441 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.FormatColumns, worksheet);
442 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.FormatRows, worksheet);
443 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.InsertColumns, worksheet);
444 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.InsertHyperlinks, worksheet);
445 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.InsertRows, worksheet);
446 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.Objects, worksheet);
447 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.PivotTables, worksheet);
448 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.Scenarios, worksheet);
449 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.SelectLockedCells, worksheet);
450 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.SelectUnlockedCells, worksheet);
451 hasProtection += ManageSheetProtection(sheetProtectionNode, Worksheet.SheetProtectionValue.Sort, worksheet);
452 if (hasProtection > 0)
454 worksheet.UseSheetProtection =
true;
456 this.passwordReader.ReadXmlAttributes(sheetProtectionNode);
457 if (this.passwordReader.PasswordIsSet())
459 if (this.passwordReader is LegacyPasswordReader && (this.passwordReader as LegacyPasswordReader).ContemporaryAlgorithmDetected && (readerOptions ==
null || !readerOptions.IgnoreNotSupportedPasswordAlgorithms))
461 throw new NotSupportedContentException(
"A not supported, contemporary password algorithm for the worksheet protection was detected. Check possible packages to add support to NanoXLSX, or ignore this error by a reader option");
463 worksheet.SheetProtectionPassword.CopyFrom(this.passwordReader);
474 private static int ManageSheetProtection(XmlNode node, Worksheet.SheetProtectionValue sheetProtectionValue, Worksheet worksheet)
476 int hasProtection = 0;
477 string attributeName = Worksheet.GetSheetProtectionName(sheetProtectionValue);
478 string attribute = ReaderUtils.GetAttribute(node, attributeName);
479 if (attribute !=
null)
482 worksheet.SheetProtectionValues.Add(sheetProtectionValue);
484 return hasProtection;
492 private static void GetMergedCells(XmlDocument xmlDocument, Worksheet worksheet)
494 XmlNodeList mergedCellsNodes = xmlDocument.GetElementsByTagName(
"mergeCells");
495 if (mergedCellsNodes !=
null && mergedCellsNodes.Count > 0)
497 XmlNodeList mergedCellNodes = mergedCellsNodes[0].ChildNodes;
498 if (mergedCellNodes !=
null && mergedCellNodes.Count > 0)
500 foreach (XmlNode mergedCells
in mergedCellNodes)
502 string attribute = ReaderUtils.GetAttribute(mergedCells,
"ref");
503 if (attribute !=
null)
505 worksheet.MergeCells(
new Range(attribute));
517 private static void GetSheetFormats(XmlDocument xmlDocument, Worksheet worksheet)
519 XmlNodeList formatNodes = xmlDocument.GetElementsByTagName(
"sheetFormatPr");
520 if (formatNodes !=
null && formatNodes.Count > 0)
522 string attribute = ReaderUtils.GetAttribute(formatNodes[0],
"defaultColWidth");
523 if (attribute !=
null)
525 worksheet.DefaultColumnWidth = ParserUtils.ParseFloat(attribute);
527 attribute = ReaderUtils.GetAttribute(formatNodes[0],
"defaultRowHeight");
528 if (attribute !=
null)
530 worksheet.DefaultRowHeight = ParserUtils.ParseFloat(attribute);
540 private static void GetAutoFilters(XmlDocument xmlDocument, Worksheet worksheet)
542 XmlNodeList autoFilterNodes = xmlDocument.GetElementsByTagName(
"autoFilter");
543 if (autoFilterNodes !=
null && autoFilterNodes.Count > 0)
545 string autoFilterRef = ReaderUtils.GetAttribute(autoFilterNodes[0],
"ref");
546 if (autoFilterRef !=
null)
548 Range range =
new Range(autoFilterRef);
549 worksheet.SetAutoFilter(range.StartAddress.Column, range.EndAddress.Column);
560 private void GetColumns(XmlDocument xmlDocument, Worksheet worksheet, ReaderOptions readerOptions)
562 XmlNodeList columnNodes = xmlDocument.GetElementsByTagName(
"col");
563 foreach (XmlNode columnNode
in columnNodes)
567 List<int> indices =
new List<int>();
568 string attribute = ReaderUtils.GetAttribute(columnNode,
"min");
569 if (attribute !=
null)
571 min = ParserUtils.ParseInt(attribute);
573 indices.Add(min.Value);
575 attribute = ReaderUtils.GetAttribute(columnNode,
"max");
576 if (attribute !=
null)
578 max = ParserUtils.ParseInt(attribute);
580 if (min !=
null && max.Value != min.Value)
582 for (
int i = min.Value; i <= max.Value; i++)
587 attribute = ReaderUtils.GetAttribute(columnNode,
"width");
588 float width = Worksheet.DefaultWorksheetColumnWidth;
589 if (attribute !=
null)
591 width = ParserUtils.ParseFloat(attribute);
593 attribute = ReaderUtils.GetAttribute(columnNode,
"hidden");
595 if (attribute !=
null)
597 int value = ParserUtils.ParseBinaryBool(attribute);
603 attribute = ReaderUtils.GetAttribute(columnNode,
"style");
604 Style defaultStyle =
null;
605 if (attribute !=
null && resolvedStyles.TryGetValue(attribute, out var attributeValue))
607 defaultStyle = attributeValue;
609 foreach (
int index
in indices)
611 string columnAddress = Cell.ResolveColumnAddress(index - 1);
612 if (defaultStyle !=
null)
614 worksheet.SetColumnDefaultStyle(columnAddress, defaultStyle);
617 if (width != Worksheet.DefaultWorksheetColumnWidth)
619 worksheet.SetColumnWidth(columnAddress, GetValidatedWidth(width, readerOptions));
623 worksheet.AddHiddenColumn(columnAddress);
634 private void ReadCell(XmlNode rowChild, Worksheet worksheet)
637 string styleNumber =
"";
638 string address =
"A1";
640 if (rowChild.LocalName.Equals(
"c", StringComparison.OrdinalIgnoreCase))
642 address = ReaderUtils.GetAttribute(rowChild,
"r");
643 type = ReaderUtils.GetAttribute(rowChild,
"t");
644 styleNumber = ReaderUtils.GetAttribute(rowChild,
"s");
645 if (rowChild.HasChildNodes)
647 foreach (XmlNode valueNode
in rowChild.ChildNodes)
649 if (valueNode.LocalName.Equals(
"v", StringComparison.OrdinalIgnoreCase))
651 value = valueNode.InnerText;
653 if (valueNode.LocalName.Equals(
"f", StringComparison.OrdinalIgnoreCase))
655 value = valueNode.InnerText;
657 if (valueNode.LocalName.Equals(
"is", StringComparison.OrdinalIgnoreCase))
659 value = valueNode.InnerText;
664 string key = ParserUtils.ToUpper(address);
665 Cell cell = ResolveCellData(value, type, styleNumber, address);
666 worksheet.AddCell(cell, address);
667 if (styleNumber !=
null)
670 this.resolvedStyles.TryGetValue(styleNumber, out style);
673 worksheet.Cells[address].SetStyle(style);
686 private Cell ResolveCellData(
string raw,
string type,
string styleNumber,
string address)
688 ReaderOptions readerOptions = this.Options as ReaderOptions;
689 Cell.CellType importedType = Cell.CellType.Default;
693 rawValue = TryParseBool(raw);
694 if (rawValue !=
null)
696 importedType = Cell.CellType.Bool;
700 rawValue = GetNumericValue(raw);
701 if (rawValue !=
null)
703 importedType = Cell.CellType.Number;
707 else if (type ==
"s")
709 importedType = Cell.CellType.String;
710 rawValue = ResolveSharedString(raw);
712 else if (type ==
"str")
714 importedType = Cell.CellType.Formula;
717 else if (type ==
"inlineStr")
719 importedType = Cell.CellType.String;
722 else if (dateStyles.Contains(styleNumber) && (type ==
null || type ==
"" || type ==
"n"))
724 rawValue = GetDateTimeValue(raw, Cell.CellType.Date, out importedType);
726 else if (timeStyles.Contains(styleNumber) && (type ==
null || type ==
"" || type ==
"n"))
728 rawValue = GetDateTimeValue(raw, Cell.CellType.Time, out importedType);
732 importedType = Cell.CellType.Number;
733 rawValue = GetNumericValue(raw);
735 if (rawValue ==
null && raw ==
"")
737 importedType = Cell.CellType.Empty;
740 else if (rawValue ==
null && raw.Length > 0)
742 importedType = Cell.CellType.String;
745 Address cellAddress =
new Address(address);
746 if (readerOptions !=
null)
748 if (readerOptions.EnforcedColumnTypes.Count > 0)
750 rawValue = GetEnforcedColumnValue(rawValue, importedType, cellAddress);
752 rawValue = GetGloballyEnforcedValue(rawValue, cellAddress);
753 rawValue = GetGloballyEnforcedFlagValues(rawValue, cellAddress);
754 importedType = ResolveType(rawValue, importedType);
755 if (importedType == Cell.CellType.Date && rawValue is DateTime && (DateTime)rawValue < DataUtils.FirstAllowedExcelDate)
758 rawValue = ((DateTime)rawValue).AddDays(1);
761 return CreateCell(rawValue, importedType, cellAddress, styleNumber);
770 private static Cell.CellType ResolveType(
object value, Cell.CellType defaultType)
772 if (defaultType == Cell.CellType.Formula)
778 return Cell.CellType.Empty;
792 return Cell.CellType.Number;
794 return Cell.CellType.Date;
796 return Cell.CellType.Time;
798 return Cell.CellType.Bool;
800 return Cell.CellType.String;
810 private object GetGloballyEnforcedFlagValues(
object data, Address address)
812 ReaderOptions readerOptions = this.Options as ReaderOptions;
813 if (address.Row < readerOptions.EnforcingStartRowNumber)
817 if (readerOptions.EnforceDateTimesAsNumbers)
819 if (data is DateTime)
821 data = DataUtils.GetOADateTime((DateTime)data,
true);
823 else if (data is TimeSpan)
825 data = DataUtils.GetOATime((TimeSpan)data);
828 if (readerOptions.EnforceEmptyValuesAsString && data ==
null)
841 private object GetGloballyEnforcedValue(
object data, Address address)
843 ReaderOptions readerOptions = this.Options as ReaderOptions;
844 if (address.Row < readerOptions.EnforcingStartRowNumber)
848 if (readerOptions.GlobalEnforcingType == ReaderOptions.GlobalType.AllNumbersToDouble)
850 object tempDouble = ConvertToDouble(data, readerOptions);
851 if (tempDouble !=
null)
856 else if (readerOptions.GlobalEnforcingType == ReaderOptions.GlobalType.AllNumbersToDecimal)
858 object tempDecimal = ConvertToDecimal(data, readerOptions);
859 if (tempDecimal !=
null)
864 else if (readerOptions.GlobalEnforcingType == ReaderOptions.GlobalType.AllNumbersToInt)
866 object tempInt = ConvertToInt(data);
872 else if (readerOptions.GlobalEnforcingType == ReaderOptions.GlobalType.EverythingToString)
874 return ConvertToString(data, readerOptions);
886 private object GetEnforcedColumnValue(
object data, Cell.CellType importedTyp, Address address)
888 ReaderOptions readerOptions = this.Options as ReaderOptions;
889 if (address.Row < readerOptions.EnforcingStartRowNumber)
893 if (!readerOptions.EnforcedColumnTypes.TryGetValue(address.Column, out var columnType))
897 if (importedTyp == Cell.CellType.Formula)
903 case ReaderOptions.ColumnType.Numeric:
904 return GetNumericValue(data, importedTyp, readerOptions);
905 case ReaderOptions.ColumnType.Decimal:
906 return ConvertToDecimal(data, readerOptions);
907 case ReaderOptions.ColumnType.Double:
908 return ConvertToDouble(data, readerOptions);
909 case ReaderOptions.ColumnType.Date:
910 return ConvertToDate(data, readerOptions);
911 case ReaderOptions.ColumnType.Time:
912 return ConvertToTime(data, readerOptions);
913 case ReaderOptions.ColumnType.Bool:
914 return ConvertToBool(data, readerOptions);
916 return ConvertToString(data, readerOptions);
926 private object ConvertToBool(
object data, ReaderOptions readerOptions)
941 object tempObject = ConvertToDouble(data, readerOptions);
942 if (tempObject is
double)
944 double tempDouble = (double)tempObject;
945 if (
double.Equals(tempDouble, 0d))
949 else if (
double.Equals(tempDouble, 1d))
957 string tempString = (string)data;
958 bool? tempBool = TryParseBool(tempString);
959 if (tempBool !=
null)
961 return tempBool.Value;
973 private static bool? TryParseBool(
string raw)
986 if (
bool.TryParse(raw, out value))
1003 private object ConvertToDouble(
object data, ReaderOptions readerOptions)
1005 object value = ConvertToDecimal(data, readerOptions);
1006 if (value is decimal)
1008 return Decimal.ToDouble((decimal)value);
1010 else if (value is
float)
1012 return Convert.ToDouble((
float)value);
1023 private object ConvertToDecimal(
object data, ReaderOptions readerOptions)
1025 IConvertible converter;
1039 converter = data as IConvertible;
1040 double tempDouble = converter.ToDouble(DataUtils.InvariantCulture);
1041 if (tempDouble > (
double)decimal.MaxValue || tempDouble < (
double)decimal.MinValue)
1047 return converter.ToDecimal(DataUtils.InvariantCulture);
1056 return decimal.Zero;
1059 return new decimal(DataUtils.GetOADateTime((DateTime)data));
1061 return new decimal(DataUtils.GetOATime((TimeSpan)data));
1064 string tempString = (string)data;
1065 if (ParserUtils.TryParseDecimal(tempString, out dValue))
1069 DateTime? tempDate = TryParseDate(tempString, readerOptions);
1070 if (tempDate !=
null)
1072 return new decimal(DataUtils.GetOADateTime(tempDate.Value));
1074 TimeSpan? tempTime = TryParseTime(tempString, readerOptions);
1075 if (tempTime !=
null)
1077 return new decimal(DataUtils.GetOATime(tempTime.Value));
1089 private static object ConvertToInt(
object data)
1099 tempDouble = DataUtils.GetOADateTime((DateTime)data,
true);
1100 return ConvertDoubleToInt(tempDouble);
1102 tempDouble = DataUtils.GetOATime((TimeSpan)data);
1103 return ConvertDoubleToInt(tempDouble);
1106 int? tempInt = TryConvertDoubleToInt(data);
1107 if (tempInt !=
null)
1113 return (
bool)data ? 1 : 0;
1116 if (ParserUtils.TryParseInt((
string)data, out tempInt2))
1131 private object ConvertToDate(
object data, ReaderOptions readerOptions)
1138 DateTime root = DataUtils.FirstAllowedExcelDate;
1139 TimeSpan time = (TimeSpan)data;
1140 root = root.AddDays(-1);
1141 root = root.AddHours(time.Hours);
1142 root = root.AddMinutes(time.Minutes);
1143 root = root.AddSeconds(time.Seconds);
1155 return ConvertDateFromDouble(data, readerOptions);
1157 DateTime? date2 = TryParseDate((
string)data, readerOptions);
1162 return ConvertDateFromDouble(data, readerOptions);
1173 private DateTime? TryParseDate(
string raw, ReaderOptions readerOptions)
1177 if (readerOptions ==
null ||
string.IsNullOrEmpty(readerOptions.DateTimeFormat) || readerOptions.TemporalCultureInfo ==
null)
1179 isDateTime = DateTime.TryParse(raw, ReaderOptions.DefaultCultureInfo, DateTimeStyles.None, out dateTime);
1183 isDateTime = DateTime.TryParseExact(raw, readerOptions.DateTimeFormat, readerOptions.TemporalCultureInfo, DateTimeStyles.None, out dateTime);
1185 if (isDateTime && dateTime >= DataUtils.FirstAllowedExcelDate && dateTime <= DataUtils.LastAllowedExcelDate)
1198 private object ConvertToTime(
object data, ReaderOptions readerOptions)
1203 return ConvertTimeFromDouble(data, readerOptions);
1216 return ConvertTimeFromDouble(data, readerOptions);
1218 TimeSpan? time = TryParseTime((
string)data, readerOptions);
1223 return ConvertTimeFromDouble(data, readerOptions);
1234 private TimeSpan? TryParseTime(
string raw, ReaderOptions readerOptions)
1238 if (readerOptions ==
null ||
string.IsNullOrEmpty(readerOptions.TimeSpanFormat) || readerOptions.TemporalCultureInfo ==
null)
1240 isTimeSpan = TimeSpan.TryParse(raw, ReaderOptions.DefaultCultureInfo, out timeSpan);
1244 isTimeSpan = TimeSpan.TryParseExact(raw, readerOptions.TimeSpanFormat, readerOptions.TemporalCultureInfo, out timeSpan);
1246 if (isTimeSpan && timeSpan.Days >= 0 && timeSpan.Days < DataUtils.MaxOADateValue)
1261 private static object GetDateTimeValue(
string raw, Cell.CellType valueType, out Cell.CellType resolvedType)
1264 if (!ParserUtils.TryParseDouble(raw, out dValue))
1266 resolvedType = Cell.CellType.String;
1269 if ((valueType == Cell.CellType.Date && (dValue < DataUtils.MinOADateValue || dValue > DataUtils.MaxOADateValue)) || (valueType == Cell.CellType.Time && (dValue < 0.0 || dValue > DataUtils.MaxOADateValue)))
1272 resolvedType = Cell.CellType.Number;
1273 return GetNumericValue(raw);
1275 DateTime tempDate = DataUtils.GetDateFromOA(dValue);
1278 tempDate = tempDate.AddDays(1);
1280 if (valueType == Cell.CellType.Date)
1282 resolvedType = Cell.CellType.Date;
1287 resolvedType = Cell.CellType.Time;
1288 return new TimeSpan((
int)dValue, tempDate.Hour, tempDate.Minute, tempDate.Second);
1298 private object ConvertDateFromDouble(
object data, ReaderOptions readerOptions)
1300 object oaDate = ConvertToDouble(data, readerOptions);
1301 if (oaDate is
double && (
double)oaDate < DataUtils.MaxOADateValue)
1303 DateTime date = DataUtils.GetDateFromOA((
double)oaDate);
1304 if (date >= DataUtils.FirstAllowedExcelDate && date <= DataUtils.LastAllowedExcelDate)
1318 private object ConvertTimeFromDouble(
object data, ReaderOptions readerOptions)
1320 object oaDate = ConvertToDouble(data, readerOptions);
1321 if (oaDate is
double)
1323 double d = (double)oaDate;
1324 if (d >= DataUtils.MinOADateValue && d <= DataUtils.MaxOADateValue)
1326 DateTime date = DataUtils.GetDateFromOA(d);
1327 return new TimeSpan((
int)d, date.Hour, date.Minute, date.Second);
1338 private static int? TryConvertDoubleToInt(
object data)
1340 IConvertible converter = data as IConvertible;
1341 double dValue = converter.ToDouble(ReaderOptions.DefaultCultureInfo);
1342 if (dValue >
int.MinValue && dValue <
int.MaxValue)
1344 return converter.ToInt32(ReaderOptions.DefaultCultureInfo);
1354 private static int ConvertDoubleToInt(
object data)
1356 IConvertible converter = data as IConvertible;
1357 return converter.ToInt32(ReaderOptions.DefaultCultureInfo);
1366 private string ConvertToString(
object data, ReaderOptions readerOptions)
1371 return ((
int)data).ToString(ReaderOptions.DefaultCultureInfo);
1373 return ((uint)data).ToString(ReaderOptions.DefaultCultureInfo);
1375 return ((
long)data).ToString(ReaderOptions.DefaultCultureInfo);
1377 return ((ulong)data).ToString(ReaderOptions.DefaultCultureInfo);
1379 return ((
float)data).ToString(ReaderOptions.DefaultCultureInfo);
1381 return ((
double)data).ToString(ReaderOptions.DefaultCultureInfo);
1383 return ((
bool)data).ToString(ReaderOptions.DefaultCultureInfo);
1385 return ((DateTime)data).ToString(readerOptions.DateTimeFormat, ParserUtils.InvariantCulture);
1387 return ((TimeSpan)data).ToString(readerOptions.TimeSpanFormat, ParserUtils.InvariantCulture);
1393 return data.ToString();
1404 private object GetNumericValue(
object raw, Cell.CellType importedType, ReaderOptions readerOptions)
1411 switch (importedType)
1413 case Cell.CellType.String:
1414 string tempString = raw.ToString();
1415 tempObject = GetNumericValue(tempString);
1416 if (tempObject !=
null)
1420 DateTime? tempDate = TryParseDate(tempString, readerOptions);
1421 if (tempDate !=
null)
1423 return DataUtils.GetOADateTime(tempDate.Value);
1425 TimeSpan? tempTime = TryParseTime(tempString, readerOptions);
1426 if (tempTime !=
null)
1428 return DataUtils.GetOATime(tempTime.Value);
1430 tempObject = ConvertToBool(raw, readerOptions);
1431 if (tempObject is
bool)
1433 return (
bool)tempObject ? 1 : 0;
1436 case Cell.CellType.Number:
1438 case Cell.CellType.Date:
1439 return DataUtils.GetOADateTime((DateTime)raw);
1440 case Cell.CellType.Time:
1441 return DataUtils.GetOATime((TimeSpan)raw);
1442 case Cell.CellType.Bool:
1458 private static object GetNumericValue(
string raw)
1460 bool hasDecimalPoint = raw.Contains(
".");
1463 if (!hasDecimalPoint)
1468 bool canBeUint = ParserUtils.TryParseUint(raw, out uiValue);
1469 bool canBeInt = ParserUtils.TryParseInt(raw, out iValue);
1470 if (canBeUint && !canBeInt)
1480 bool canBeUlong = ParserUtils.TryParseUlong(raw, out ulValue);
1481 bool canBeLong = ParserUtils.TryParseLong(raw, out lValue);
1482 if (canBeUlong && !canBeLong)
1497 if (ParserUtils.TryParseDecimal(raw, out dcValue))
1500 float testFloat = decimal.ToSingle(dcValue);
1501 decimal backToDecimal = (decimal)testFloat;
1504 if (dcValue == backToDecimal)
1511 return decimal.ToDouble(dcValue);
1515 else if (ParserUtils.TryParseFloat(raw, out fValue) && fValue >=
float.MinValue && fValue <=
float.MaxValue && !
float.IsInfinity(fValue))
1519 if (ParserUtils.TryParseDouble(raw, out dValue))
1533 private float GetValidatedWidth(
float rawValue, ReaderOptions readerOptions)
1535 if (rawValue < Worksheet.MinColumnWidth)
1537 if (readerOptions.EnforceStrictValidation)
1539 throw new WorksheetException($
"The worksheet contains an invalid column width (too small: {rawValue}) value. This error is ignored when disabling the reader option 'EnforceStrictValidation'");
1543 return Worksheet.MinColumnWidth;
1546 else if (rawValue > Worksheet.MaxColumnWidth)
1548 if (readerOptions.EnforceStrictValidation)
1550 throw new WorksheetException($
"The worksheet contains an invalid column width (too large: {rawValue}) value. This error is ignored when disabling the reader option 'EnforceStrictValidation'");
1554 return Worksheet.MaxColumnWidth;
1570 private float GetValidatedHeight(
float rawValue, ReaderOptions readerOptions)
1572 if (rawValue < Worksheet.MinRowHeight)
1574 if (readerOptions.EnforceStrictValidation)
1576 throw new WorksheetException($
"The worksheet contains an invalid row height (too small: {rawValue}) value. Consider using the ImportOption 'EnforceValidRowDimensions' to ignore this error.");
1580 return Worksheet.MinRowHeight;
1583 else if (rawValue > Worksheet.MaxRowHeight)
1585 if (readerOptions.EnforceStrictValidation)
1587 throw new WorksheetException($
"The worksheet contains an invalid row height (too large: {rawValue}) value. Consider using the ImportOption 'EnforceValidRowDimensions' to ignore this error.");
1591 return Worksheet.MaxRowHeight;
1605 private string ResolveSharedString(
string raw)
1608 if (ParserUtils.TryParseInt(raw, out stringId))
1610 string resolvedString =
SharedStrings.ElementAtOrDefault(stringId);
1611 if (resolvedString ==
null)
1617 return resolvedString;
1631 private Cell CreateCell(
object value, Cell.CellType type, Address address,
string styleNumber =
null)
1633 Cell cell =
new Cell(value, type, address);
1634 if (styleNumber !=
null && resolvedStyles.TryGetValue(styleNumber, out var styleValue))
1636 cell.SetStyle(styleValue);