diff --git a/src/Exceltk/Exceltk_vs.csproj b/src/Exceltk/Exceltk_vs.csproj
index 2337718..9d6d5a1 100644
--- a/src/Exceltk/Exceltk_vs.csproj
+++ b/src/Exceltk/Exceltk_vs.csproj
@@ -84,7 +84,6 @@
-
diff --git a/src/Exceltk/Reader/Binary/XlsBiffStream.cs b/src/Exceltk/Reader/Binary/XlsBiffStream.cs
deleted file mode 100644
index 93ac428..0000000
--- a/src/Exceltk/Reader/Binary/XlsBiffStream.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-using System;
-using System.IO;
-
-namespace Exceltk.Reader.Binary {
- ///
- /// Represents a BIFF stream
- ///
- internal class XlsBiffStream : XlsStream {
- private readonly byte[] bytes;
- private readonly int m_size;
- private readonly ExcelBinaryReader reader;
- private int m_offset;
-
- public XlsBiffStream(XlsHeader hdr, uint streamStart, bool isMini, XlsRootDirectory rootDir,
- ExcelBinaryReader reader)
- : base(hdr, streamStart, isMini, rootDir) {
- this.reader=reader;
- bytes=base.ReadStream();
- m_size=bytes.Length;
- m_offset=0;
- }
-
- ///
- /// Returns size of BIFF stream in bytes
- ///
- public int Size {
- get {
- return m_size;
- }
- }
-
- ///
- /// Returns current position in BIFF stream
- ///
- public int Position {
- get {
- return m_offset;
- }
- }
-
- ///
- /// Sets stream pointer to the specified offset
- ///
- /// Offset value
- /// Offset origin
- public void Seek(int offset, SeekOrigin origin) {
- switch (origin) {
- case SeekOrigin.Begin:
- m_offset=offset;
- break;
- case SeekOrigin.Current:
- m_offset+=offset;
- break;
- case SeekOrigin.End:
- m_offset=m_size-offset;
- break;
- }
-
- if (m_offset<0){
- string message = string.Format("{0} On offset={1}", Errors.ErrorBIFFIlegalBefore, offset);
- throw new ArgumentOutOfRangeException(message);
- }
-
- if (m_offset>m_size){
- string message = string.Format("{0} On offset={1}", Errors.ErrorBIFFIlegalAfter,offset);
- throw new ArgumentOutOfRangeException(message);
- }
- }
-
- ///
- /// Reads record under cursor and advances cursor position to next record
- ///
- ///
- public XlsBiffRecord Read() {
- if ((uint)m_offset>=bytes.Length){
- return null;
- }
-
- XlsBiffRecord rec=XlsBiffRecord.GetRecord(bytes, (uint)m_offset, reader);
- m_offset+=rec.Size;
-
- if (m_offset>m_size){
- return null;
- }
-
- return rec;
- }
-
- ///
- /// Reads record at specified offset, does not change cursor position
- ///
- ///
- ///
- public XlsBiffRecord ReadAt(int offset) {
- if ((uint)offset>=bytes.Length){
- return null;
- }
-
- XlsBiffRecord rec=XlsBiffRecord.GetRecord(bytes, (uint)offset, reader);
-
- //choose ReadOption.Loose to skip this check (e.g. sql reporting services)
- if (reader.ReadOption==ReadOption.Strict) {
- if (offset+rec.Size>m_size){
- return null;
- }
- }
-
- return rec;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Exceltk/Reader/ExcelBinaryReader.cs b/src/Exceltk/Reader/ExcelBinaryReader.cs
index bd1fa5d..6cc42c9 100644
--- a/src/Exceltk/Reader/ExcelBinaryReader.cs
+++ b/src/Exceltk/Reader/ExcelBinaryReader.cs
@@ -5,6 +5,8 @@
using System.IO;
using System.Text;
using Exceltk.Reader.Binary;
+using Exceltk.Reader.Package;
+using Exceltk.Reader.Parser;
namespace Exceltk.Reader {
///
@@ -49,7 +51,7 @@ public class ExcelBinaryReader : IExcelDataReader {
private int m_maxRow;
private bool m_noIndex;
private List m_sheets;
- private XlsBiffStream m_stream;
+ private BinaryPackageParser m_stream;
private ushort m_version;
private DataSet m_workbookData;
@@ -128,6 +130,11 @@ public void Close() {
#endregion
+
+ private static XlsBiffRecord RecordOf(BinaryPackage package) {
+ return package==null ? null : package.Record;
+ }
+
#region Private methods
private int ResultsCount {
@@ -150,7 +157,7 @@ private bool Read() {
private int findFirstDataCellOffset(int startOffset) {
//seek to the first dbcell record
- XlsBiffRecord record=m_stream.ReadAt(startOffset);
+ XlsBiffRecord record=RecordOf(m_stream.ReadAt(startOffset));
while (!(record is XlsBiffDbCell)) {
if (m_stream.Position >= m_stream.Size) {
return -1;
@@ -161,7 +168,7 @@ private int findFirstDataCellOffset(int startOffset) {
}
try {
- record=m_stream.Read();
+ record=RecordOf(m_stream.Read());
} catch {
return -2;
}
@@ -173,7 +180,7 @@ private int findFirstDataCellOffset(int startOffset) {
int offs=startCell.RowAddress;
do {
- row=m_stream.ReadAt(offs) as XlsBiffRow;
+ row=RecordOf(m_stream.ReadAt(offs)) as XlsBiffRow;
if (row==null){
break;
}
@@ -205,7 +212,7 @@ private void readWorkBookGlobals() {
return;
}
- m_stream=new XlsBiffStream(m_hdr,
+ m_stream=new BinaryPackageParser(m_hdr,
workbookEntry.StreamFirstSector,
workbookEntry.IsEntryMiniStream,
dir,this);
@@ -214,7 +221,7 @@ private void readWorkBookGlobals() {
m_stream.Seek(0, SeekOrigin.Begin);
- XlsBiffRecord rec=m_stream.Read();
+ XlsBiffRecord rec=RecordOf(m_stream.Read());
var bof=rec as XlsBiffBOF;
if (bof==null||bof.Type!=BIFFTYPE.WorkbookGlobals) {
@@ -227,7 +234,7 @@ private void readWorkBookGlobals() {
m_version=bof.Version;
m_sheets=new List();
- while (null!=(rec=m_stream.Read())) {
+ while (null!=(rec=RecordOf(m_stream.Read()))) {
switch (rec.ID) {
case BIFFRECORDTYPE.INTERFACEHDR:
m_globals.InterfaceHdr=(XlsBiffInterfaceHdr)rec;
@@ -321,20 +328,20 @@ private bool readWorkSheetGlobals(XlsWorksheet sheet, out XlsBiffIndex idx, out
m_stream.Seek((int)sheet.DataOffset, SeekOrigin.Begin);
// Read BOF
- var bof=m_stream.Read() as XlsBiffBOF;
+ var bof=RecordOf(m_stream.Read()) as XlsBiffBOF;
if (bof==null||bof.Type!=BIFFTYPE.Worksheet) {
return false;
}
// Read Index
- XlsBiffRecord rec=m_stream.Read();
+ XlsBiffRecord rec=RecordOf(m_stream.Read());
if (rec==null)
return false;
if (rec is XlsBiffIndex) {
idx=rec as XlsBiffIndex;
} else if (rec is XlsBiffUncalced) {
// Sometimes this come before the index...
- idx=m_stream.Read() as XlsBiffIndex;
+ idx=RecordOf(m_stream.Read()) as XlsBiffIndex;
}
if (idx!=null) {
@@ -346,7 +353,7 @@ private bool readWorkSheetGlobals(XlsWorksheet sheet, out XlsBiffIndex idx, out
XlsBiffDimensions dims=null;
do {
- trec=m_stream.Read();
+ trec=RecordOf(m_stream.Read());
if (trec.ID==BIFFRECORDTYPE.DIMENSIONS) {
dims=(XlsBiffDimensions)trec;
break;
@@ -363,7 +370,7 @@ private bool readWorkSheetGlobals(XlsWorksheet sheet, out XlsBiffIndex idx, out
while (rowRecord==null) {
if (m_stream.Position>=m_stream.Size)
break;
- XlsBiffRecord thisRec=m_stream.Read();
+ XlsBiffRecord thisRec=RecordOf(m_stream.Read());
if (thisRec is XlsBiffEOF)
break;
@@ -402,7 +409,7 @@ private bool readWorkSheetGlobals(XlsWorksheet sheet, out XlsBiffIndex idx, out
while (true) {
if (m_stream.Position>=m_stream.Size)
break;
- XlsBiffRecord thisRecord=m_stream.Read();
+ XlsBiffRecord thisRecord=RecordOf(m_stream.Read());
if (thisRecord is XlsBiffEOF) {
break;
@@ -427,7 +434,7 @@ private void DumpBiffRecords() {
int startPos=m_stream.Position;
do {
- rec=m_stream.Read();
+ rec=RecordOf(m_stream.Read());
} while (rec!=null&&m_stream.Position m_rowPackages;
#endregion
@@ -47,25 +49,13 @@ internal ExcelOpenXmlReader() {
#region IExcelDataReader Members
public void Open(Stream fileStream) {
- var zipWorker = new ZipWorker();
- zipWorker.Extract(fileStream);
- Open(zipWorker, ownsPackage: true);
- }
-
- ///
- /// Open an already-extracted OpenXML package (package / package-parser path).
- ///
- public void Open(IOpenXmlPackage package, bool ownsPackage = false) {
- if (package == null) {
- throw new ArgumentNullException("package");
- }
-
- m_package = package;
- m_ownsPackage = ownsPackage;
+ m_zipWorker = new ZipWorker();
+ m_zipWorker.Extract(fileStream);
+ m_ownsZipWorker = true;
- if (!m_package.IsValid) {
+ if (!m_zipWorker.IsValid) {
m_isValid = false;
- m_exceptionMessage = m_package.ExceptionMessage;
+ m_exceptionMessage = m_zipWorker.ExceptionMessage;
Dispose();
} else {
m_isValid = true;
@@ -98,11 +88,16 @@ public void Close() {
m_sheetStream = null;
}
- if (m_package != null) {
- if (m_ownsPackage) {
- m_package.Dispose();
+ if (m_rowPackages != null) {
+ m_rowPackages.Dispose();
+ m_rowPackages = null;
+ }
+
+ if (m_zipWorker != null) {
+ if (m_ownsZipWorker) {
+ m_zipWorker.Dispose();
}
- m_package = null;
+ m_zipWorker = null;
}
}
@@ -112,10 +107,10 @@ public void Close() {
private void ReadGlobals() {
m_workbook = new XlsxWorkbook(
- m_package.GetWorkbookStream(),
- m_package.GetWorkbookRelsStream(),
- m_package.GetSharedStringsStream(),
- m_package.GetStylesStream());
+ m_zipWorker.GetWorkbookStream(),
+ m_zipWorker.GetWorkbookRelsStream(),
+ m_zipWorker.GetSharedStringsStream(),
+ m_zipWorker.GetStylesStream());
// Some workbooks omit styles.xml; treat that as empty styles instead of NRE (#10).
if (m_workbook.Styles == null) {
@@ -228,6 +223,14 @@ private void ReadSheetGlobals(XlsxWorksheet sheet) {
m_xmlReader.ReadToFollowing(XlsxWorksheet.N_sheetData, m_namespaceUri);
if (m_xmlReader.IsEmptyElement) {
sheet.IsEmpty=true;
+ m_rowPackages = null;
+ } else {
+ // Stream rows as XmlRowPackage entities via XmlPackageParser.
+ if (m_rowPackages != null) {
+ m_rowPackages.Dispose();
+ }
+ var parser = new XmlPackageParser(m_xmlReader, m_namespaceUri);
+ m_rowPackages = parser.ParseRows().GetEnumerator();
}
}
@@ -242,7 +245,7 @@ private bool ResetSheetReader(XlsxWorksheet sheet) {
m_xmlReader = null;
}
- m_sheetStream = m_package.GetWorksheetStream(sheet.Path);
+ m_sheetStream = m_zipWorker.GetWorksheetStream(sheet.Path);
if (null == m_sheetStream) {
return false;
}
@@ -312,10 +315,6 @@ private bool ReadSheetRow(XlsxWorksheet sheet) {
return false;
}
- if (null == m_xmlReader) {
- return false;
- }
-
if (m_emptyRowCount != 0) {
m_cellsValues = new object[sheet.ColumnsCount];
m_emptyRowCount--;
@@ -332,147 +331,25 @@ private bool ReadSheetRow(XlsxWorksheet sheet) {
return true;
}
- bool isRow = false;
- bool isSheetData = (m_xmlReader.NodeType == XmlNodeType.Element &&
- m_xmlReader.LocalName == XlsxWorksheet.N_sheetData);
- if (isSheetData) {
- isRow = m_xmlReader.ReadToFollowing(XlsxWorksheet.N_row, m_namespaceUri);
- } else {
- if (m_xmlReader.LocalName == XlsxWorksheet.N_row && m_xmlReader.NodeType == XmlNodeType.EndElement) {
- //Console.WriteLine("read");
- m_xmlReader.Read();
- }
- isRow = (m_xmlReader.NodeType == XmlNodeType.Element && m_xmlReader.LocalName == XlsxWorksheet.N_row);
- }
-
- if (!isRow) {
+ if (m_rowPackages == null || !m_rowPackages.MoveNext()) {
return false;
}
- //Console.WriteLine("New Row");
-
+ XmlRowPackage rowPackage = m_rowPackages.Current;
m_cellsValues = new object[sheet.ColumnsCount];
- if (sheet.ColumnsCount > 13) {
- int i = sheet.ColumnsCount;
- }
- var rowIndexText = m_xmlReader.GetAttribute(XlsxWorksheet.A_r);
- Debug.Assert(rowIndexText!=null);
- int rowIndex=int.Parse(rowIndexText);
+ Debug.Assert(rowPackage.RowIndexAttribute != null);
+ int rowIndex = int.Parse(rowPackage.RowIndexAttribute);
if (rowIndex != (m_depth + 1)) {
m_emptyRowCount = rowIndex - m_depth - 1;
}
- bool hasValue = false;
- bool hasFormula = false;
- HyperLinkIndex hyperlinkIndex = null;
- string a_s = String.Empty;
- string a_t = String.Empty;
- string a_r = String.Empty;
- string f = String.Empty;
- int col = 0;
- int row = 0;
-
- while (m_xmlReader.Read()) {
-
- //Console.WriteLine("m_xmlReader.LocalName:{0}",m_xmlReader.LocalName);
- //Console.WriteLine("m_xmlReader.Value:{0}",m_xmlReader.Value);
- if (m_xmlReader.Depth == 2) {
- break;
- }
-
- if (m_xmlReader.NodeType == XmlNodeType.Element) {
- hasValue = false;
-
- if (m_xmlReader.LocalName == XlsxWorksheet.N_c) {
- a_s = m_xmlReader.GetAttribute(XlsxWorksheet.A_s);
- a_t = m_xmlReader.GetAttribute(XlsxWorksheet.A_t);
- a_r = m_xmlReader.GetAttribute(XlsxWorksheet.A_r);
- XlsxDimension.XlsxDim(a_r, out col, out row);
- } else if(m_xmlReader.LocalName == XlsxWorksheet.N_f){
- hasFormula = true;
- } else if (m_xmlReader.LocalName == XlsxWorksheet.N_v || m_xmlReader.LocalName == XlsxWorksheet.N_t) {
- hasValue = true;
- hasFormula = false;
- } else {
- //Console.WriteLine("m_xmlReader.LocalName:{0}",m_xmlReader.LocalName);
- // Ignore
- }
- }
-
- bool hasHyperLinkFormula = false;
- if(m_xmlReader.NodeType == XmlNodeType.Text && hasFormula){
- string formula = m_xmlReader.Value.ToString();
- if(formula.StartsWith("HYPERLINK(")){
- hyperlinkIndex = this.ReadHyperLinkFormula(sheet.Name, formula);
- }
- }
-
-
- if (m_xmlReader.NodeType == XmlNodeType.Text && hasValue) {
- double number;
- object o = m_xmlReader.Value;
-
- //Console.WriteLine("O:{0}", o);
-
- if (double.TryParse(o.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out number)) {
- // numeric
- o=number;
- }
-
- if (null!=a_t&&a_t==XlsxWorksheet.A_s) {
- // string
- if (m_workbook.SST!=null) {
- var sstStr = m_workbook.SST[int.Parse(o.ToString())];
- //Console.WriteLine(sstStr);
- o=sstStr.ConvertEscapeChars();
- }
- } else if (null!=a_t&&a_t==XlsxWorksheet.N_inlineStr) {
- // string inline
- o=o.ToString().ConvertEscapeChars();
- } else if (a_t=="b") {
- // boolean
- o=m_xmlReader.Value=="1";
- } else if (a_t=="str") {
- // string
- o=m_xmlReader.Value;
- } else if (null!=a_s && m_workbook.Styles!=null && m_workbook.Styles.CellXfs!=null) {
- // something else — apply number/date format when style exists
- int styleIndex;
- if (int.TryParse(a_s, out styleIndex)
- && styleIndex>=0
- && styleIndex= 1) {
- EnsureRowCapacity(sheet, col);
- if(hyperlinkIndex!=null){
- var co = new XlsCell(o);
- co.HyperLinkIndex = hyperlinkIndex;
- m_cellsValues[col - 1] = co;
- hyperlinkIndex = null;
- }else{
- m_cellsValues[col - 1] = o;
- }
- }
- }else{
- //Console.WriteLine(m_xmlReader.Value.ToString());
- }
+ foreach (XmlCellPackage cellPackage in rowPackage.Cells) {
+ ApplyCellPackage(sheet, cellPackage);
}
if (m_emptyRowCount > 0) {
- //Console.WriteLine("Again");
m_savedCellsValues = m_cellsValues;
return ReadSheetRow(sheet);
}
@@ -481,37 +358,80 @@ private bool ReadSheetRow(XlsxWorksheet sheet) {
return true;
}
- private bool ReadMergeCells(XlsxWorksheet sheet, DataTable table) {
- // Restart the sheet stream so we can locate mergeCells independently of row reading.
- if (!ResetSheetReader(sheet)) {
- return false;
- }
-
- if (!m_xmlReader.ReadToFollowing(XlsxWorksheet.N_mergeCells)) {
- return false;
- }
- if (m_xmlReader.IsEmptyElement) {
- return false;
+ private void ApplyCellPackage(XlsxWorksheet sheet, XmlCellPackage cellPackage) {
+ string a_s = cellPackage.StyleId;
+ string a_t = cellPackage.CellType;
+ string a_r = cellPackage.Reference;
+ int col;
+ int row;
+ if (string.IsNullOrEmpty(a_r)) {
+ return;
}
+ XlsxDimension.XlsxDim(a_r, out col, out row);
- while (m_xmlReader.Read()) {
- if (m_xmlReader.NodeType != XmlNodeType.Element) {
- if (m_xmlReader.NodeType == XmlNodeType.EndElement &&
- m_xmlReader.LocalName == XlsxWorksheet.N_mergeCells) {
- break;
+ HyperLinkIndex hyperlinkIndex = null;
+ if (!string.IsNullOrEmpty(cellPackage.Formula) && cellPackage.Formula.StartsWith("HYPERLINK(")) {
+ hyperlinkIndex = this.ReadHyperLinkFormula(sheet.Name, cellPackage.Formula);
+ }
+
+ double number;
+ object o = cellPackage.ValueText;
+
+ if (double.TryParse(o.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out number)) {
+ o = number;
+ }
+
+ if (null != a_t && a_t == XlsxWorksheet.A_s) {
+ if (m_workbook.SST != null) {
+ var sstStr = m_workbook.SST[int.Parse(o.ToString())];
+ o = sstStr.ConvertEscapeChars();
+ }
+ } else if (null != a_t && a_t == XlsxWorksheet.N_inlineStr) {
+ o = o.ToString().ConvertEscapeChars();
+ } else if (a_t == "b") {
+ o = cellPackage.ValueText == "1";
+ } else if (a_t == "str") {
+ o = cellPackage.ValueText;
+ } else if (null != a_s && m_workbook.Styles != null && m_workbook.Styles.CellXfs != null) {
+ int styleIndex;
+ if (int.TryParse(a_s, out styleIndex)
+ && styleIndex >= 0
+ && styleIndex < m_workbook.Styles.CellXfs.Count) {
+ XlsxXf xf = m_workbook.Styles.CellXfs[styleIndex];
+ if (xf.ApplyNumberFormat && o != null && o.ToString() != string.Empty &&
+ IsDateTimeStyle(xf.NumFmtId)) {
+ o = number.ConvertFromOATime();
+ } else if (xf.NumFmtId == 49) {
+ o = o.ToString();
}
- continue;
}
- if (m_xmlReader.LocalName != XlsxWorksheet.N_mergeCell) {
- break;
+ }
+
+ if (col >= 1) {
+ EnsureRowCapacity(sheet, col);
+ if (hyperlinkIndex != null) {
+ var co = new XlsCell(o);
+ co.HyperLinkIndex = hyperlinkIndex;
+ m_cellsValues[col - 1] = co;
+ } else {
+ m_cellsValues[col - 1] = o;
}
+ }
+ }
- string aref = m_xmlReader.GetAttribute(XlsxWorksheet.A_ref);
+ private bool ReadMergeCells(XlsxWorksheet sheet, DataTable table) {
+ // Restart the sheet stream so we can locate mergeCells independently of row reading.
+ if (!ResetSheetReader(sheet)) {
+ return false;
+ }
+
+ var parser = new XmlPackageParser(m_xmlReader, m_namespaceUri);
+ foreach (XmlMergePackage mergePackage in parser.ParseMerges()) {
+ string aref = mergePackage.Ref;
if (string.IsNullOrEmpty(aref)) {
continue;
}
- // ref may be "A2:A8" or a single cell "A2"
string[] parts = aref.Split(':');
int c1, r1, c2, r2;
XlsxDimension.XlsxDim(parts[0], out c1, out r1);
@@ -522,7 +442,6 @@ private bool ReadMergeCells(XlsxWorksheet sheet, DataTable table) {
r2 = r1;
}
- // Convert to 0-based
c1--; r1--; c2--; r2--;
if (c1 < 0 || r1 < 0) {
continue;
@@ -551,27 +470,19 @@ private bool ReadHyperLinks(XlsxWorksheet sheet, DataTable table) {
return false;
}
- // ReadTo HyperLinks Node
if (m_xmlReader == null) {
return false;
}
- if (!m_xmlReader.ReadToFollowing(XlsxWorksheet.N_hyperlinks)) {
- return false;
- }
- if (m_xmlReader.IsEmptyElement) {
- return false;
- }
-
- // Read Realtionship Table
- Stream sheetRelStream = m_package.GetWorksheetRelsStream(sheet.Path);
+ // Read Relationship Table
+ Stream sheetRelStream = m_zipWorker.GetWorksheetRelsStream(sheet.Path);
var hyperDict = new Dictionary();
if (sheetRelStream != null) {
using (XmlReader reader = XmlReader.Create(sheetRelStream)) {
while (reader.Read()) {
if (reader.NodeType == XmlNodeType.Element && reader.LocalName == XlsxWorkbook.N_rel) {
string rid = reader.GetAttribute(XlsxWorkbook.A_id);
- Debug.Assert(rid!=null);
+ Debug.Assert(rid != null);
hyperDict[rid] = reader.GetAttribute(XlsxWorkbook.A_target);
}
}
@@ -579,21 +490,14 @@ private bool ReadHyperLinks(XlsxWorksheet sheet, DataTable table) {
}
}
-
- // Read All HyperLink Node
- while (m_xmlReader.Read()) {
- if (m_xmlReader.NodeType != XmlNodeType.Element) {
- break;
- }
-
- if (m_xmlReader.LocalName != XlsxWorksheet.N_hyperlink) {
- break;
- }
-
- string aref = m_xmlReader.GetAttribute(XlsxWorksheet.A_ref);
- string display = m_xmlReader.GetAttribute(XlsxWorksheet.A_display);
- string rid = m_xmlReader.GetAttribute(XlsxWorksheet.A_rid);
- string location = m_xmlReader.GetAttribute("location"); // fragment identifier
+ var parser = new XmlPackageParser(m_xmlReader, m_namespaceUri);
+ bool any = false;
+ foreach (XmlHyperlinkPackage linkPackage in parser.ParseHyperlinks()) {
+ any = true;
+ string aref = linkPackage.Ref;
+ string display = linkPackage.Display;
+ string rid = linkPackage.RelationshipId;
+ string location = linkPackage.Location;
string hyperlink = display;
if (!string.IsNullOrEmpty(rid) && hyperDict.ContainsKey(rid)) {
@@ -604,7 +508,6 @@ private bool ReadHyperLinks(XlsxWorksheet sheet, DataTable table) {
continue;
}
- // ref may be a single cell "A2" or a range "A3:A4"
var dim = new XlsxDimension(aref);
int c1 = dim.FirstCol - 1;
int r1 = dim.FirstRow - 1;
@@ -633,13 +536,12 @@ private bool ReadHyperLinks(XlsxWorksheet sheet, DataTable table) {
}
}
- // Close
m_xmlReader.Close();
if (m_sheetStream != null) {
m_sheetStream.Close();
}
- return true;
+ return any;
}
private bool IsDateTimeStyle(int styleId) {
@@ -805,11 +707,12 @@ private void Dispose(bool disposing) {
((IDisposable)m_xmlReader).Dispose();
if (m_sheetStream != null)
m_sheetStream.Dispose();
- if (m_package != null && m_ownsPackage)
- m_package.Dispose();
+ if (m_zipWorker != null && m_ownsZipWorker)
+ m_zipWorker.Dispose();
}
- m_package = null;
+ m_zipWorker = null;
+ m_rowPackages = null;
m_xmlReader = null;
m_sheetStream = null;
diff --git a/src/Exceltk/Reader/Package/BinaryPackage.cs b/src/Exceltk/Reader/Package/BinaryPackage.cs
new file mode 100644
index 0000000..49780bb
--- /dev/null
+++ b/src/Exceltk/Reader/Package/BinaryPackage.cs
@@ -0,0 +1,23 @@
+using Exceltk.Reader.Binary;
+
+namespace Exceltk.Reader.Package {
+ ///
+ /// One BIFF record as a streamed package entity.
+ ///
+ internal sealed class BinaryPackage : IPackage {
+ public BinaryPackage(XlsBiffRecord record) {
+ Record = record;
+ }
+
+ public XlsBiffRecord Record {
+ get;
+ private set;
+ }
+
+ public BIFFRECORDTYPE Id {
+ get {
+ return Record.ID;
+ }
+ }
+ }
+}
diff --git a/src/Exceltk/Reader/Package/IExcelPackage.cs b/src/Exceltk/Reader/Package/IExcelPackage.cs
deleted file mode 100644
index e79bbe8..0000000
--- a/src/Exceltk/Reader/Package/IExcelPackage.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-
-namespace Exceltk.Reader.Package {
- ///
- /// Opened workbook container (ZIP package, OLE compound file, or plain file).
- /// Parsers read workbook content through this abstraction.
- ///
- public interface IExcelPackage : IDisposable {
- bool IsValid {
- get;
- }
-
- string ExceptionMessage {
- get;
- }
- }
-}
diff --git a/src/Exceltk/Reader/Package/IOpenXmlPackage.cs b/src/Exceltk/Reader/Package/IOpenXmlPackage.cs
deleted file mode 100644
index f52768c..0000000
--- a/src/Exceltk/Reader/Package/IOpenXmlPackage.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.IO;
-
-namespace Exceltk.Reader.Package {
- ///
- /// OpenXML (.xlsx) package: ZIP parts for workbook, sheets, shared strings, and styles.
- ///
- public interface IOpenXmlPackage : IExcelPackage {
- Stream GetSharedStringsStream();
- Stream GetStylesStream();
- Stream GetWorkbookStream();
- Stream GetWorkbookRelsStream();
- Stream GetWorksheetStream(string sheetPath);
- Stream GetWorksheetRelsStream(string sheetPath);
- }
-}
diff --git a/src/Exceltk/Reader/Package/IPackage.cs b/src/Exceltk/Reader/Package/IPackage.cs
new file mode 100644
index 0000000..2fa1b30
--- /dev/null
+++ b/src/Exceltk/Reader/Package/IPackage.cs
@@ -0,0 +1,8 @@
+namespace Exceltk.Reader.Package {
+ ///
+ /// A parsed semantic unit emitted by a streaming package parser.
+ /// Not a file container — binary records and XML elements are packages.
+ ///
+ public interface IPackage {
+ }
+}
diff --git a/src/Exceltk/Reader/Package/IPathPackage.cs b/src/Exceltk/Reader/Package/IPathPackage.cs
deleted file mode 100644
index 368d2fe..0000000
--- a/src/Exceltk/Reader/Package/IPathPackage.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Exceltk.Reader.Package {
- ///
- /// Package identified by a filesystem path (e.g. CSV).
- ///
- public interface IPathPackage : IExcelPackage {
- string Path {
- get;
- }
- }
-}
diff --git a/src/Exceltk/Reader/Package/IStreamPackage.cs b/src/Exceltk/Reader/Package/IStreamPackage.cs
deleted file mode 100644
index 9fb178c..0000000
--- a/src/Exceltk/Reader/Package/IStreamPackage.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.IO;
-
-namespace Exceltk.Reader.Package {
- ///
- /// Package that exposes a single content stream (binary .xls or similar).
- ///
- public interface IStreamPackage : IExcelPackage {
- Stream Content {
- get;
- }
- }
-}
diff --git a/src/Exceltk/Reader/Package/PathPackage.cs b/src/Exceltk/Reader/Package/PathPackage.cs
deleted file mode 100644
index 165905c..0000000
--- a/src/Exceltk/Reader/Package/PathPackage.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using System.IO;
-
-namespace Exceltk.Reader.Package {
- ///
- /// Package that points at a file path without loading the whole file into memory.
- ///
- public sealed class PathPackage : IPathPackage {
- public PathPackage(string path) {
- if (string.IsNullOrEmpty(path)) {
- throw new ArgumentException("path");
- }
- Path = path;
- if (File.Exists(path)) {
- IsValid = true;
- ExceptionMessage = null;
- } else {
- IsValid = false;
- ExceptionMessage = "File not found: " + path;
- }
- }
-
- public string Path {
- get;
- private set;
- }
-
- public bool IsValid {
- get;
- private set;
- }
-
- public string ExceptionMessage {
- get;
- private set;
- }
-
- public void Dispose() {
- // Nothing to release; path is metadata only.
- }
- }
-}
diff --git a/src/Exceltk/Reader/Package/StreamPackage.cs b/src/Exceltk/Reader/Package/StreamPackage.cs
deleted file mode 100644
index 84b8d9a..0000000
--- a/src/Exceltk/Reader/Package/StreamPackage.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-using System.IO;
-
-namespace Exceltk.Reader.Package {
- ///
- /// Thin package wrapper around an already-opened content stream.
- ///
- public sealed class StreamPackage : IStreamPackage {
- private readonly bool m_ownsStream;
- private bool m_disposed;
-
- public StreamPackage(Stream content, bool ownsStream = true) {
- if (content == null) {
- throw new ArgumentNullException("content");
- }
- Content = content;
- m_ownsStream = ownsStream;
- IsValid = true;
- ExceptionMessage = null;
- }
-
- public Stream Content {
- get;
- private set;
- }
-
- public bool IsValid {
- get;
- private set;
- }
-
- public string ExceptionMessage {
- get;
- private set;
- }
-
- public void Dispose() {
- if (m_disposed) {
- return;
- }
- m_disposed = true;
- if (m_ownsStream && Content != null) {
- Content.Dispose();
- Content = null;
- }
- }
- }
-}
diff --git a/src/Exceltk/Reader/Package/XmlPackage.cs b/src/Exceltk/Reader/Package/XmlPackage.cs
new file mode 100644
index 0000000..1dccd0b
--- /dev/null
+++ b/src/Exceltk/Reader/Package/XmlPackage.cs
@@ -0,0 +1,99 @@
+using System.Collections.Generic;
+
+namespace Exceltk.Reader.Package {
+ ///
+ /// Base type for OpenXML worksheet semantic units streamed by XmlPackageParser.
+ ///
+ internal abstract class XmlPackage : IPackage {
+ }
+
+ internal sealed class XmlWorksheetStartPackage : XmlPackage {
+ public string NamespaceUri {
+ get;
+ set;
+ }
+ }
+
+ internal sealed class XmlDimensionPackage : XmlPackage {
+ public string Ref {
+ get;
+ set;
+ }
+ }
+
+ internal sealed class XmlCellPackage : XmlPackage {
+ public string Reference {
+ get;
+ set;
+ }
+
+ public string StyleId {
+ get;
+ set;
+ }
+
+ public string CellType {
+ get;
+ set;
+ }
+
+ public string Formula {
+ get;
+ set;
+ }
+
+ public string ValueText {
+ get;
+ set;
+ }
+ }
+
+ internal sealed class XmlRowPackage : XmlPackage {
+ public XmlRowPackage() {
+ Cells = new List();
+ }
+
+ /// 1-based row index from the r attribute, when present.
+ public string RowIndexAttribute {
+ get;
+ set;
+ }
+
+ public List Cells {
+ get;
+ private set;
+ }
+ }
+
+ internal sealed class XmlMergePackage : XmlPackage {
+ public string Ref {
+ get;
+ set;
+ }
+ }
+
+ internal sealed class XmlHyperlinkPackage : XmlPackage {
+ public string Ref {
+ get;
+ set;
+ }
+
+ public string Display {
+ get;
+ set;
+ }
+
+ public string RelationshipId {
+ get;
+ set;
+ }
+
+ public string Location {
+ get;
+ set;
+ }
+ }
+
+ internal sealed class XmlSheetDataEndPackage : XmlPackage {
+ }
+}
diff --git a/src/Exceltk/Reader/Parser/BinaryPackageParser.cs b/src/Exceltk/Reader/Parser/BinaryPackageParser.cs
index b505521..c50601d 100644
--- a/src/Exceltk/Reader/Parser/BinaryPackageParser.cs
+++ b/src/Exceltk/Reader/Parser/BinaryPackageParser.cs
@@ -1,24 +1,109 @@
using System;
+using System.Collections.Generic;
+using System.IO;
+using Exceltk.Reader.Binary;
using Exceltk.Reader.Package;
namespace Exceltk.Reader.Parser {
///
- /// Parses a binary (.xls) package via .
+ /// Streams entities (one BIFF record each) from a workbook stream.
///
- public sealed class BinaryPackageParser : IExcelPackageParser {
- public DataSet Parse(IExcelPackage package) {
- var streamPackage = package as IStreamPackage;
- if (streamPackage == null) {
- throw new ArgumentException("BinaryPackageParser requires IStreamPackage", "package");
+ internal sealed class BinaryPackageParser : XlsStream, IPackageParser {
+ private readonly byte[] m_bytes;
+ private readonly int m_size;
+ private readonly ExcelBinaryReader m_reader;
+ private int m_offset;
+
+ public BinaryPackageParser(XlsHeader hdr, uint streamStart, bool isMini, XlsRootDirectory rootDir,
+ ExcelBinaryReader reader)
+ : base(hdr, streamStart, isMini, rootDir) {
+ m_reader = reader;
+ m_bytes = base.ReadStream();
+ m_size = m_bytes.Length;
+ m_offset = 0;
+ }
+
+ public int Size {
+ get {
+ return m_size;
+ }
+ }
+
+ public int Position {
+ get {
+ return m_offset;
+ }
+ }
+
+ public void Seek(int offset, SeekOrigin origin) {
+ switch (origin) {
+ case SeekOrigin.Begin:
+ m_offset = offset;
+ break;
+ case SeekOrigin.Current:
+ m_offset += offset;
+ break;
+ case SeekOrigin.End:
+ m_offset = m_size - offset;
+ break;
+ }
+
+ if (m_offset < 0) {
+ string message = string.Format("{0} On offset={1}", Errors.ErrorBIFFIlegalBefore, offset);
+ throw new ArgumentOutOfRangeException(message);
+ }
+
+ if (m_offset > m_size) {
+ string message = string.Format("{0} On offset={1}", Errors.ErrorBIFFIlegalAfter, offset);
+ throw new ArgumentOutOfRangeException(message);
+ }
+ }
+
+ ///
+ /// Read the next BIFF record as a and advance the cursor.
+ ///
+ public BinaryPackage Read() {
+ if ((uint)m_offset >= m_bytes.Length) {
+ return null;
}
- if (!streamPackage.IsValid) {
+
+ XlsBiffRecord rec = XlsBiffRecord.GetRecord(m_bytes, (uint)m_offset, m_reader);
+ m_offset += rec.Size;
+
+ if (m_offset > m_size) {
return null;
}
- // ExcelBinaryReader.AsDataSet/Close dispose the stream; do not dispose again here.
- var reader = new ExcelBinaryReader();
- reader.Open(streamPackage.Content);
- return reader.AsDataSet();
+ return new BinaryPackage(rec);
+ }
+
+ ///
+ /// Read a record package at an absolute offset without moving the cursor.
+ ///
+ public BinaryPackage ReadAt(int offset) {
+ if ((uint)offset >= m_bytes.Length) {
+ return null;
+ }
+
+ XlsBiffRecord rec = XlsBiffRecord.GetRecord(m_bytes, (uint)offset, m_reader);
+
+ if (m_reader.ReadOption == ReadOption.Strict) {
+ if (offset + rec.Size > m_size) {
+ return null;
+ }
+ }
+
+ return new BinaryPackage(rec);
+ }
+
+ ///
+ /// Stream all remaining packages from the current cursor to the end.
+ ///
+ public IEnumerable Parse() {
+ BinaryPackage package;
+ while ((package = Read()) != null) {
+ yield return package;
+ }
}
}
}
diff --git a/src/Exceltk/Reader/Parser/CsvPackageParser.cs b/src/Exceltk/Reader/Parser/CsvPackageParser.cs
deleted file mode 100644
index d571b0b..0000000
--- a/src/Exceltk/Reader/Parser/CsvPackageParser.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-using Exceltk.Reader.Package;
-
-namespace Exceltk.Reader.Parser {
- ///
- /// Parses a CSV path package via .
- ///
- public sealed class CsvPackageParser : IExcelPackageParser {
- public DataSet Parse(IExcelPackage package) {
- var pathPackage = package as IPathPackage;
- if (pathPackage == null) {
- throw new ArgumentException("CsvPackageParser requires IPathPackage", "package");
- }
- if (!pathPackage.IsValid) {
- return null;
- }
- return CsvReader.AsDataSet(pathPackage.Path);
- }
- }
-}
diff --git a/src/Exceltk/Reader/Parser/ExcelPackageParserFactory.cs b/src/Exceltk/Reader/Parser/ExcelPackageParserFactory.cs
deleted file mode 100644
index 565bb43..0000000
--- a/src/Exceltk/Reader/Parser/ExcelPackageParserFactory.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.IO;
-using Exceltk.Reader.Package;
-
-namespace Exceltk.Reader.Parser {
- ///
- /// Creates the matching package + parser pair for a workbook path.
- ///
- public static class ExcelPackageParserFactory {
- public static IExcelPackage OpenPackage(string path) {
- string ext = Path.GetExtension(path);
- if (string.Equals(ext, ".csv", StringComparison.OrdinalIgnoreCase)) {
- return new PathPackage(path);
- }
- if (string.Equals(ext, ".xls", StringComparison.OrdinalIgnoreCase)) {
- Stream stream = File.Open(path, FileMode.Open, FileAccess.Read);
- return new StreamPackage(stream, ownsStream: true);
- }
- if (string.Equals(ext, ".xlsx", StringComparison.OrdinalIgnoreCase)) {
- Stream stream = File.Open(path, FileMode.Open, FileAccess.Read);
- var package = new ZipWorker();
- package.Extract(stream);
- return package;
- }
- throw new ArgumentException("Not Support Format: " + ext);
- }
-
- public static IExcelPackageParser CreateParser(string path) {
- string ext = Path.GetExtension(path);
- if (string.Equals(ext, ".csv", StringComparison.OrdinalIgnoreCase)) {
- return new CsvPackageParser();
- }
- if (string.Equals(ext, ".xls", StringComparison.OrdinalIgnoreCase)) {
- return new BinaryPackageParser();
- }
- if (string.Equals(ext, ".xlsx", StringComparison.OrdinalIgnoreCase)) {
- return new OpenXmlPackageParser();
- }
- throw new ArgumentException("Not Support Format: " + ext);
- }
-
- public static DataSet Load(string path) {
- using (IExcelPackage package = OpenPackage(path)) {
- IExcelPackageParser parser = CreateParser(path);
- return parser.Parse(package);
- }
- }
- }
-}
diff --git a/src/Exceltk/Reader/Parser/IExcelPackageParser.cs b/src/Exceltk/Reader/Parser/IExcelPackageParser.cs
deleted file mode 100644
index 8f1422d..0000000
--- a/src/Exceltk/Reader/Parser/IExcelPackageParser.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using Exceltk.Reader.Package;
-
-namespace Exceltk.Reader.Parser {
- ///
- /// Parses an into the shared model.
- ///
- public interface IExcelPackageParser {
- DataSet Parse(IExcelPackage package);
- }
-}
diff --git a/src/Exceltk/Reader/Parser/IPackageParser.cs b/src/Exceltk/Reader/Parser/IPackageParser.cs
new file mode 100644
index 0000000..0e2609f
--- /dev/null
+++ b/src/Exceltk/Reader/Parser/IPackageParser.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.IO;
+using Exceltk.Reader.Package;
+
+namespace Exceltk.Reader.Parser {
+ ///
+ /// Streaming parser: reads an input and yields package entities incrementally.
+ ///
+ public interface IPackageParser where TPackage : IPackage {
+ ///
+ /// Parse from the current position, yielding packages one at a time.
+ ///
+ IEnumerable Parse();
+ }
+}
diff --git a/src/Exceltk/Reader/Parser/OpenXmlPackageParser.cs b/src/Exceltk/Reader/Parser/OpenXmlPackageParser.cs
deleted file mode 100644
index d6dc315..0000000
--- a/src/Exceltk/Reader/Parser/OpenXmlPackageParser.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-using Exceltk.Reader.Package;
-
-namespace Exceltk.Reader.Parser {
- ///
- /// Parses an OpenXML (.xlsx) package via .
- ///
- public sealed class OpenXmlPackageParser : IExcelPackageParser {
- public DataSet Parse(IExcelPackage package) {
- var openXml = package as IOpenXmlPackage;
- if (openXml == null) {
- throw new ArgumentException("OpenXmlPackageParser requires IOpenXmlPackage", "package");
- }
- if (!openXml.IsValid) {
- return null;
- }
-
- var reader = new ExcelOpenXmlReader();
- try {
- reader.Open(openXml);
- return reader.AsDataSet();
- } finally {
- reader.Close();
- }
- }
- }
-}
diff --git a/src/Exceltk/Reader/Parser/XmlPackageParser.cs b/src/Exceltk/Reader/Parser/XmlPackageParser.cs
new file mode 100644
index 0000000..e4c33b5
--- /dev/null
+++ b/src/Exceltk/Reader/Parser/XmlPackageParser.cs
@@ -0,0 +1,203 @@
+using System.Collections.Generic;
+using System.Xml;
+using Exceltk.Reader.Package;
+using Exceltk.Reader.Xml;
+
+namespace Exceltk.Reader.Parser {
+ ///
+ /// Streams entities from an OpenXML worksheet XmlReader.
+ ///
+ internal sealed class XmlPackageParser : IPackageParser {
+ private readonly XmlReader m_reader;
+ private readonly string m_namespaceUri;
+
+ public XmlPackageParser(XmlReader reader, string namespaceUri = null) {
+ m_reader = reader;
+ m_namespaceUri = namespaceUri;
+ }
+
+ ///
+ /// Walk the worksheet document, yielding dimension / row / sheetData-end packages.
+ /// Caller should position at the start of the worksheet document.
+ ///
+ public IEnumerable Parse() {
+ while (m_reader.Read()) {
+ if (m_reader.NodeType != XmlNodeType.Element) {
+ continue;
+ }
+
+ if (m_reader.LocalName == XlsxWorksheet.N_worksheet) {
+ yield return new XmlWorksheetStartPackage {
+ NamespaceUri = m_reader.NamespaceURI
+ };
+ } else if (m_reader.LocalName == XlsxWorksheet.N_dimension) {
+ yield return new XmlDimensionPackage {
+ Ref = m_reader.GetAttribute(XlsxWorksheet.A_ref)
+ };
+ } else if (m_reader.LocalName == XlsxWorksheet.N_sheetData) {
+ if (m_reader.IsEmptyElement) {
+ yield return new XmlSheetDataEndPackage();
+ continue;
+ }
+ foreach (XmlPackage rowPackage in ParseRows()) {
+ yield return rowPackage;
+ }
+ yield return new XmlSheetDataEndPackage();
+ } else if (m_reader.LocalName == XlsxWorksheet.N_mergeCells) {
+ foreach (XmlMergePackage merge in ParseMergesFromCurrent()) {
+ yield return merge;
+ }
+ } else if (m_reader.LocalName == XlsxWorksheet.N_hyperlinks) {
+ foreach (XmlHyperlinkPackage link in ParseHyperlinksFromCurrent()) {
+ yield return link;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Stream row packages from the current sheetData element (or subsequent rows).
+ ///
+ public IEnumerable ParseRows() {
+ bool first = true;
+ while (true) {
+ bool isRow;
+ if (first && m_reader.NodeType == XmlNodeType.Element &&
+ m_reader.LocalName == XlsxWorksheet.N_sheetData) {
+ if (m_namespaceUri != null) {
+ isRow = m_reader.ReadToFollowing(XlsxWorksheet.N_row, m_namespaceUri);
+ } else {
+ isRow = m_reader.ReadToFollowing(XlsxWorksheet.N_row);
+ }
+ first = false;
+ } else {
+ if (m_reader.LocalName == XlsxWorksheet.N_row && m_reader.NodeType == XmlNodeType.EndElement) {
+ m_reader.Read();
+ }
+ isRow = (m_reader.NodeType == XmlNodeType.Element && m_reader.LocalName == XlsxWorksheet.N_row);
+ first = false;
+ }
+
+ if (!isRow) {
+ yield break;
+ }
+
+ yield return ReadCurrentRow();
+ }
+ }
+
+ public IEnumerable ParseMerges() {
+ if (!m_reader.ReadToFollowing(XlsxWorksheet.N_mergeCells)) {
+ yield break;
+ }
+ foreach (XmlMergePackage merge in ParseMergesFromCurrent()) {
+ yield return merge;
+ }
+ }
+
+ public IEnumerable ParseHyperlinks() {
+ if (!m_reader.ReadToFollowing(XlsxWorksheet.N_hyperlinks)) {
+ yield break;
+ }
+ foreach (XmlHyperlinkPackage link in ParseHyperlinksFromCurrent()) {
+ yield return link;
+ }
+ }
+
+ private IEnumerable ParseMergesFromCurrent() {
+ if (m_reader.IsEmptyElement) {
+ yield break;
+ }
+
+ while (m_reader.Read()) {
+ if (m_reader.NodeType != XmlNodeType.Element) {
+ if (m_reader.NodeType == XmlNodeType.EndElement &&
+ m_reader.LocalName == XlsxWorksheet.N_mergeCells) {
+ yield break;
+ }
+ continue;
+ }
+ if (m_reader.LocalName != XlsxWorksheet.N_mergeCell) {
+ yield break;
+ }
+ yield return new XmlMergePackage {
+ Ref = m_reader.GetAttribute(XlsxWorksheet.A_ref)
+ };
+ }
+ }
+
+ private IEnumerable ParseHyperlinksFromCurrent() {
+ if (m_reader.IsEmptyElement) {
+ yield break;
+ }
+
+ while (m_reader.Read()) {
+ if (m_reader.NodeType != XmlNodeType.Element) {
+ yield break;
+ }
+ if (m_reader.LocalName != XlsxWorksheet.N_hyperlink) {
+ yield break;
+ }
+ yield return new XmlHyperlinkPackage {
+ Ref = m_reader.GetAttribute(XlsxWorksheet.A_ref),
+ Display = m_reader.GetAttribute(XlsxWorksheet.A_display),
+ RelationshipId = m_reader.GetAttribute(XlsxWorksheet.A_rid),
+ Location = m_reader.GetAttribute("location")
+ };
+ }
+ }
+
+ private XmlRowPackage ReadCurrentRow() {
+ var row = new XmlRowPackage {
+ RowIndexAttribute = m_reader.GetAttribute(XlsxWorksheet.A_r)
+ };
+
+ string a_s = string.Empty;
+ string a_t = string.Empty;
+ string a_r = string.Empty;
+ string formula = null;
+ bool hasValue = false;
+ bool hasFormula = false;
+
+ while (m_reader.Read()) {
+ if (m_reader.Depth == 2) {
+ break;
+ }
+
+ if (m_reader.NodeType == XmlNodeType.Element) {
+ hasValue = false;
+ if (m_reader.LocalName == XlsxWorksheet.N_c) {
+ a_s = m_reader.GetAttribute(XlsxWorksheet.A_s);
+ a_t = m_reader.GetAttribute(XlsxWorksheet.A_t);
+ a_r = m_reader.GetAttribute(XlsxWorksheet.A_r);
+ formula = null;
+ } else if (m_reader.LocalName == XlsxWorksheet.N_f) {
+ hasFormula = true;
+ } else if (m_reader.LocalName == XlsxWorksheet.N_v || m_reader.LocalName == XlsxWorksheet.N_t) {
+ hasValue = true;
+ hasFormula = false;
+ }
+ }
+
+ if (m_reader.NodeType == XmlNodeType.Text && hasFormula) {
+ formula = m_reader.Value;
+ hasFormula = false;
+ }
+
+ if (m_reader.NodeType == XmlNodeType.Text && hasValue) {
+ row.Cells.Add(new XmlCellPackage {
+ Reference = a_r,
+ StyleId = a_s,
+ CellType = a_t,
+ Formula = formula,
+ ValueText = m_reader.Value
+ });
+ formula = null;
+ hasValue = false;
+ }
+ }
+
+ return row;
+ }
+ }
+}
diff --git a/src/Exceltk/Reader/WorkbookLoader.cs b/src/Exceltk/Reader/WorkbookLoader.cs
index f1d4d4a..5c1ad35 100644
--- a/src/Exceltk/Reader/WorkbookLoader.cs
+++ b/src/Exceltk/Reader/WorkbookLoader.cs
@@ -1,15 +1,38 @@
using System;
using System.IO;
-using Exceltk.Reader.Parser;
namespace Exceltk.Reader {
///
- /// Loads a workbook-like DataSet from .xls, .xlsx, or .csv via the
- /// package / package-parser pipeline.
+ /// Loads a workbook-like DataSet from .xls, .xlsx, or .csv.
+ /// Binary/XML formats are read via streaming package parsers internally.
///
public static class WorkbookLoader {
public static DataSet Load(string path) {
- return ExcelPackageParserFactory.Load(path);
+ string ext=Path.GetExtension(path);
+ if (string.Equals(ext, ".csv", StringComparison.OrdinalIgnoreCase)) {
+ return CsvReader.AsDataSet(path);
+ }
+
+ FileStream stream=File.Open(path, FileMode.Open, FileAccess.Read);
+ IExcelDataReader excelReader=null;
+ try {
+ if (string.Equals(ext, ".xls", StringComparison.OrdinalIgnoreCase)) {
+ excelReader=ExcelReaderFactory.CreateBinaryReader(stream);
+ } else if (string.Equals(ext, ".xlsx", StringComparison.OrdinalIgnoreCase)) {
+ excelReader=ExcelReaderFactory.CreateOpenXmlReader(stream);
+ } else {
+ stream.Close();
+ throw new ArgumentException("Not Support Format: "+ext);
+ }
+ DataSet dataSet=excelReader.AsDataSet();
+ return dataSet;
+ } finally {
+ if (excelReader!=null) {
+ excelReader.Close();
+ } else {
+ stream.Close();
+ }
+ }
}
public static bool IsSupportedExtension(string path) {
diff --git a/src/Exceltk/Reader/ZipWorker.cs b/src/Exceltk/Reader/ZipWorker.cs
index 5874b6d..f53e2e1 100644
--- a/src/Exceltk/Reader/ZipWorker.cs
+++ b/src/Exceltk/Reader/ZipWorker.cs
@@ -3,15 +3,14 @@
using System.Diagnostics;
using System.Globalization;
using System.IO;
-using Exceltk.Reader.Package;
using ICSharpCode.SharpZipLib.Zip;
namespace Exceltk.Reader {
///
- /// OpenXML ZIP package worker. Implements for the
- /// package / package-parser architecture.
+ /// OpenXML ZIP archive IO helper (file container). Not a semantic Package entity —
+ /// worksheet XML is streamed as XmlPackage by XmlPackageParser.
///
- public class ZipWorker : IOpenXmlPackage {
+ public class ZipWorker : IDisposable {
#region Members and Properties
private const string TMP="TMP_Z";