zhao
2021-06-24 02ca96debc6056275d58e55d97f7885a195542d0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using HH.WMS.Utils.ExcelLibrary.CompoundDocumentFormat;
using HH.WMS.Utils.ExcelLibrary.SpreadSheet;
 
namespace HH.WMS.Utils.ExcelLibrary.BinaryFileFormat
{
    public class WorksheetDecoder
    {
        public static Worksheet Decode(Workbook book, Stream stream, SharedResource sharedResource)
        {
            Worksheet sheet = new Worksheet();
            sheet.Book = book;
            List<Record> records = ReadRecords(stream, out sheet.Drawing);
            sheet.Cells = PopulateCells(records, sharedResource);
            sheet.Book.Records.AddRange(records);
            return sheet;
        }
 
        private static List<Record> ReadRecords(Stream stream, out MSODRAWING drawingRecord)
        {
            List<Record> records = new List<Record>();
            drawingRecord = null;
            Record record = Record.Read(stream);
            Record last_record = record;
            Record last_formula_record = null;
            last_record.Decode();
            if (record is BOF && ((BOF)record).StreamType == StreamType.Worksheet)
            {
                while (record.Type != RecordType.EOF)
                {
                    if (record.Type == RecordType.CONTINUE)
                    {
                        last_record.ContinuedRecords.Add(record);
                    }
                    else
                    {
                        switch (record.Type)
                        {
                            case RecordType.STRING:
                                // jetcat_au: use last_formula_record instead of last_record
                                if (last_formula_record is FORMULA)
                                {
                                    record.Decode();
                                    (last_formula_record as FORMULA).StringRecord = record as STRING;
                                }
                                break;
                            case RecordType.MSODRAWING:
                                if (drawingRecord == null)
                                {
                                    drawingRecord = record as MSODRAWING;
                                    records.Add(record);
                                }
                                else
                                {
                                    drawingRecord.ContinuedRecords.Add(record);
                                }
                                break;
                            default:
                                records.Add(record);
                                break;
                        }
                        // jetcat_au: see 4.8 Array Formulas and Shared Formulas
                        if (record.Type == RecordType.FORMULA)
                        {
                            last_formula_record = record;
                        }
                        else if (record.Type != RecordType.SHRFMLA && record.Type != RecordType.ARRAY)
                        {
                            last_formula_record = null;
                        }
                        last_record = record;
                    }
                    record = Record.Read(stream);
                }
                records.Add(record);
            }
            return records;
        }
 
        private static CellCollection PopulateCells(List<Record> records, SharedResource sharedResource)
        {
            CellCollection cells = new CellCollection();
            cells.SharedResource = sharedResource;
            foreach (Record record in records)
            {
                record.Decode();
                switch (record.Type)
                {
                    //case RecordType.DIMENSIONS:
                    //    DIMENSIONS dimensions = record as DIMENSIONS;
                    //    cells.FirstRowIndex = dimensions.FirstRow;
                    //    cells.FirstColIndex = dimensions.FirstColumn;
                    //    cells.LastRowIndex = dimensions.LastRow-1;
                    //    cells.LastColIndex = dimensions.LastColumn-1;
                    //    break;
                    case RecordType.BOOLERR:
                        BOOLERR boolerr = record as BOOLERR;
                        cells.CreateCell(boolerr.RowIndex, boolerr.ColIndex, boolerr.GetValue(), boolerr.XFIndex);
                        break;
                    case RecordType.LABEL:
                        LABEL label = record as LABEL;
                        cells.CreateCell(label.RowIndex, label.ColIndex, label.Value, label.XFIndex);
                        break;
                    case RecordType.LABELSST:
                        LABELSST labelsst = record as LABELSST;
                        Cell cell = cells.CreateCell(labelsst.RowIndex, labelsst.ColIndex, sharedResource.GetStringFromSST(labelsst.SSTIndex), labelsst.XFIndex);
                        cell.Style.RichTextFormat = sharedResource.SharedStringTable.RichTextFormatting[labelsst.SSTIndex];
                        break;
                    case RecordType.NUMBER:
                        NUMBER number = record as NUMBER;
                        cells.CreateCell(number.RowIndex, number.ColIndex, number.Value, number.XFIndex);
                        break;
                    case RecordType.RK:
                        RK rk = record as RK;
                        cells.CreateCell(rk.RowIndex, rk.ColIndex, Record.DecodeRK(rk.Value), rk.XFIndex);
                        break;
                    case RecordType.MULRK:
                        MULRK mulrk = record as MULRK;
                        int row = mulrk.RowIndex;
                        for (int col = mulrk.FirstColIndex; col <= mulrk.LastColIndex; col++)
                        {
                            int index = col - mulrk.FirstColIndex;
                            object value = Record.DecodeRK(mulrk.RKList[index]);
                            int XFindex = mulrk.XFList[index];
                            cells.CreateCell(row, col, value, XFindex);
                        }
                        break;
                    case RecordType.FORMULA:
                        FORMULA formula = record as FORMULA;
                        cells.CreateCell(formula.RowIndex, formula.ColIndex, formula.DecodeResult(), formula.XFIndex);
                        break;
                }
            }
            return cells;
        }
 
        /*
         * Page 171 of the OpenOffice documentation of the Excel File Format
         * 
         * The font with index 4 is omitted in all BIFF versions. This means the first four fonts have zero-based indexes, 
         * and the fifth font and all following fonts are referenced with one-based indexes.
         */
        //public FONT getFontRecord(int index)
        private static FONT getFontRecord(SharedResource sharedResource, UInt16 index)
        {
            if (index >= 0 && index <= 3)
            {
                return sharedResource.Fonts[index];
            }
            else if (index >= 5)
            {
                return sharedResource.Fonts[index - 1];
            }
            else // index == 4 -> error
            {
                return null;
            }
        }
 
        /*
         * Sunil Shenoi, 8-25-2008
         * 
         * Assuming cell has a valid string vlaue, find the font record for a given characterIndex
         * into the stringValue of the cell
         */
        public static FONT getFontForCharacter(Cell cell, UInt16 charIndex)
        {
            FONT f = null;
 
            int index = cell.Style.RichTextFormat.CharIndexes.BinarySearch(charIndex);
            List<UInt16> fontIndexList = cell.Style.RichTextFormat.FontIndexes;
            
            if (index >= 0)
            {
                // found the object, return the font record
                f = getFontRecord(cell.SharedResource, fontIndexList[index]);
                //Console.WriteLine("for charIndex={0}, fontIndex={1})", charIndex, fontIndexList[index]);
                //Console.WriteLine("Object: {0} found at [{1}]", o, index);
            }
            else
            {
                // would have been inserted before the returned value, so insert just before it
                if (~index == 0)
                {
                    //f = getFontRecord(sheet,fontIndexList[0]);
                    //Console.WriteLine("for charIndex={0}, fontIndex=CELL", charIndex);
                }
                else
                {
                    f = getFontRecord(cell.SharedResource, fontIndexList[(~index) - 1]);
                    //Console.WriteLine("for charIndex={0}, fontIndex={1})", charIndex, fontIndexList[(~index) - 1]);
                }
                //Console.WriteLine("Object: {0} not found. "
                //   + "Next larger object found at [{1}].", o, ~index);
            }
 
            return f;
        }
    }
}