33 private Stream stream;
34 private HashSet<string> dateStyles;
35 private HashSet<string> timeStyles;
36 private Dictionary<string, Style> resolvedStyles;
37 private IPasswordReader passwordReader;
38 private ReaderOptions readerOptions;
83 public void Init(Stream stream,
Workbook workbook, IOptions readerOptions, Action<Stream, Workbook, string, IOptions, int?> inlinePluginHandler)
86 this.Workbook = workbook;
87 this.Options = readerOptions;
88 this.readerOptions = readerOptions as ReaderOptions;
89 this.InlinePluginHandler = inlinePluginHandler;
90 if (dateStyles ==
null || timeStyles ==
null || this.resolvedStyles ==
null)
93 ProcessStyles(styleReaderContainer);
95 if (this.passwordReader ==
null)
97 this.passwordReader = PlugInLoader.GetPlugIn<IPasswordReader>(PlugInUUID.PasswordReader,
new LegacyPasswordReader());
98 this.passwordReader.Init(PasswordType.WorksheetProtection, (ReaderOptions)readerOptions);
110 WorksheetDefinition worksheetDefinition =
Workbook.AuxiliaryData.GetData<WorksheetDefinition>(PlugInUUID.WorkbookReader, PlugInUUID.WorksheetDefinitionEntity,
CurrentWorksheetID);
111 Worksheet worksheet =
new Worksheet(worksheetDefinition.WorksheetName, worksheetDefinition.SheetID,
Workbook)
113 Hidden = worksheetDefinition.Hidden
117 StringBuilder sb =
new StringBuilder();
118 using (XmlReader reader = XmlReader.Create(stream, XmlStreamUtils.CreateSettings()))
120 while (reader.Read())
122 if (reader.NodeType != XmlNodeType.Element)
126 switch (reader.LocalName.ToLowerInvariant())
129 GetSheetView(reader, worksheet);
131 case "sheetformatpr":
132 GetSheetFormats(reader, worksheet);
135 GetColumns(reader, worksheet, readerOptions);
138 GetRows(reader, worksheet, readerOptions, sb);
140 case "sheetprotection":
141 GetSheetProtection(reader, worksheet);
144 GetMergedCells(reader, worksheet);
147 GetAutoFilters(reader, worksheet);
151 SetWorkbookRelation(worksheet);
156 catch (NotSupportedContentException)
162 throw new IOException(
"The XML entry could not be read from the input stream. Please see the inner exception:", ex);
170 private void SetWorkbookRelation(Worksheet worksheet)
173 int selectedWorksheetId =
Workbook.AuxiliaryData.GetData<
int>(PlugInUUID.WorkbookReader, PlugInUUID.SelectedWorksheetEntity);
176 Workbook.SetSelectedWorksheet(worksheet);
184 private void ProcessStyles(StyleReaderContainer styleReaderContainer)
186 this.dateStyles =
new HashSet<string>();
187 this.timeStyles =
new HashSet<string>();
188 this.resolvedStyles =
new Dictionary<string, Style>();
189 for (
int i = 0; i < styleReaderContainer.StyleCount; i++)
193 string index = ParserUtils.ToString(i);
194 Style style = styleReaderContainer.GetStyle(i, out isDate, out isTime);
197 this.dateStyles.Add(index);
201 this.timeStyles.Add(index);
203 this.resolvedStyles.Add(index, style);
214 private void GetRows(XmlReader reader, Worksheet worksheet, ReaderOptions readerOptions, StringBuilder sb)
216 using (XmlReader sheetDataReader = reader.ReadSubtree())
218 sheetDataReader.Read();
219 while (sheetDataReader.Read())
221 if (!XmlStreamUtils.IsElement(sheetDataReader,
"row"))
225 string rowAttribute = sheetDataReader.GetAttribute(
"r");
226 if (rowAttribute !=
null)
228 int rowNumber = ParserUtils.ParseInt(rowAttribute) - 1;
229 string hiddenAttribute = sheetDataReader.GetAttribute(
"hidden");
230 if (hiddenAttribute !=
null && ParserUtils.ParseBinaryBool(hiddenAttribute) == 1)
232 worksheet.AddHiddenRow(rowNumber);
234 string heightAttribute = sheetDataReader.GetAttribute(
"ht");
235 if (heightAttribute !=
null)
237 worksheet.RowHeights.Add(rowNumber, GetValidatedHeight(ParserUtils.ParseFloat(heightAttribute), readerOptions));
240 if (!sheetDataReader.IsEmptyElement)
242 using (XmlReader rowReader = sheetDataReader.ReadSubtree())
245 while (rowReader.Read())
247 if (!XmlStreamUtils.IsElement(rowReader,
"c"))
251 ReadCell(rowReader, worksheet, sb);
264 private static void GetSheetView(XmlReader reader, Worksheet worksheet)
266 using (XmlReader subtree = reader.ReadSubtree())
269 while (subtree.Read())
271 if (!XmlStreamUtils.IsElement(subtree,
"sheetView"))
275 string attribute = subtree.GetAttribute(
"view") ??
string.Empty;
276 worksheet.ViewType = Worksheet.GetSheetViewTypeEnum(attribute);
277 attribute = subtree.GetAttribute(
"zoomScale");
278 if (attribute !=
null)
280 worksheet.ZoomFactor = ParserUtils.ParseInt(attribute);
282 attribute = subtree.GetAttribute(
"zoomScaleNormal");
283 if (attribute !=
null)
285 worksheet.ZoomFactors[Worksheet.SheetViewType.Normal] = ParserUtils.ParseInt(attribute);
287 attribute = subtree.GetAttribute(
"zoomScalePageLayoutView");
288 if (attribute !=
null)
290 worksheet.ZoomFactors[Worksheet.SheetViewType.PageLayout] = ParserUtils.ParseInt(attribute);
292 attribute = subtree.GetAttribute(
"zoomScaleSheetLayoutView");
293 if (attribute !=
null)
295 worksheet.ZoomFactors[Worksheet.SheetViewType.PageBreakPreview] = ParserUtils.ParseInt(attribute);
297 attribute = subtree.GetAttribute(
"showGridLines");
298 if (attribute !=
null)
300 worksheet.ShowGridLines = ParserUtils.ParseBinaryBool(attribute) == 1;
302 attribute = subtree.GetAttribute(
"showRowColHeaders");
303 if (attribute !=
null)
305 worksheet.ShowRowColumnHeaders = ParserUtils.ParseBinaryBool(attribute) == 1;
307 attribute = subtree.GetAttribute(
"showRuler");
308 if (attribute !=
null)
310 worksheet.ShowRuler = ParserUtils.ParseBinaryBool(attribute) == 1;
312 using (XmlReader sheetViewReader = subtree.ReadSubtree())
314 sheetViewReader.Read();
315 while (sheetViewReader.Read())
317 if (sheetViewReader.NodeType != XmlNodeType.Element)
321 if (XmlStreamUtils.IsElement(sheetViewReader,
"selection"))
323 attribute = sheetViewReader.GetAttribute(
"sqref");
324 if (attribute !=
null)
326 if (attribute.Contains(
" "))
328 string[] ranges = attribute.Split(
' ');
329 foreach (
string range
in ranges)
331 CollectSelectedCells(range, worksheet);
336 CollectSelectedCells(attribute, worksheet);
340 else if (XmlStreamUtils.IsElement(sheetViewReader,
"pane"))
342 SetPaneSplit(sheetViewReader, worksheet);
355 private static void CollectSelectedCells(
string attribute, Worksheet worksheet)
357 if (attribute.Contains(
":"))
360 worksheet.AddSelectedCells(
new Range(attribute));
365 worksheet.AddSelectedCells(
new Range(attribute +
":" + attribute));
374 private static void SetPaneSplit(XmlReader reader, Worksheet worksheet)
376 string attribute = reader.GetAttribute(
"state");
377 bool useNumbers =
false;
378 bool frozenState =
false;
379 bool ySplitDefined =
false;
380 bool xSplitDefined =
false;
381 int? paneSplitRowIndex =
null;
382 int? paneSplitColumnIndex =
null;
383 float? paneSplitHeight =
null;
384 float? paneSplitWidth =
null;
385 Address topLeftCell =
new Address(0, 0);
386 Worksheet.WorksheetPane? activePane =
null;
387 if (attribute !=
null)
389 if (ParserUtils.ToLower(attribute) ==
"frozen" || ParserUtils.ToLower(attribute) ==
"frozensplit")
393 useNumbers = frozenState;
395 attribute = reader.GetAttribute(
"ySplit");
396 if (attribute !=
null)
398 ySplitDefined =
true;
401 paneSplitRowIndex = ParserUtils.ParseInt(attribute);
405 paneSplitHeight = DataUtils.GetPaneSplitHeight(ParserUtils.ParseFloat(attribute));
408 attribute = reader.GetAttribute(
"xSplit");
409 if (attribute !=
null)
411 xSplitDefined =
true;
414 paneSplitColumnIndex = ParserUtils.ParseInt(attribute);
418 paneSplitWidth = DataUtils.GetPaneSplitWidth(ParserUtils.ParseFloat(attribute));
421 attribute = reader.GetAttribute(
"topLeftCell");
422 if (attribute !=
null)
424 topLeftCell =
new Address(attribute);
426 attribute = reader.GetAttribute(
"activePane") ??
string.Empty;
427 activePane = Worksheet.GetWorksheetPaneEnum(attribute);
430 if (ySplitDefined && !xSplitDefined)
432 worksheet.SetHorizontalSplit(paneSplitRowIndex.Value, frozenState, topLeftCell, activePane);
434 if (!ySplitDefined && xSplitDefined)
436 worksheet.SetVerticalSplit(paneSplitColumnIndex.Value, frozenState, topLeftCell, activePane);
438 else if (ySplitDefined && xSplitDefined)
440 worksheet.SetSplit(paneSplitColumnIndex.Value, paneSplitRowIndex.Value, frozenState, topLeftCell, activePane);
445 if (ySplitDefined && !xSplitDefined)
447 worksheet.SetHorizontalSplit(paneSplitHeight.Value, topLeftCell, activePane);
449 if (!ySplitDefined && xSplitDefined)
451 worksheet.SetVerticalSplit(paneSplitWidth.Value, topLeftCell, activePane);
453 else if (ySplitDefined && xSplitDefined)
455 worksheet.SetSplit(paneSplitWidth, paneSplitHeight, topLeftCell, activePane);
468 private void GetSheetProtection(XmlReader reader, Worksheet worksheet)
470 int hasProtection = 0;
471 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.AutoFilter, worksheet);
472 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.DeleteColumns, worksheet);
473 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.DeleteRows, worksheet);
474 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.FormatCells, worksheet);
475 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.FormatColumns, worksheet);
476 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.FormatRows, worksheet);
477 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.InsertColumns, worksheet);
478 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.InsertHyperlinks, worksheet);
479 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.InsertRows, worksheet);
480 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.Objects, worksheet);
481 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.PivotTables, worksheet);
482 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.Scenarios, worksheet);
483 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.SelectLockedCells, worksheet);
484 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.SelectUnlockedCells, worksheet);
485 hasProtection += ReadSheetProtectionAttribute(reader, Worksheet.SheetProtectionValue.Sort, worksheet);
486 if (hasProtection > 0)
488 worksheet.UseSheetProtection =
true;
491 using (XmlReader subtree = reader.ReadSubtree())
493 subtree.MoveToContent();
494 outerXml = subtree.ReadOuterXml();
496 XmlDocument miniDoc =
new XmlDocument { XmlResolver =
null };
497 miniDoc.LoadXml(outerXml);
498 this.passwordReader.ReadXmlAttributes(miniDoc.DocumentElement);
499 if (this.passwordReader.PasswordIsSet())
501 if (this.passwordReader is LegacyPasswordReader && (this.passwordReader as LegacyPasswordReader).ContemporaryAlgorithmDetected && (readerOptions ==
null || !readerOptions.IgnoreNotSupportedPasswordAlgorithms))
503 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");
505 worksheet.SheetProtectionPassword.CopyFrom(this.passwordReader);
516 private static int ReadSheetProtectionAttribute(XmlReader reader, Worksheet.SheetProtectionValue sheetProtectionValue, Worksheet worksheet)
518 string attrName = Worksheet.GetSheetProtectionName(sheetProtectionValue);
519 if (reader.GetAttribute(attrName) !=
null)
521 worksheet.SheetProtectionValues.Add(sheetProtectionValue);
532 private static void GetMergedCells(XmlReader reader, Worksheet worksheet)
534 using (XmlReader subtree = reader.ReadSubtree())
537 while (subtree.Read())
539 if (!XmlStreamUtils.IsElement(subtree,
"mergeCell"))
543 string attribute = subtree.GetAttribute(
"ref");
544 if (attribute !=
null)
546 worksheet.MergeCells(
new Range(attribute));
557 private static void GetSheetFormats(XmlReader reader, Worksheet worksheet)
559 string attribute = reader.GetAttribute(
"defaultColWidth");
560 if (attribute !=
null)
562 worksheet.DefaultColumnWidth = ParserUtils.ParseFloat(attribute);
564 attribute = reader.GetAttribute(
"defaultRowHeight");
565 if (attribute !=
null)
567 worksheet.DefaultRowHeight = ParserUtils.ParseFloat(attribute);
576 private static void GetAutoFilters(XmlReader reader, Worksheet worksheet)
578 string autoFilterRef = reader.GetAttribute(
"ref");
579 if (autoFilterRef !=
null)
581 Range range =
new Range(autoFilterRef);
582 worksheet.SetAutoFilter(range.StartAddress.Column, range.EndAddress.Column);
592 private void GetColumns(XmlReader reader, Worksheet worksheet, ReaderOptions readerOptions)
594 using (XmlReader subtree = reader.ReadSubtree())
597 while (subtree.Read())
599 if (!XmlStreamUtils.IsElement(subtree,
"col"))
605 List<int> indices =
new List<int>();
606 string attribute = subtree.GetAttribute(
"min");
607 if (attribute !=
null)
609 min = ParserUtils.ParseInt(attribute);
611 indices.Add(min.Value);
613 attribute = subtree.GetAttribute(
"max");
614 if (attribute !=
null)
616 max = ParserUtils.ParseInt(attribute);
618 if (min !=
null && max.Value != min.Value)
620 for (
int i = min.Value; i <= max.Value; i++)
625 attribute = subtree.GetAttribute(
"width");
626 float width = Worksheet.DefaultWorksheetColumnWidth;
627 if (attribute !=
null)
629 width = ParserUtils.ParseFloat(attribute);
631 attribute = subtree.GetAttribute(
"hidden");
633 if (attribute !=
null && ParserUtils.ParseBinaryBool(attribute) == 1)
637 attribute = subtree.GetAttribute(
"style");
638 Style defaultStyle =
null;
639 if (attribute !=
null && resolvedStyles.TryGetValue(attribute, out var attributeValue))
641 defaultStyle = attributeValue;
643 foreach (
int index
in indices)
645 string columnAddress = Cell.ResolveColumnAddress(index - 1);
646 if (defaultStyle !=
null)
648 worksheet.SetColumnDefaultStyle(columnAddress, defaultStyle);
650 if (width != Worksheet.DefaultWorksheetColumnWidth)
652 worksheet.SetColumnWidth(columnAddress, GetValidatedWidth(width, readerOptions));
656 worksheet.AddHiddenColumn(columnAddress);
669 private void ReadCell(XmlReader rowReader, Worksheet worksheet, StringBuilder sb)
671 string address = rowReader.GetAttribute(
"r");
672 string type = rowReader.GetAttribute(
"t");
673 string styleNumber = rowReader.GetAttribute(
"s");
675 if (!rowReader.IsEmptyElement)
677 using (XmlReader cellReader = rowReader.ReadSubtree())
680 while (cellReader.Read())
682 if (cellReader.NodeType != XmlNodeType.Element)
686 if (cellReader.LocalName.Equals(
"v", StringComparison.OrdinalIgnoreCase) ||
687 cellReader.LocalName.Equals(
"f", StringComparison.OrdinalIgnoreCase))
689 value = cellReader.ReadElementContentAsString();
691 else if (cellReader.LocalName.Equals(
"is", StringComparison.OrdinalIgnoreCase))
694 using (XmlReader isReader = cellReader.ReadSubtree())
697 while (isReader.Read())
699 if (isReader.NodeType == XmlNodeType.Element &&
700 isReader.LocalName.Equals(
"t", StringComparison.OrdinalIgnoreCase))
702 sb.Append(isReader.ReadElementContentAsString());
706 value = sb.ToString();
711 Cell cell = ResolveCellData(value, type, styleNumber, address);
712 worksheet.AddCell(cell, address);
723 private Cell ResolveCellData(
string raw,
string type,
string styleNumber,
string address)
725 Cell.CellType importedType = Cell.CellType.Default;
729 rawValue = TryParseBool(raw);
730 if (rawValue !=
null)
732 importedType = Cell.CellType.Bool;
736 rawValue = GetNumericValue(raw);
737 if (rawValue !=
null)
739 importedType = Cell.CellType.Number;
743 else if (type ==
"s")
745 importedType = Cell.CellType.String;
746 rawValue = ResolveSharedString(raw);
748 else if (type ==
"str")
750 importedType = Cell.CellType.Formula;
753 else if (type ==
"inlineStr")
755 importedType = Cell.CellType.String;
758 else if (dateStyles.Contains(styleNumber) && (type ==
null || type ==
"" || type ==
"n"))
760 rawValue = GetDateTimeValue(raw, Cell.CellType.Date, out importedType);
762 else if (timeStyles.Contains(styleNumber) && (type ==
null || type ==
"" || type ==
"n"))
764 rawValue = GetDateTimeValue(raw, Cell.CellType.Time, out importedType);
768 importedType = Cell.CellType.Number;
769 rawValue = GetNumericValue(raw);
771 if (rawValue ==
null && raw ==
"")
773 importedType = Cell.CellType.Empty;
776 else if (rawValue ==
null && raw.Length > 0)
778 importedType = Cell.CellType.String;
781 Address cellAddress =
new Address(address);
782 if (readerOptions !=
null)
784 if (readerOptions.EnforcedColumnTypes.Count > 0)
786 rawValue = GetEnforcedColumnValue(rawValue, importedType, cellAddress);
788 rawValue = GetGloballyEnforcedValue(rawValue, cellAddress);
789 rawValue = GetGloballyEnforcedFlagValues(rawValue, cellAddress);
790 importedType = ResolveType(rawValue, importedType);
791 if (importedType == Cell.CellType.Date && rawValue is DateTime && (DateTime)rawValue < DataUtils.FirstAllowedExcelDate)
794 rawValue = ((DateTime)rawValue).AddDays(1);
797 return CreateCell(rawValue, importedType, cellAddress, styleNumber);
806 private static Cell.CellType ResolveType(
object value, Cell.CellType defaultType)
808 if (defaultType == Cell.CellType.Formula)
814 return Cell.CellType.Empty;
828 return Cell.CellType.Number;
830 return Cell.CellType.Date;
832 return Cell.CellType.Time;
834 return Cell.CellType.Bool;
836 return Cell.CellType.String;
846 private object GetGloballyEnforcedFlagValues(
object data, Address address)
848 if (address.Row < readerOptions.EnforcingStartRowNumber)
852 if (readerOptions.EnforceDateTimesAsNumbers)
854 if (data is DateTime)
856 data = DataUtils.GetOADateTime((DateTime)data,
true);
858 else if (data is TimeSpan)
860 data = DataUtils.GetOATime((TimeSpan)data);
863 if (readerOptions.EnforceEmptyValuesAsString && data ==
null)
876 private object GetGloballyEnforcedValue(
object data, Address address)
878 if (address.Row < readerOptions.EnforcingStartRowNumber)
882 if (readerOptions.GlobalEnforcingType == ReaderOptions.GlobalType.AllNumbersToDouble)
884 object tempDouble = ConvertToDouble(data, readerOptions);
885 if (tempDouble !=
null)
890 else if (readerOptions.GlobalEnforcingType == ReaderOptions.GlobalType.AllNumbersToDecimal)
892 object tempDecimal = ConvertToDecimal(data, readerOptions);
893 if (tempDecimal !=
null)
898 else if (readerOptions.GlobalEnforcingType == ReaderOptions.GlobalType.AllNumbersToInt)
900 object tempInt = ConvertToInt(data);
906 else if (readerOptions.GlobalEnforcingType == ReaderOptions.GlobalType.EverythingToString)
908 return ConvertToString(data, readerOptions);
920 private object GetEnforcedColumnValue(
object data, Cell.CellType importedTyp, Address address)
922 if (address.Row < readerOptions.EnforcingStartRowNumber)
926 if (!readerOptions.EnforcedColumnTypes.TryGetValue(address.Column, out var columnType))
930 if (importedTyp == Cell.CellType.Formula)
936 case ReaderOptions.ColumnType.Numeric:
937 return GetNumericValue(data, importedTyp, readerOptions);
938 case ReaderOptions.ColumnType.Decimal:
939 return ConvertToDecimal(data, readerOptions);
940 case ReaderOptions.ColumnType.Double:
941 return ConvertToDouble(data, readerOptions);
942 case ReaderOptions.ColumnType.Date:
943 return ConvertToDate(data, readerOptions);
944 case ReaderOptions.ColumnType.Time:
945 return ConvertToTime(data, readerOptions);
946 case ReaderOptions.ColumnType.Bool:
947 return ConvertToBool(data, readerOptions);
949 return ConvertToString(data, readerOptions);
959 private object ConvertToBool(
object data, ReaderOptions readerOptions)
974 object tempObject = ConvertToDouble(data, readerOptions);
975 if (tempObject is
double)
977 double tempDouble = (double)tempObject;
978 if (
double.Equals(tempDouble, 0d))
982 else if (
double.Equals(tempDouble, 1d))
990 string tempString = (string)data;
991 bool? tempBool = TryParseBool(tempString);
992 if (tempBool !=
null)
994 return tempBool.Value;
1006 private static bool? TryParseBool(
string raw)
1012 else if (raw ==
"1")
1019 if (
bool.TryParse(raw, out value))
1036 private object ConvertToDouble(
object data, ReaderOptions readerOptions)
1038 object value = ConvertToDecimal(data, readerOptions);
1039 if (value is decimal)
1041 return Decimal.ToDouble((decimal)value);
1043 else if (value is
float)
1045 return Convert.ToDouble((
float)value);
1056 private object ConvertToDecimal(
object data, ReaderOptions readerOptions)
1058 IConvertible converter;
1072 converter = data as IConvertible;
1073 double tempDouble = converter.ToDouble(DataUtils.InvariantCulture);
1074 if (tempDouble > (
double)decimal.MaxValue || tempDouble < (
double)decimal.MinValue)
1080 return converter.ToDecimal(DataUtils.InvariantCulture);
1089 return decimal.Zero;
1092 return new decimal(DataUtils.GetOADateTime((DateTime)data));
1094 return new decimal(DataUtils.GetOATime((TimeSpan)data));
1097 string tempString = (string)data;
1098 if (ParserUtils.TryParseDecimal(tempString, out dValue))
1102 DateTime? tempDate = TryParseDate(tempString, readerOptions);
1103 if (tempDate !=
null)
1105 return new decimal(DataUtils.GetOADateTime(tempDate.Value));
1107 TimeSpan? tempTime = TryParseTime(tempString, readerOptions);
1108 if (tempTime !=
null)
1110 return new decimal(DataUtils.GetOATime(tempTime.Value));
1122 private static object ConvertToInt(
object data)
1132 tempDouble = DataUtils.GetOADateTime((DateTime)data,
true);
1133 return ConvertDoubleToInt(tempDouble);
1135 tempDouble = DataUtils.GetOATime((TimeSpan)data);
1136 return ConvertDoubleToInt(tempDouble);
1139 int? tempInt = TryConvertDoubleToInt(data);
1140 if (tempInt !=
null)
1146 return (
bool)data ? 1 : 0;
1149 if (ParserUtils.TryParseInt((
string)data, out tempInt2))
1164 private object ConvertToDate(
object data, ReaderOptions readerOptions)
1171 DateTime root = DataUtils.FirstAllowedExcelDate;
1172 TimeSpan time = (TimeSpan)data;
1173 root = root.AddDays(-1);
1174 root = root.AddHours(time.Hours);
1175 root = root.AddMinutes(time.Minutes);
1176 root = root.AddSeconds(time.Seconds);
1188 return ConvertDateFromDouble(data, readerOptions);
1190 DateTime? date2 = TryParseDate((
string)data, readerOptions);
1195 return ConvertDateFromDouble(data, readerOptions);
1206 private DateTime? TryParseDate(
string raw, ReaderOptions readerOptions)
1210 if (readerOptions ==
null ||
string.IsNullOrEmpty(readerOptions.DateTimeFormat) || readerOptions.TemporalCultureInfo ==
null)
1212 isDateTime = DateTime.TryParse(raw, ReaderOptions.DefaultCultureInfo, DateTimeStyles.None, out dateTime);
1216 isDateTime = DateTime.TryParseExact(raw, readerOptions.DateTimeFormat, readerOptions.TemporalCultureInfo, DateTimeStyles.None, out dateTime);
1218 if (isDateTime && dateTime >= DataUtils.FirstAllowedExcelDate && dateTime <= DataUtils.LastAllowedExcelDate)
1231 private object ConvertToTime(
object data, ReaderOptions readerOptions)
1236 return ConvertTimeFromDouble(data, readerOptions);
1249 return ConvertTimeFromDouble(data, readerOptions);
1251 TimeSpan? time = TryParseTime((
string)data, readerOptions);
1256 return ConvertTimeFromDouble(data, readerOptions);
1267 private TimeSpan? TryParseTime(
string raw, ReaderOptions readerOptions)
1271 if (readerOptions ==
null ||
string.IsNullOrEmpty(readerOptions.TimeSpanFormat) || readerOptions.TemporalCultureInfo ==
null)
1273 isTimeSpan = TimeSpan.TryParse(raw, ReaderOptions.DefaultCultureInfo, out timeSpan);
1277 isTimeSpan = TimeSpan.TryParseExact(raw, readerOptions.TimeSpanFormat, readerOptions.TemporalCultureInfo, out timeSpan);
1279 if (isTimeSpan && timeSpan.Days >= 0 && timeSpan.Days < DataUtils.MaxOADateValue)
1294 private static object GetDateTimeValue(
string raw, Cell.CellType valueType, out Cell.CellType resolvedType)
1297 if (!ParserUtils.TryParseDouble(raw, out dValue))
1299 resolvedType = Cell.CellType.String;
1302 if ((valueType == Cell.CellType.Date && (dValue < DataUtils.MinOADateValue || dValue > DataUtils.MaxOADateValue)) || (valueType == Cell.CellType.Time && (dValue < 0.0 || dValue > DataUtils.MaxOADateValue)))
1305 resolvedType = Cell.CellType.Number;
1306 return GetNumericValue(raw);
1308 DateTime tempDate = DataUtils.GetDateFromOA(dValue);
1311 tempDate = tempDate.AddDays(1);
1313 if (valueType == Cell.CellType.Date)
1315 resolvedType = Cell.CellType.Date;
1320 resolvedType = Cell.CellType.Time;
1321 return new TimeSpan((
int)dValue, tempDate.Hour, tempDate.Minute, tempDate.Second);
1331 private object ConvertDateFromDouble(
object data, ReaderOptions readerOptions)
1333 object oaDate = ConvertToDouble(data, readerOptions);
1334 if (oaDate is
double && (
double)oaDate < DataUtils.MaxOADateValue)
1336 DateTime date = DataUtils.GetDateFromOA((
double)oaDate);
1337 if (date >= DataUtils.FirstAllowedExcelDate && date <= DataUtils.LastAllowedExcelDate)
1351 private object ConvertTimeFromDouble(
object data, ReaderOptions readerOptions)
1353 object oaDate = ConvertToDouble(data, readerOptions);
1354 if (oaDate is
double)
1356 double d = (double)oaDate;
1357 if (d >= DataUtils.MinOADateValue && d <= DataUtils.MaxOADateValue)
1359 DateTime date = DataUtils.GetDateFromOA(d);
1360 return new TimeSpan((
int)d, date.Hour, date.Minute, date.Second);
1371 private static int? TryConvertDoubleToInt(
object data)
1373 IConvertible converter = data as IConvertible;
1374 double dValue = converter.ToDouble(ReaderOptions.DefaultCultureInfo);
1375 if (dValue >
int.MinValue && dValue <
int.MaxValue)
1377 return converter.ToInt32(ReaderOptions.DefaultCultureInfo);
1387 private static int ConvertDoubleToInt(
object data)
1389 IConvertible converter = data as IConvertible;
1390 return converter.ToInt32(ReaderOptions.DefaultCultureInfo);
1399 private string ConvertToString(
object data, ReaderOptions readerOptions)
1404 return ((
int)data).ToString(ReaderOptions.DefaultCultureInfo);
1406 return ((uint)data).ToString(ReaderOptions.DefaultCultureInfo);
1408 return ((
long)data).ToString(ReaderOptions.DefaultCultureInfo);
1410 return ((ulong)data).ToString(ReaderOptions.DefaultCultureInfo);
1412 return ((
float)data).ToString(ReaderOptions.DefaultCultureInfo);
1414 return ((
double)data).ToString(ReaderOptions.DefaultCultureInfo);
1416 return ((
bool)data).ToString(ReaderOptions.DefaultCultureInfo);
1418 return ((DateTime)data).ToString(readerOptions.DateTimeFormat, ParserUtils.InvariantCulture);
1420 return ((TimeSpan)data).ToString(readerOptions.TimeSpanFormat, ParserUtils.InvariantCulture);
1426 return data.ToString();
1437 private object GetNumericValue(
object raw, Cell.CellType importedType, ReaderOptions readerOptions)
1444 switch (importedType)
1446 case Cell.CellType.String:
1447 string tempString = raw.ToString();
1448 tempObject = GetNumericValue(tempString);
1449 if (tempObject !=
null)
1453 DateTime? tempDate = TryParseDate(tempString, readerOptions);
1454 if (tempDate !=
null)
1456 return DataUtils.GetOADateTime(tempDate.Value);
1458 TimeSpan? tempTime = TryParseTime(tempString, readerOptions);
1459 if (tempTime !=
null)
1461 return DataUtils.GetOATime(tempTime.Value);
1463 tempObject = ConvertToBool(raw, readerOptions);
1464 if (tempObject is
bool)
1466 return (
bool)tempObject ? 1 : 0;
1469 case Cell.CellType.Number:
1471 case Cell.CellType.Date:
1472 return DataUtils.GetOADateTime((DateTime)raw);
1473 case Cell.CellType.Time:
1474 return DataUtils.GetOATime((TimeSpan)raw);
1475 case Cell.CellType.Bool:
1491 private static object GetNumericValue(
string raw)
1493 bool hasDecimalPoint = raw.Contains(
".");
1496 if (!hasDecimalPoint)
1501 bool canBeUint = ParserUtils.TryParseUint(raw, out uiValue);
1502 bool canBeInt = ParserUtils.TryParseInt(raw, out iValue);
1503 if (canBeUint && !canBeInt)
1513 bool canBeUlong = ParserUtils.TryParseUlong(raw, out ulValue);
1514 bool canBeLong = ParserUtils.TryParseLong(raw, out lValue);
1515 if (canBeUlong && !canBeLong)
1530 if (ParserUtils.TryParseDecimal(raw, out dcValue))
1533 float testFloat = decimal.ToSingle(dcValue);
1534 decimal backToDecimal = (decimal)testFloat;
1537 if (dcValue == backToDecimal)
1544 return decimal.ToDouble(dcValue);
1548 else if (ParserUtils.TryParseFloat(raw, out fValue) && fValue >=
float.MinValue && fValue <=
float.MaxValue && !
float.IsInfinity(fValue))
1552 if (ParserUtils.TryParseDouble(raw, out dValue))
1566 private float GetValidatedWidth(
float rawValue, ReaderOptions readerOptions)
1568 if (rawValue < Worksheet.MinColumnWidth)
1570 if (readerOptions.EnforceStrictValidation)
1572 throw new WorksheetException($
"The worksheet contains an invalid column width (too small: {rawValue}) value. This error is ignored when disabling the reader option 'EnforceStrictValidation'");
1576 return Worksheet.MinColumnWidth;
1579 else if (rawValue > Worksheet.MaxColumnWidth)
1581 if (readerOptions.EnforceStrictValidation)
1583 throw new WorksheetException($
"The worksheet contains an invalid column width (too large: {rawValue}) value. This error is ignored when disabling the reader option 'EnforceStrictValidation'");
1587 return Worksheet.MaxColumnWidth;
1603 private float GetValidatedHeight(
float rawValue, ReaderOptions readerOptions)
1605 if (rawValue < Worksheet.MinRowHeight)
1607 if (readerOptions.EnforceStrictValidation)
1609 throw new WorksheetException($
"The worksheet contains an invalid row height (too small: {rawValue}) value. Consider using the ImportOption 'EnforceValidRowDimensions' to ignore this error.");
1613 return Worksheet.MinRowHeight;
1616 else if (rawValue > Worksheet.MaxRowHeight)
1618 if (readerOptions.EnforceStrictValidation)
1620 throw new WorksheetException($
"The worksheet contains an invalid row height (too large: {rawValue}) value. Consider using the ImportOption 'EnforceValidRowDimensions' to ignore this error.");
1624 return Worksheet.MaxRowHeight;
1638 private string ResolveSharedString(
string raw)
1641 if (ParserUtils.TryParseInt(raw, out stringId))
1643 string resolvedString =
SharedStrings.ElementAtOrDefault(stringId);
1644 if (resolvedString ==
null)
1650 return resolvedString;
1664 private Cell CreateCell(
object value, Cell.CellType type, Address address,
string styleNumber =
null)
1666 Cell cell =
new Cell(value, type, address);
1667 if (styleNumber !=
null && resolvedStyles.TryGetValue(styleNumber, out var styleValue))
1669 cell.SetStyle(styleValue);