SpreadsheetWriter.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  1. // Copyright (c) Microsoft. All rights reserved.
  2. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  3. #undef DisplayWorkingSet
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text.RegularExpressions;
  9. using System.Xml;
  10. using System.Xml.Linq;
  11. using DocumentFormat.OpenXml.Packaging;
  12. using OpenXmlPowerTools;
  13. namespace OpenXmlPowerTools
  14. {
  15. // The classes in SpreadsheetWriter are still a work-in-progress. While they are useful in their current state, I will be enhancing and
  16. // changing them in the future. In particular, I will be augmenting the various definition classes (WorkbookDfn, WorksheetDfn,
  17. // RowDfn, and CellDfn.
  18. // They are robust enough in their current form to be used in enterprise, mission critical.
  19. public class WorkbookDfn
  20. {
  21. public IEnumerable<WorksheetDfn> Worksheets;
  22. }
  23. public class WorksheetDfn
  24. {
  25. public string Name;
  26. public string TableName;
  27. public IEnumerable<CellDfn> ColumnHeadings;
  28. public IEnumerable<RowDfn> Rows;
  29. }
  30. public class RowDfn
  31. {
  32. public IEnumerable<CellDfn> Cells;
  33. }
  34. // Value can be:
  35. // - string
  36. // - bool
  37. // - DateTime
  38. // - int32, int64, uint, double, float, etc.
  39. // Standard formats
  40. public class CellDfn
  41. {
  42. public static Dictionary<string, int> StandardFormats = new Dictionary<string, int>
  43. {
  44. { "0", 1 },
  45. { "0.00", 2 },
  46. { "#,##0", 3 },
  47. { "#,##0.00", 4 },
  48. { "0%", 9 },
  49. { "0.00%", 10 },
  50. { "0.00E+00", 11 },
  51. { "# ?/?", 12 },
  52. { "# ??/??", 13 },
  53. { "mm-dd-yy", 14 },
  54. { "d-mmm-yy", 15 },
  55. { "d-mmm", 16 },
  56. { "mmm-yy", 17 },
  57. { "h:mm AM/PM", 18 },
  58. { "h:mm:ss AM/PM", 19 },
  59. { "h:mm", 20 },
  60. { "h:mm:ss", 21 },
  61. { "h/d/yy h:mm", 22 },
  62. { "#,##0;(#,##0)", 37 },
  63. { "#,##0;[Red](#,##0)", 38 },
  64. { "#,##0.00;(#,##0.00)", 39 },
  65. { "#,##0.00;[Red](#,##0.00)", 40 },
  66. { "mm:ss", 45 },
  67. { "[h]:mm:ss", 46 },
  68. { "mmss.0", 47 },
  69. { "##0.0E+0", 48 },
  70. { "@", 49 },
  71. };
  72. public object Value;
  73. public CellDataType? CellDataType;
  74. public HorizontalCellAlignment? HorizontalCellAlignment;
  75. public bool? Bold;
  76. public bool? Italic;
  77. public string FormatCode;
  78. }
  79. public enum HorizontalCellAlignment
  80. {
  81. Left,
  82. Center,
  83. Right,
  84. }
  85. public enum CellDataType
  86. {
  87. Boolean,
  88. Date,
  89. Number,
  90. String,
  91. }
  92. public static class SpreadsheetWriter
  93. {
  94. public static void Write(string fileName, WorkbookDfn workbook)
  95. {
  96. try
  97. {
  98. if (fileName == null) throw new ArgumentNullException("fileName");
  99. if (workbook == null) throw new ArgumentNullException("workbook");
  100. FileInfo fi = new FileInfo(fileName);
  101. if (fi.Exists)
  102. fi.Delete();
  103. // create the blank workbook
  104. char[] base64CharArray = _EmptyXlsx
  105. .Where(c => c != '\r' && c != '\n').ToArray();
  106. byte[] byteArray =
  107. System.Convert.FromBase64CharArray(base64CharArray,
  108. 0, base64CharArray.Length);
  109. File.WriteAllBytes(fi.FullName, byteArray);
  110. // open the workbook, and create the TableProperties sheet, populate it
  111. using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(fi.FullName, true))
  112. {
  113. WorkbookPart workbookPart = sDoc.WorkbookPart;
  114. XDocument wXDoc = workbookPart.GetXDocument();
  115. XElement sheetElement = wXDoc
  116. .Root
  117. .Elements(S.sheets)
  118. .Elements(S.sheet)
  119. .Where(s => (string)s.Attribute(SSNoNamespace.name) == "Sheet1")
  120. .FirstOrDefault();
  121. if (sheetElement == null)
  122. throw new SpreadsheetWriterInternalException();
  123. string id = (string)sheetElement.Attribute(R.id);
  124. sheetElement.Remove();
  125. workbookPart.PutXDocument();
  126. WorksheetPart sPart = (WorksheetPart)workbookPart.GetPartById(id);
  127. workbookPart.DeletePart(sPart);
  128. XDocument appXDoc = sDoc
  129. .ExtendedFilePropertiesPart
  130. .GetXDocument();
  131. XElement vector = appXDoc
  132. .Root
  133. .Elements(EP.TitlesOfParts)
  134. .Elements(VT.vector)
  135. .FirstOrDefault();
  136. if (vector != null)
  137. {
  138. vector.SetAttributeValue(SSNoNamespace.size, 0);
  139. XElement lpstr = vector.Element(VT.lpstr);
  140. lpstr.Remove();
  141. }
  142. XElement vector2 = appXDoc
  143. .Root
  144. .Elements(EP.HeadingPairs)
  145. .Elements(VT.vector)
  146. .FirstOrDefault();
  147. XElement variant = vector2
  148. .Descendants(VT.i4)
  149. .FirstOrDefault();
  150. if (variant != null)
  151. variant.Value = "1";
  152. sDoc.ExtendedFilePropertiesPart.PutXDocument();
  153. if (workbook.Worksheets != null)
  154. foreach (var worksheet in workbook.Worksheets)
  155. AddWorksheet(sDoc, worksheet);
  156. workbookPart.WorkbookStylesPart.PutXDocument();
  157. }
  158. }
  159. catch (Exception e)
  160. {
  161. Console.WriteLine("Unhandled exception: {0} in {1}",
  162. e.ToString(), e.Source);
  163. throw e;
  164. }
  165. }
  166. public static void AddWorksheet(SpreadsheetDocument sDoc, WorksheetDfn worksheetData)
  167. {
  168. Regex validSheetName = new Regex(@"^[^'*\[\]/\\:?][^*\[\]/\\:?]{0,30}$");
  169. if (!validSheetName.IsMatch(worksheetData.Name))
  170. throw new InvalidSheetNameException(worksheetData.Name);
  171. // throw WorksheetAlreadyExistsException if a sheet with the same name (case-insensitive) already exists in the workbook
  172. string UCName = worksheetData.Name.ToUpper();
  173. XDocument wXDoc = sDoc.WorkbookPart.GetXDocument();
  174. if (wXDoc
  175. .Root
  176. .Elements(S.sheets)
  177. .Elements(S.sheet)
  178. .Attributes(SSNoNamespace.name)
  179. .Select(a => ((string)a).ToUpper())
  180. .Contains(UCName))
  181. throw new WorksheetAlreadyExistsException(worksheetData.Name);
  182. // create the worksheet with the supplied name
  183. XDocument appXDoc = sDoc
  184. .ExtendedFilePropertiesPart
  185. .GetXDocument();
  186. XElement vector = appXDoc
  187. .Root
  188. .Elements(EP.TitlesOfParts)
  189. .Elements(VT.vector)
  190. .FirstOrDefault();
  191. if (vector != null)
  192. {
  193. int? size = (int?)vector.Attribute(SSNoNamespace.size);
  194. if (size == null)
  195. size = 1;
  196. else
  197. size = size + 1;
  198. vector.SetAttributeValue(SSNoNamespace.size, size);
  199. vector.Add(
  200. new XElement(VT.lpstr, worksheetData.Name));
  201. XElement i4 = appXDoc
  202. .Root
  203. .Elements(EP.HeadingPairs)
  204. .Elements(VT.vector)
  205. .Elements(VT.variant)
  206. .Elements(VT.i4)
  207. .FirstOrDefault();
  208. if (i4 != null)
  209. i4.Value = ((int)i4 + 1).ToString();
  210. sDoc.ExtendedFilePropertiesPart.PutXDocument();
  211. }
  212. WorkbookPart workbook = sDoc.WorkbookPart;
  213. string rId = "R" + Guid.NewGuid().ToString().Replace("-", "");
  214. WorksheetPart worksheetPart = workbook.AddNewPart<WorksheetPart>(rId);
  215. XDocument wbXDoc = workbook.GetXDocument();
  216. XElement sheets = wbXDoc.Descendants(S.sheets).FirstOrDefault();
  217. sheets.Add(
  218. new XElement(S.sheet,
  219. new XAttribute(SSNoNamespace.name, worksheetData.Name.ToString()),
  220. new XAttribute(SSNoNamespace.sheetId, sheets.Elements(S.sheet).Count() + 1),
  221. new XAttribute(R.id, rId)));
  222. workbook.PutXDocument();
  223. string ws = S.s.ToString();
  224. string relns = R.r.ToString();
  225. using (Stream partStream = worksheetPart.GetStream(FileMode.Create, FileAccess.Write))
  226. {
  227. using (XmlWriter partXmlWriter = XmlWriter.Create(partStream))
  228. {
  229. partXmlWriter.WriteStartDocument();
  230. partXmlWriter.WriteStartElement("worksheet", ws);
  231. partXmlWriter.WriteStartElement("sheetData", ws);
  232. int numColumnHeadingRows = 0;
  233. int numColumns = 0;
  234. int numColumnsInRows = 0;
  235. int numRows;
  236. if (worksheetData.ColumnHeadings != null)
  237. {
  238. RowDfn row = new RowDfn
  239. {
  240. Cells = worksheetData.ColumnHeadings
  241. };
  242. SerializeRows(sDoc, partXmlWriter, new[] { row }, 1, out numColumns, out numColumnHeadingRows);
  243. }
  244. SerializeRows(sDoc, partXmlWriter, worksheetData.Rows, numColumnHeadingRows + 1, out numColumnsInRows,
  245. out numRows);
  246. int totalRows = numColumnHeadingRows + numRows;
  247. int totalColumns = Math.Max(numColumns, numColumnsInRows);
  248. if (worksheetData.ColumnHeadings != null && worksheetData.TableName != null)
  249. {
  250. partXmlWriter.WriteEndElement();
  251. string rId2 = "R" + Guid.NewGuid().ToString().Replace("-", "");
  252. partXmlWriter.WriteStartElement("tableParts", ws);
  253. partXmlWriter.WriteStartAttribute("count");
  254. partXmlWriter.WriteValue(1);
  255. partXmlWriter.WriteEndAttribute();
  256. partXmlWriter.WriteStartElement("tablePart", ws);
  257. partXmlWriter.WriteStartAttribute("id", relns);
  258. partXmlWriter.WriteValue(rId2);
  259. TableDefinitionPart tdp = worksheetPart.AddNewPart<TableDefinitionPart>(rId2);
  260. XDocument tXDoc = tdp.GetXDocument();
  261. XElement table = new XElement(S.table,
  262. new XAttribute(SSNoNamespace.id, 1),
  263. new XAttribute(SSNoNamespace.name, worksheetData.TableName),
  264. new XAttribute(SSNoNamespace.displayName, worksheetData.TableName),
  265. new XAttribute(SSNoNamespace._ref, "A1:" + SpreadsheetMLUtil.IntToColumnId(totalColumns - 1) + totalRows.ToString()),
  266. new XAttribute(SSNoNamespace.totalsRowShown, 0),
  267. new XElement(S.autoFilter,
  268. new XAttribute(SSNoNamespace._ref, "A1:" + SpreadsheetMLUtil.IntToColumnId(totalColumns - 1) + totalRows.ToString())),
  269. new XElement(S.tableColumns,
  270. new XAttribute(SSNoNamespace.count, totalColumns),
  271. worksheetData.ColumnHeadings.Select((ch, i) =>
  272. new XElement(S.tableColumn,
  273. new XAttribute(SSNoNamespace.id, i + 1),
  274. new XAttribute(SSNoNamespace.name, ch.Value)))),
  275. new XElement(S.tableStyleInfo,
  276. new XAttribute(SSNoNamespace.name, "TableStyleMedium2"),
  277. new XAttribute(SSNoNamespace.showFirstColumn, 0),
  278. new XAttribute(SSNoNamespace.showLastColumn, 0),
  279. new XAttribute(SSNoNamespace.showRowStripes, 1),
  280. new XAttribute(SSNoNamespace.showColumnStripes, 0)));
  281. tXDoc.Add(table);
  282. tdp.PutXDocument();
  283. }
  284. }
  285. }
  286. sDoc.WorkbookPart.WorkbookStylesPart.PutXDocument();
  287. sDoc.WorkbookPart.WorkbookStylesPart.Stylesheet.Save();
  288. }
  289. private static void SerializeRows(SpreadsheetDocument sDoc, XmlWriter xmlWriter, IEnumerable<RowDfn> rows,
  290. int startingRowNumber, out int numColumns, out int numRows)
  291. {
  292. int rowCount = 0;
  293. int rowNumber = startingRowNumber;
  294. int maxColumns = 0;
  295. int localNumColumns;
  296. #if DisplayWorkingSet
  297. int workingSetInterval = 10000;
  298. int workingSetCount = 0;
  299. #endif
  300. foreach (var row in rows)
  301. {
  302. SerializeRow(sDoc, xmlWriter, rowNumber, row, out localNumColumns);
  303. maxColumns = Math.Max(maxColumns, localNumColumns);
  304. rowNumber++;
  305. rowCount++;
  306. #if DisplayWorkingSet
  307. if (workingSetCount++ > workingSetInterval)
  308. {
  309. workingSetCount = 0;
  310. Console.WriteLine(Environment.WorkingSet);
  311. }
  312. #endif
  313. }
  314. numColumns = maxColumns;
  315. numRows = rowCount;
  316. }
  317. private static void SerializeRow(SpreadsheetDocument sDoc, XmlWriter xw, int rowCount, RowDfn row, out int numColumns)
  318. {
  319. string ns = S.s.NamespaceName;
  320. xw.WriteStartElement("row", ns);
  321. xw.WriteStartAttribute("r");
  322. xw.WriteValue(rowCount);
  323. xw.WriteEndAttribute();
  324. xw.WriteStartAttribute("spans");
  325. xw.WriteValue("1:" + row.Cells.Count().ToString());
  326. xw.WriteEndAttribute();
  327. int cellCount = 0;
  328. foreach (var cell in row.Cells)
  329. {
  330. if (cell != null)
  331. {
  332. xw.WriteStartElement("c", ns);
  333. xw.WriteStartAttribute("r");
  334. xw.WriteValue(SpreadsheetMLUtil.IntToColumnId(cellCount) + rowCount.ToString());
  335. xw.WriteEndAttribute();
  336. if (cell.Bold != null ||
  337. cell.Italic != null ||
  338. cell.FormatCode != null ||
  339. cell.HorizontalCellAlignment != null)
  340. {
  341. xw.WriteStartAttribute("s");
  342. xw.WriteValue(GetCellStyle(sDoc, cell));
  343. xw.WriteEndAttribute();
  344. }
  345. switch (cell.CellDataType)
  346. {
  347. case CellDataType.Boolean:
  348. xw.WriteStartAttribute("t");
  349. xw.WriteValue("b");
  350. xw.WriteEndAttribute();
  351. break;
  352. case CellDataType.Date:
  353. xw.WriteStartAttribute("t");
  354. xw.WriteValue("d");
  355. xw.WriteEndAttribute();
  356. break;
  357. case CellDataType.Number:
  358. xw.WriteStartAttribute("t");
  359. xw.WriteValue("n");
  360. xw.WriteEndAttribute();
  361. break;
  362. case CellDataType.String:
  363. xw.WriteStartAttribute("t");
  364. xw.WriteValue("str");
  365. xw.WriteEndAttribute();
  366. break;
  367. default:
  368. xw.WriteStartAttribute("t");
  369. xw.WriteValue("str");
  370. xw.WriteEndAttribute();
  371. break;
  372. }
  373. if (cell.Value != null)
  374. {
  375. xw.WriteStartElement("v", ns);
  376. xw.WriteValue(cell.Value);
  377. xw.WriteEndElement();
  378. }
  379. xw.WriteEndElement();
  380. }
  381. cellCount++;
  382. }
  383. xw.WriteEndElement();
  384. numColumns = cellCount;
  385. }
  386. private static int GetCellStyle(SpreadsheetDocument sDoc, CellDfn cell)
  387. {
  388. XDocument sXDoc = sDoc.WorkbookPart.WorkbookStylesPart.GetXDocument();
  389. var match = sXDoc
  390. .Root
  391. .Element(S.cellXfs)
  392. .Elements(S.xf)
  393. .Select((e, i) => new
  394. {
  395. Element = e,
  396. Index = i,
  397. })
  398. .FirstOrDefault(xf => CompareStyles(sXDoc, xf.Element, cell));
  399. if (match != null)
  400. return match.Index;
  401. // if no match, then create a style
  402. int newId = CreateNewStyle(sXDoc, cell, sDoc);
  403. return newId;
  404. }
  405. private static int CreateNewStyle(XDocument sXDoc, CellDfn cell, SpreadsheetDocument sDoc)
  406. {
  407. XAttribute applyFont = null;
  408. XAttribute fontId = null;
  409. if (cell.Bold == true || cell.Italic == true)
  410. {
  411. applyFont = new XAttribute(SSNoNamespace.applyFont, 1);
  412. fontId = new XAttribute(SSNoNamespace.fontId, GetFontId(sXDoc, cell));
  413. }
  414. XAttribute applyAlignment = null;
  415. XElement alignment = null;
  416. if (cell.HorizontalCellAlignment != null)
  417. {
  418. applyAlignment = new XAttribute(SSNoNamespace.applyAlignment, 1);
  419. alignment = new XElement(S.alignment,
  420. new XAttribute(SSNoNamespace.horizontal, cell.HorizontalCellAlignment.ToString().ToLower()));
  421. }
  422. XAttribute applyNumberFormat = null;
  423. XAttribute numFmtId = null;
  424. if (cell.FormatCode != null)
  425. {
  426. if (CellDfn.StandardFormats.ContainsKey(cell.FormatCode))
  427. {
  428. applyNumberFormat = new XAttribute(SSNoNamespace.applyNumberFormat, 1);
  429. numFmtId = new XAttribute(SSNoNamespace.numFmtId, CellDfn.StandardFormats[cell.FormatCode]);
  430. }
  431. else
  432. {
  433. applyNumberFormat = new XAttribute(SSNoNamespace.applyNumberFormat, 1);
  434. numFmtId = new XAttribute(SSNoNamespace.numFmtId, GetNumFmtId(sXDoc, cell.FormatCode));
  435. }
  436. }
  437. XElement newXf = new XElement(S.xf,
  438. applyFont,
  439. fontId,
  440. applyAlignment,
  441. alignment,
  442. applyNumberFormat,
  443. numFmtId);
  444. XElement cellXfs = sXDoc
  445. .Root
  446. .Element(S.cellXfs);
  447. if (cellXfs == null)
  448. {
  449. cellXfs = new XElement(S.cellXfs,
  450. new XAttribute(SSNoNamespace.count, 1),
  451. newXf);
  452. return 0;
  453. }
  454. else
  455. {
  456. int currentCount = (int)cellXfs.Attribute(SSNoNamespace.count);
  457. cellXfs.SetAttributeValue(SSNoNamespace.count, currentCount + 1);
  458. cellXfs.Add(newXf);
  459. return currentCount;
  460. }
  461. }
  462. private static int GetFontId(XDocument sXDoc, CellDfn cell)
  463. {
  464. XElement fonts = sXDoc.Root.Element(S.fonts);
  465. if (fonts == null)
  466. {
  467. fonts = new XElement(S.fonts,
  468. new XAttribute(SSNoNamespace.count, 1),
  469. new XElement(S.font,
  470. cell.Bold == true ? new XElement(S.b) : null,
  471. cell.Italic == true ? new XElement(S.i) : null));
  472. sXDoc.Root.Add(fonts);
  473. return 0;
  474. }
  475. XElement font = new XElement(S.font,
  476. cell.Bold == true ? new XElement(S.b) : null,
  477. cell.Italic == true ? new XElement(S.i) : null);
  478. fonts.Add(font);
  479. int count = (int)fonts.Attribute(SSNoNamespace.count);
  480. fonts.SetAttributeValue(SSNoNamespace.count, count + 1);
  481. return count;
  482. }
  483. private static int GetNumFmtId(XDocument sXDoc, string formatCode)
  484. {
  485. int xfNumber = 81;
  486. while (true)
  487. {
  488. if (!sXDoc
  489. .Root
  490. .Elements(S.numFmts)
  491. .Elements(S.numFmt)
  492. .Any(nf => (int)nf.Attribute(SSNoNamespace.numFmtId) == xfNumber))
  493. break;
  494. ++xfNumber;
  495. }
  496. XElement numFmts = sXDoc.Root.Element(S.numFmts);
  497. if (numFmts == null)
  498. {
  499. numFmts = new XElement(S.numFmts,
  500. new XAttribute(SSNoNamespace.count, 1),
  501. new XElement(S.numFmt,
  502. new XAttribute(SSNoNamespace.numFmtId, xfNumber),
  503. new XAttribute(SSNoNamespace.formatCode, formatCode)));
  504. sXDoc.Root.AddFirst(numFmts);
  505. return xfNumber;
  506. }
  507. XElement numFmt = new XElement(S.numFmt,
  508. new XAttribute(SSNoNamespace.numFmtId, xfNumber),
  509. new XAttribute(SSNoNamespace.formatCode, formatCode));
  510. numFmts.Add(numFmt);
  511. return xfNumber;
  512. }
  513. private static bool CompareStyles(XDocument sXDoc, XElement xf, CellDfn cell)
  514. {
  515. bool matchFont = MatchFont(sXDoc, xf, cell);
  516. bool matchAlignment = MatchAlignment(sXDoc, xf, cell);
  517. bool matchFormat = MatchFormat(sXDoc, xf, cell);
  518. return (matchFont && matchAlignment && matchFormat);
  519. }
  520. private static bool MatchFont(XDocument sXDoc, XElement xf, CellDfn cell)
  521. {
  522. if (((int?)xf.Attribute(SSNoNamespace.applyFont) == 0 ||
  523. xf.Attribute(SSNoNamespace.applyFont) == null) &&
  524. (cell.Bold == null || cell.Bold == false) &&
  525. (cell.Italic == null || cell.Italic == false))
  526. return true;
  527. if (((int?)xf.Attribute(SSNoNamespace.applyFont) == 0 ||
  528. xf.Attribute(SSNoNamespace.applyFont) == null) &&
  529. (cell.Bold == true ||
  530. cell.Italic == true))
  531. return false;
  532. int fontId = (int)xf.Attribute(SSNoNamespace.fontId);
  533. XElement font = sXDoc
  534. .Root
  535. .Element(S.fonts)
  536. .Elements(S.font)
  537. .ElementAt(fontId);
  538. XElement fabFont = new XElement(S.font,
  539. cell.Bold == true ? new XElement(S.b) : null,
  540. cell.Italic == true ? new XElement(S.i) : null);
  541. bool match = XNode.DeepEquals(font, fabFont);
  542. return match;
  543. }
  544. private static bool MatchAlignment(XDocument sXDoc, XElement xf, CellDfn cell)
  545. {
  546. if ((int?)xf.Attribute(SSNoNamespace.applyAlignment) == 0 ||
  547. (xf.Attribute(SSNoNamespace.applyAlignment) == null) &&
  548. cell.HorizontalCellAlignment == null)
  549. return true;
  550. if (xf.Attribute(SSNoNamespace.applyAlignment) == null &&
  551. cell.HorizontalCellAlignment != null)
  552. return false;
  553. string alignment = (string)xf.Element(S.alignment).Attribute(SSNoNamespace.horizontal);
  554. bool match = alignment == cell.HorizontalCellAlignment.ToString().ToLower();
  555. return match;
  556. }
  557. private static bool MatchFormat(XDocument sXDoc, XElement xf, CellDfn cell)
  558. {
  559. if ((int?)xf.Attribute(SSNoNamespace.applyNumberFormat) != 1 &&
  560. cell.FormatCode == null)
  561. return true;
  562. if (xf.Attribute(SSNoNamespace.applyNumberFormat) == null &&
  563. cell.FormatCode != null)
  564. return false;
  565. int numFmtId = (int)xf.Attribute(SSNoNamespace.numFmtId);
  566. int? nfi = null;
  567. if (cell.FormatCode != null)
  568. {
  569. if (CellDfn.StandardFormats.ContainsKey(cell.FormatCode))
  570. nfi = CellDfn.StandardFormats[cell.FormatCode];
  571. if (nfi == numFmtId)
  572. return true;
  573. }
  574. XElement numFmts = sXDoc
  575. .Root
  576. .Element(S.numFmts);
  577. if (numFmts == null)
  578. return false;
  579. XElement numFmt = numFmts
  580. .Elements(S.numFmt)
  581. .FirstOrDefault(numFmtElement =>
  582. (int)numFmtElement.Attribute(SSNoNamespace.numFmtId) == numFmtId);
  583. if (numFmt == null)
  584. return false;
  585. string styleFormatCode = (string)numFmt.Attribute(SSNoNamespace.formatCode);
  586. bool match = styleFormatCode == cell.FormatCode;
  587. return match;
  588. }
  589. private static string _EmptyXlsx = @"UEsDBBQABgAIAAAAIQBi7p1oYQEAAJAEAAATAAgCW0NvbnRlbnRfVHlwZXNdLnhtbCCiBAIooAAC
  590. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  591. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  592. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  593. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  594. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  595. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  596. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  597. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  598. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACs
  599. lE1PwzAMhu9I/IcqV9Rm44AQWrcDH0eYxPgBoXHXaGkSxd7Y/j1u9iGEyqaJXRq1sd/3iWtnNFm3
  600. NltBRONdKYbFQGTgKq+Nm5fiY/aS34sMSTmtrHdQig2gmIyvr0azTQDMONthKRqi8CAlVg20Cgsf
  601. wPFO7WOriF/jXAZVLdQc5O1gcCcr7wgc5dRpiPHoCWq1tJQ9r/nzliSCRZE9bgM7r1KoEKypFDGp
  602. XDn9yyXfORScmWKwMQFvGEPIXodu52+DXd4blyYaDdlURXpVLWPItZVfPi4+vV8Ux0V6KH1dmwq0
  603. r5YtV6DAEEFpbACotUVai1YZt+c+4p+CUaZleGGQ7nxJ+AQH8f8GmZ7/R0gyJwyRNhbwwqfdip5y
  604. blQE/U6RJ+PiAD+1j3Fw30yjD8gTFOH8KuxHpMvOAwtBJAOHIelrtoMjT9/5hr+6Hbr51qB7vGW6
  605. T8bfAAAA//8DAFBLAwQUAAYACAAAACEAtVUwI/UAAABMAgAACwAIAl9yZWxzLy5yZWxzIKIEAiig
  606. AAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  607. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  608. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  609. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  610. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  611. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  612. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  613. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  614. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  615. AIySz07DMAzG70i8Q+T76m5ICKGlu0xIuyFUHsAk7h+1jaMkQPf2hAOCSmPb0fbnzz9b3u7maVQf
  616. HGIvTsO6KEGxM2J712p4rZ9WD6BiImdpFMcajhxhV93ebF94pJSbYtf7qLKLixq6lPwjYjQdTxQL
  617. 8exypZEwUcphaNGTGahl3JTlPYa/HlAtPNXBaggHeweqPvo8+bK3NE1veC/mfWKXToxAnhM7y3bl
  618. Q2YLqc/bqJpCy0mDFfOc0xHJ+yJjA54m2lxP9P+2OHEiS4nQSODzPN+Kc0Dr64Eun2ip+L3OPOKn
  619. hOFNZPhhwcUPVF8AAAD//wMAUEsDBBQABgAIAAAAIQCBPpSX9AAAALoCAAAaAAgBeGwvX3JlbHMv
  620. d29ya2Jvb2sueG1sLnJlbHMgogQBKKAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  621. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  622. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  623. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  624. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsks9K
  625. xDAQxu+C7xDmbtOuIiKb7kWEvWp9gJBMm7JtEjLjn769oaLbhWW99BL4Zsj3/TKZ7e5rHMQHJuqD
  626. V1AVJQj0JtjedwremuebBxDE2ls9BI8KJiTY1ddX2xccNOdL5PpIIrt4UuCY46OUZByOmooQ0edO
  627. G9KoOcvUyajNQXcoN2V5L9PSA+oTT7G3CtLe3oJoppiT//cObdsbfArmfUTPZyIk8TTkB4hGpw5Z
  628. wY8uMiPI8/GbNeM5jwWP6bOU81ldYqjWZPgM6UAOkY8cfyWSc+cizN2aMOR0QvvKKa/b8luW5d/J
  629. yJONq78BAAD//wMAUEsDBBQABgAIAAAAIQAEjLxIUwEAACcCAAAPAAAAeGwvd29ya2Jvb2sueG1s
  630. jJHLTsMwEEX3SPyDNXuaxISqVE0qIUB0gyoB7drEk8aqY0e207R/zyRRKEtW9ryO516v1udasxM6
  631. r6zJIJnFwNAUVipzyODr8/VuAcwHYaTQ1mAGF/Swzm9vVp11x29rj4wAxmdQhdAso8gXFdbCz2yD
  632. hiqldbUIFLpD5BuHQvoKMdQ64nE8j2qhDIyEpfsPw5alKvDZFm2NJowQh1oEWt9XqvGQr0qlcTcq
  633. YqJp3kVNe581MC18eJEqoMzggULb4TWRAnNt89QqTdXH+5hDlP+K3DpG1IBu69RJFBdyCpjEUrQ6
  634. fJLg6T3K85TzeT/bm7NT2Pkrpg/Zea+MtF0GPCWzL1OUxLRSN5T2SoaKUOnimntDdahCBos4iXt6
  635. 9Ac/WErPDCczg96P3mZacshtSBLd3VLRxW1kMhCmsULoggT2x9DIOU/GjumP8x8AAAD//wMAUEsD
  636. BBQABgAIAAAAIQDQjLALfAAAAIEAAAAUAAAAeGwvc2hhcmVkU3RyaW5ncy54bWwMy0EKwjAQQNG9
  637. 4B3C7G2iCxFp2p0n0AMMzdgEkknIDKK3N8vP48/rt2TzoS6psofz5MAQbzUk3j28no/TDYwocsBc
  638. mTz8SGBdjodZRM14WTxE1Xa3VrZIBWWqjXjIu/aCOrLvVlonDBKJtGR7ce5qCyYGu/wBAAD//wMA
  639. UEsDBBQABgAIAAAAIQD7YqVtlAYAAKcbAAATAAAAeGwvdGhlbWUvdGhlbWUxLnhtbOxZT2/bNhS/
  640. D9h3IHRvbSe2Gwd1itixm61NG8Ruhx5pmZZYU6JA0kl9G9rjgAHDumGXAbvtMGwr0AK7dJ8mW4et
  641. A/oV9khKshjLS9IGG9bVh0Qif3z/3+MjdfXag4ihQyIk5XHbq12ueojEPh/TOGh7d4b9SxsekgrH
  642. Y8x4TNrenEjv2tb7713FmyokEUGwPpabuO2FSiWblYr0YRjLyzwhMcxNuIiwglcRVMYCHwHdiFXW
  643. qtVmJcI09lCMIyB7ezKhPkFDTdLbyoj3GLzGSuoBn4mBJk2cFQY7ntY0Qs5llwl0iFnbAz5jfjQk
  644. D5SHGJYKJtpe1fy8ytbVCt5MFzG1Ym1hXd/80nXpgvF0zfAUwShnWuvXW1d2cvoGwNQyrtfrdXu1
  645. nJ4BYN8HTa0sRZr1/katk9EsgOzjMu1utVGtu/gC/fUlmVudTqfRSmWxRA3IPtaX8BvVZn17zcEb
  646. kMU3lvD1zna323TwBmTxzSV8/0qrWXfxBhQyGk+X0Nqh/X5KPYdMONsthW8AfKOawhcoiIY8ujSL
  647. CY/VqliL8H0u+gDQQIYVjZGaJ2SCfYjiLo5GgmLNAG8SXJixQ75cGtK8kPQFTVTb+zDBkBELeq+e
  648. f//q+VP06vmT44fPjh/+dPzo0fHDHy0tZ+EujoPiwpfffvbn1x+jP55+8/LxF+V4WcT/+sMnv/z8
  649. eTkQMmgh0Ysvn/z27MmLrz79/bvHJfBtgUdF+JBGRKJb5Agd8Ah0M4ZxJScjcb4VwxBTZwUOgXYJ
  650. 6Z4KHeCtOWZluA5xjXdXQPEoA16f3XdkHYRipmgJ5xth5AD3OGcdLkoNcEPzKlh4OIuDcuZiVsQd
  651. YHxYxruLY8e1vVkCVTMLSsf23ZA4Yu4zHCsckJgopOf4lJAS7e5R6th1j/qCSz5R6B5FHUxLTTKk
  652. IyeQFot2aQR+mZfpDK52bLN3F3U4K9N6hxy6SEgIzEqEHxLmmPE6nikclZEc4ogVDX4Tq7BMyMFc
  653. +EVcTyrwdEAYR70xkbJszW0B+hacfgNDvSp1+x6bRy5SKDoto3kTc15E7vBpN8RRUoYd0DgsYj+Q
  654. UwhRjPa5KoPvcTdD9Dv4Accr3X2XEsfdpxeCOzRwRFoEiJ6ZiRJfXifcid/BnE0wMVUGSrpTqSMa
  655. /13ZZhTqtuXwrmy3vW3YxMqSZ/dEsV6F+w+W6B08i/cJZMXyFvWuQr+r0N5bX6FX5fLF1+VFKYYq
  656. rRsS22ubzjta2XhPKGMDNWfkpjS9t4QNaNyHQb3OHDpJfhBLQnjUmQwMHFwgsFmDBFcfURUOQpxA
  657. 317zNJFApqQDiRIu4bxohktpazz0/sqeNhv6HGIrh8Rqj4/t8Loezo4bORkjVWDOtBmjdU3grMzW
  658. r6REQbfXYVbTQp2ZW82IZoqiwy1XWZvYnMvB5LlqMJhbEzobBP0QWLkJx37NGs47mJGxtrv1UeYW
  659. 44WLdJEM8ZikPtJ6L/uoZpyUxcqSIloPGwz67HiK1QrcWprsG3A7i5OK7Oor2GXeexMvZRG88BJQ
  660. O5mOLC4mJ4vRUdtrNdYaHvJx0vYmcFSGxygBr0vdTGIWwH2Tr4QN+1OT2WT5wputTDE3CWpw+2Ht
  661. vqSwUwcSIdUOlqENDTOVhgCLNScr/1oDzHpRCpRUo7NJsb4BwfCvSQF2dF1LJhPiq6KzCyPadvY1
  662. LaV8pogYhOMjNGIzcYDB/TpUQZ8xlXDjYSqCfoHrOW1tM+UW5zTpipdiBmfHMUtCnJZbnaJZJlu4
  663. KUi5DOatIB7oViq7Ue78qpiUvyBVimH8P1NF7ydwBbE+1h7w4XZYYKQzpe1xoUIOVSgJqd8X0DiY
  664. 2gHRAle8MA1BBXfU5r8gh/q/zTlLw6Q1nCTVAQ2QoLAfqVAQsg9lyUTfKcRq6d5lSbKUkImogrgy
  665. sWKPyCFhQ10Dm3pv91AIoW6qSVoGDO5k/LnvaQaNAt3kFPPNqWT53mtz4J/ufGwyg1JuHTYNTWb/
  666. XMS8PVjsqna9WZ7tvUVF9MSizapnWQHMCltBK0371xThnFutrVhLGq81MuHAi8saw2DeECVwkYT0
  667. H9j/qPCZ/eChN9QhP4DaiuD7hSYGYQNRfck2HkgXSDs4gsbJDtpg0qSsadPWSVst26wvuNPN+Z4w
  668. tpbsLP4+p7Hz5sxl5+TiRRo7tbBjazu20tTg2ZMpCkOT7CBjHGO+lBU/ZvHRfXD0Dnw2mDElTTDB
  669. pyqBoYcemDyA5LcczdKtvwAAAP//AwBQSwMEFAAGAAgAAAAhAJQ34e1HAgAA7AQAAA0AAAB4bC9z
  670. dHlsZXMueG1spJRfi9swDMDfB/sOxu+p06zdmpLkoO0VDm7joB3s1U2c1Jz/BNvpmo1998lJmrbc
  671. wwb3Ekuy/LMkS0kezlKgEzOWa5Xi6STEiKlcF1xVKf6+3wYLjKyjqqBCK5billn8kH38kFjXCrY7
  672. MuYQIJRN8dG5ekmIzY9MUjvRNVOwU2ojqQPVVMTWhtHC+kNSkCgMPxNJucI9YSnz/4FIal6bOsi1
  673. rKnjBy64azsWRjJfPlVKG3oQEOp5OqP5hd0pb/CS50ZbXboJ4IguS56zt1HGJCZAypJSK2dRrhvl
  674. oFaA9jcsX5X+qbZ+yxt7ryyxv9CJCrBMMcmSXAttkIPKQGCdRVHJeo81FfxguHcrqeSi7c2RN3TF
  675. HPwkh9S8kfg4hsXCIS7EGFXkAwBDlkB1HDNqCwoa5H1bw/UKHrLHdH7/8K4MbafR/OYA6S7MkoM2
  676. BTTOtR4XU5YIVjoI1PDq6Fena/getHNQ5SwpOK20ogJE0kNGAdLJmRA731w/yjv2uUSqkVvpnooU
  677. Q5v6IlxESGQQe16veP4trWe/G4vO5T0fiDdh3wU9Xo/8e6f4m58GAZ0zINCh4cJxdQ/s0gdmcb6W
  678. IPQv4Hxn97uXskMlClbSRrj9uJniq/yVFbyR0ej1wk/adYgUX+XeK/Z3sLN7ttBesKLG8BT/flx9
  679. iTeP2yhYhKtFMPvE5kE8X22C+Wy92my2cRiF6z83g/aOMet+B1kCg7W0AobRDMkOKe6uthTfKM++
  680. 0bqxIhA2PPslCWLH31T2FwAA//8DAFBLAwQUAAYACAAAACEA5lWo42gBAACEAgAAGAAAAHhsL3dv
  681. cmtzaGVldHMvc2hlZXQxLnhtbIySy2rDMBBF94X+g9A+lpM+E+KEQgjNolD62svy2BaRNEaaNM3f
  682. d+yQUsgmO400c7j3jubLH+/EN8RkMRRynOVSQDBY2dAU8vNjPXqUIpEOlXYYoJAHSHK5uL6a7zFu
  683. UwtAggkhFbIl6mZKJdOC1ynDDgK/1Bi9Ji5jo1IXQVfDkHdqkuf3ymsb5JEwi5cwsK6tgRWanYdA
  684. R0gEp4n1p9Z26UTz5hKc13G760YGfceI0jpLhwEqhTezTRMw6tKx75/xrTYn9lCc4b01ERPWlDFO
  685. HYWee56qqWLSYl5ZdtDHLiLUhXwaS7WYD+F8Wdinf2dBunwHB4ag4h1J0WdfIm77xg1f5f2oOptd
  686. D9m/RlFBrXeO3nD/DLZpiSF37KW3NKsOK0iGs2RMNrn7E7HSpJna6QZedGxsSMJBPXQ9SBGPmDzj
  687. M2HXzz4wskQi9Keq5W0DbzXPbqSoEelU9Gr//s/iFwAA//8DAFBLAwQUAAYACAAAACEAm2QW1T4B
  688. AABRAgAAEQAIAWRvY1Byb3BzL2NvcmUueG1sIKIEASigAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  689. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  690. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  691. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  692. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  693. AAAAAAAAfJJRS8MwFIXfBf9DyXuaZGNDQ9uByp4cCE4U30Jy1xWbNCTRbv/etN1qB0PIS+4597sn
  694. l2Srg66TH3C+akyOWEpRAkY2qjJljt62a3yHEh+EUaJuDOToCB6titubTFouGwcvrrHgQgU+iSTj
  695. ubQ52odgOSFe7kELn0aHieKucVqEeHUlsUJ+iRLIjNIl0RCEEkGQDojtSEQnpJIj0n67ugcoSaAG
  696. DSZ4wlJG/rwBnPZXG3pl4tRVONr4plPcKVvJQRzdB1+NxrZt03bex4j5GfnYPL/2T8WV6XYlARWZ
  697. klw6EKFxRUaml7i4WviwiTveVaAejlG/UlOyjztAQCUxAB/inpX3+ePTdo2KboeY3mO23FLK+/PZ
  698. jbzo7wINBX0a/C+RzTBlmEbigjPGF/MJ8QwYcl9+guIXAAD//wMAUEsDBBQABgAIAAAAIQB0RMwo
  699. iQEAABEDAAAQAAgBZG9jUHJvcHMvYXBwLnhtbCCiBAEooAABAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  700. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  701. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  702. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  703. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  704. AAAAAAAAAJySQW/bMAyF7wP2HwzdGzltMQyBrGJIO/SwYQGStmdNpmOhsiSIrJHs14+2kcbZdtqN
  705. 5Ht4+kRJ3R06X/SQ0cVQieWiFAUEG2sX9pV42n29+iwKJBNq42OAShwBxZ3++EFtckyQyQEWHBGw
  706. Ei1RWkmJtoXO4ILlwEoTc2eI27yXsWmchfto3zoIJK/L8pOEA0Goob5K74FiSlz19L+hdbQDHz7v
  707. jomBtfqSknfWEN9Sf3c2R4wNFQ8HC17JuaiYbgv2LTs66lLJeau21nhYc7BujEdQ8jxQj2CGpW2M
  708. y6hVT6seLMVcoPvFa7sWxU+DMOBUojfZmUCMNdimZqx9Qsr6JeZXbAEIlWTDNBzLuXdeu1u9HA1c
  709. XBqHgAmEhUvEnSMP+KPZmEz/IF7OiUeGiXfC2Q5805lzvvHKfNIf2evYJROOLLxX31x4xae0i/eG
  710. 4LTOy6HatiZDzS9w0s8D9cibzH4IWbcm7KE+ef4Whsd/nn64Xt4uypuS33U2U/L8l/VvAAAA//8D
  711. AFBLAQItABQABgAIAAAAIQBi7p1oYQEAAJAEAAATAAAAAAAAAAAAAAAAAAAAAABbQ29udGVudF9U
  712. eXBlc10ueG1sUEsBAi0AFAAGAAgAAAAhALVVMCP1AAAATAIAAAsAAAAAAAAAAAAAAAAAmgMAAF9y
  713. ZWxzLy5yZWxzUEsBAi0AFAAGAAgAAAAhAIE+lJf0AAAAugIAABoAAAAAAAAAAAAAAAAAwAYAAHhs
  714. L19yZWxzL3dvcmtib29rLnhtbC5yZWxzUEsBAi0AFAAGAAgAAAAhAASMvEhTAQAAJwIAAA8AAAAA
  715. AAAAAAAAAAAA9AgAAHhsL3dvcmtib29rLnhtbFBLAQItABQABgAIAAAAIQDQjLALfAAAAIEAAAAU
  716. AAAAAAAAAAAAAAAAAHQKAAB4bC9zaGFyZWRTdHJpbmdzLnhtbFBLAQItABQABgAIAAAAIQD7YqVt
  717. lAYAAKcbAAATAAAAAAAAAAAAAAAAACILAAB4bC90aGVtZS90aGVtZTEueG1sUEsBAi0AFAAGAAgA
  718. AAAhAJQ34e1HAgAA7AQAAA0AAAAAAAAAAAAAAAAA5xEAAHhsL3N0eWxlcy54bWxQSwECLQAUAAYA
  719. CAAAACEA5lWo42gBAACEAgAAGAAAAAAAAAAAAAAAAABZFAAAeGwvd29ya3NoZWV0cy9zaGVldDEu
  720. eG1sUEsBAi0AFAAGAAgAAAAhAJtkFtU+AQAAUQIAABEAAAAAAAAAAAAAAAAA9xUAAGRvY1Byb3Bz
  721. L2NvcmUueG1sUEsBAi0AFAAGAAgAAAAhAHREzCiJAQAAEQMAABAAAAAAAAAAAAAAAAAAbBgAAGRv
  722. Y1Byb3BzL2FwcC54bWxQSwUGAAAAAAoACgCAAgAAKxsAAAAA";
  723. }
  724. public class SpreadsheetWriterInternalException : Exception
  725. {
  726. public SpreadsheetWriterInternalException()
  727. : base("Internal error - unexpected content in _EmptyXlsx.")
  728. {
  729. }
  730. }
  731. public class InvalidSheetNameException : Exception
  732. {
  733. public InvalidSheetNameException(string name)
  734. : base(string.Format("The supplied name ({0}) is not a valid XLSX worksheet name.", name))
  735. {
  736. }
  737. }
  738. }