-
Notifications
You must be signed in to change notification settings - Fork 0
/
BasicExcel.hpp
1914 lines (1672 loc) · 63.2 KB
/
BasicExcel.hpp
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Created by Yap Chun Wei
// Version 1.0 (20 April 2006)
// Version 1.1 (22 April 2006)
// - Fixed bugs with compound files not being able to write files more than 65535 bytes.
// - Fixed bugs with reading and writing to Excel files containing many strings.
// Version 1.2 (30 April 2006)
// - Added operator<< to pass BasicExcelCell to an output stream.
// - Added Print() to BasicExcelWorksheet to print the worksheet to an output stream.
// - Change BasicExcelCell Get functions to const functions.
// - Rename BasicExcelWorksheet functions RenameWorkSheet() to Rename().
// Version 1.3 (10 May 2006)
// - Fixed bugs with reading from Excel files containing Asian characters.
// Version 1.4 (13 May 2006)
// - Fixed bugs with reading and writing to Excel files containing many strings.
// Version 1.5 (15 May 2006)
// - Remove code for ExtSST because it was causing problems with reading and writing to Excel files containing many strings.
// Version 1.6 (16 May 2006)
// - Optimized code for reading and writing.
// Version 1.7 (22 May 2006)
// - Fixed code to remove some warnings.
// - Fixed bug with BasicExcelWorksheet::Cell.
// - Fixed bug with BasicExcel::UpdateWorksheets().
// Version 1.8 (23 May 2006)
// - Fixed bug with reading Excel files containing many unicode strings.
// - Fixed code to remove some warnings.
// - Fixed variable code_ duplication in BoolErr.
// - Minor changes to BasicExcelCell:Set functions.
// Version 1.9 (24 May 2006)
// - Changed name_ in Style from SmallString to LargeString.
// - Fixed bug in BasicExcelCell::GetString and BasicExcelCell::GetWString.
// - Minor changes to functions in BasicExcel and BasicExcelWorksheet which checks for unicode.
// - Minor change to SmallString::Read.
// Version 1.10 (30 May 2006)
// - Fixed bug with reading Excel files containing many strings.
// - Remove memory leaks.
// Version 1.11 (2 June 2006)
// - Fixed bug with reading and writing Excel files containing many unicode and ANSI strings.
// Version 1.12 (6 June 2006)
// - Fixed bug with reading and writing Excel files containing many unicode and ANSI strings.
// Version 1.13 (1 August 2006)
// - Changed BasicExcelCell::Get() so that it will get a stored double as an integer or vice versa if necessary.
// - Changed BasicExcelCell::Get() so that it will not cause any errors if a string is empty.
// - Changed BasicExcelCell::SetString() and BasicExcelCell::SetWString() so that it will not save an empty string.
// Version 1.14 (6 August 2006)
// - Fixed bug with reading Excel files that contain a null string.
// Version 2.0 (September 2009, Martin Fuchs)
// - extended to maintain font and format information when reading and writing Excel sheets
// - XLSFormatManager, ExcelFont and CellFormat to edit fonts and formats
// Version 2.1 (04.10.2009, Martin Fuchs)
// - fixed memory leak in XLSFormatManager::get_font_idx()
// - define macros and constants for cell and font properties
// Version 2.2 (07.11.2009, Martin Fuchs)
// - fixed VS2008 problem when reading sheets with formula fields
// - added BasicExcel::Close()
// - added CellFormat::get/set_text_props() and get/set_borderlines()
// Version 2.3 (05.01.2010, Ami Castonguay/Martin Fuchs)
// - fixed reference counting of Formula data structs
// - support for shared formulas
// - support for merged cells
// - save formatting even if cell is empty
// - flush fstream instead of closing it followed by open to prevent races in conjunction with virus scanners
// - enable reading of XLS files exported by MacOS Numbers.app
// Version 2.4 (24.01.2010, Long Wenbiao/Martin Fuchs)
// - add second set_borderlines() overload
// - add ExcelFont::set_italic(), CellFormat::set_wrapping()
// - handle COLINFO
// - miscellaneous fixes
// Version 2.5 (01.01.2011, Martin Fuchs)
// - dynamically allocate memory for unexpected high row/column values
// - Unicode overloads for Load() and SaveAs()
// - adjust to RKValues written by OpenOffice Calc
// Version 3.0 (23.01.2011, Martin Fuchs)
// - portability fixes to enable using the code in 64 Bit development environments
// - in a Windows environment use the Windows API instead of the old CompoundFile class to access compound document files
// - reduced memory consumption in BasicExcel data handling
// - return current value string from formula cells
// - don't preserve empty rows/columns at the end of sheets
#pragma once
#ifndef BASICEXCEL_HPP
#define BASICEXCEL_HPP
//MF
#if defined(_MSC_VER) && _MSC_VER<=1200 // VC++ 6.0
#pragma warning(disable: 4786)
#define LONGINT __int64
#define LONGINT_CONST(x) x
#define COMPOUNDFILE
#else // newer Microsoft compilers
#define LONGINT long long
#define LONGINT_CONST(x) x##LL
#define COMPOUNDFILE CompoundFile::
#ifdef _DEBUG
//#define _ITERATOR_DEBUG_LEVEL 0 // speedup iterator operations while debugging
#endif
#endif
//MF type definitions of the Windows Compound Binary File Format (CBF) Specification
typedef unsigned char BYTE; // 8 bit unsigned integer
typedef unsigned short WORD; // 16 bit unsigned integer
typedef short SHORT; // 16 bit signed integer
typedef unsigned short USHORT; // 16 bit unsigned integer
#ifdef _MSC_VER
typedef unsigned long DWORD; // 32 bit unsigned integer
typedef long LONG; // 32 bit signed integer
typedef unsigned long ULONG; // 32 bit unsigned integer
#else
typedef unsigned int DWORD; // 32 bit unsigned integer
typedef int LONG; // 32 bit signed integer
typedef unsigned int ULONG; // 32 bit unsigned integer
#endif
typedef short OFFSET;
typedef ULONG SECT;
typedef ULONG FSINDEX;
typedef USHORT FSOFFSET;
typedef ULONG DFSIGNATURE;
typedef WORD DFPROPTYPE;
typedef ULONG CBF_SID; // renamed SID because of ambiguity with windows header files
#ifndef GUID_DEFINED
#define GUID_DEFINED
typedef struct _GUID {
ULONG Data1;
USHORT Data2;
USHORT Data3;
BYTE Data4[8];
} GUID;
#endif
typedef GUID CLSID; // 16 bytes
struct TIME_T { // FILETYPE
DWORD dwLowDateTime;
DWORD dwHighDateTime;
};
#define DIFSECT 0xFFFFFFFC
#define FATSECT 0xFFFFFFFD
#define ENDOFCHAIN 0xFFFFFFFE
#define FREESECT 0xFFFFFFFF
#ifndef _WIN32
enum STGTY {
STGTY_INVALID = 0,
STGTY_STORAGE = 1,
STGTY_STREAM = 2,
STGTY_LOCKBYTES = 3,
STGTY_PROPERTY = 4,
STGTY_ROOT = 5
};
#endif
enum DECOLOR {
DE_RED = 0,
DE_BLACK = 1
};
#if _MSC_VER>=1400 // VS 2005
//#define _CRT_SECURE_NO_WARNINGS //MF
//#define _SCL_SECURE_NO_WARNINGS //MF
#endif
#include <algorithm>
#include <cmath>
#include <functional>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <map>
#include <vector>
#include <string> //MF
using namespace std;
// get facet from locale for GCC
#ifndef _USE
#define _USE(loc, fac) use_facet<fac >(loc)
#endif
#include <assert.h> //MF
#ifndef _MSC_VER
#include <string.h>
#endif
#define UTF16
#ifdef UTF16
#define SIZEOFWCHAR_T 2
#else
#define SIZEOFWCHAR_T sizeof(wchar_t)
#endif
//MF string conversion functions
// Courtesy of Tom Widmer (VC++ MVP)
inline std::string narrow_string(const std::wstring& str)
{
std::string ret;
if (!str.empty()) {
ret.resize(str.length());
typedef std::ctype<wchar_t> CT;
CT const& ct = std::_USE(std::locale(), CT);
ct.narrow(&str[0], &*str.begin()+str.size(), '?', &ret[0]);
}
return ret;
}
inline std::wstring widen_string(const std::string& str)
{
std::wstring ret;
if (!str.empty()) {
ret.resize(str.length());
typedef std::ctype<wchar_t> CT;
CT const& ct = std::_USE(std::locale(), CT);
ct.widen(&str[0], &*str.begin()+str.size(), &ret[0]);
}
return ret;
}
#ifdef _WIN32
#include <objbase.h>
#pragma comment(lib, "ole32")
// MF
namespace WinCompFiles
{
enum CF_RESULT {
INVALID_SIZE = -6,
FILE_NOT_FOUND = -4,
DIRECTORY_NOT_EMPTY = -3,
DIRECTORY_NOT_FOUND = -2,
INVALID_PATH = -1,
SUCCESS = 1
};
struct CompoundFile
{
CompoundFile();
~CompoundFile();
// Compound File functions
bool Create(const wchar_t* filename);
bool Open(const wchar_t* filename, ios_base::openmode mode=ios_base::in|ios_base::out);
bool Close();
bool IsOpen();
// File functions
CF_RESULT MakeFile(const wchar_t* path);
CF_RESULT FileSize(const wchar_t* path, ULONGLONG& size);
CF_RESULT ReadFile(const wchar_t* path, char* data, ULONG size);
CF_RESULT ReadFile(const wchar_t* path, vector<char>&data);
CF_RESULT WriteFile(const wchar_t* path, const char* data, ULONG size);
CF_RESULT WriteFile(const wchar_t* path, const vector<char>&data, ULONG size);
// ANSI char functions
bool Create(const char* filename);
bool Open(const char* filename, ios_base::openmode mode=ios_base::in|ios_base::out);
CF_RESULT MakeFile(const char* path);
CF_RESULT FileSize(const char* path, ULONGLONG& size);
CF_RESULT ReadFile(const char* path, char* data, ULONG size);
CF_RESULT ReadFile(const char* path, vector<char>& data);
CF_RESULT WriteFile(const char* path, const char* data, ULONG size);
CF_RESULT WriteFile(const char* path, const vector<char>& data, ULONG size);
private:
IStorage* _pStg;
};
} // namespace WinCompFiles
#endif
namespace YCompoundFiles
{
struct LittleEndian
{
#if defined(_MSC_VER) && _MSC_VER<=1200 // VC++ 6.0
#define READWRITE(Type) \
static void Read(const char* buffer, Type& retVal, size_t pos=0, int bytes=0) \
{ \
retVal = Type(0); \
if (bytes == 0) bytes = sizeof(Type); \
for (size_t i=0; i<bytes; ++i) \
{ \
retVal |= ((Type)((unsigned char)buffer[pos+i])) << 8*i; \
} \
} \
static void ReadString(const char* buffer, Type* str, size_t pos=0, int bytes=0) \
{ \
for (size_t i=0; i<bytes; ++i) Read(buffer, str[i], pos+i*sizeof(Type)); \
} \
static void Write(char* buffer, Type val, size_t pos=0, int bytes=0) \
{ \
if (bytes == 0) bytes = sizeof(Type); \
for (size_t i=0; i<bytes; ++i) \
{ \
buffer[pos+i] = (unsigned char)val; \
val >>= 8; \
} \
} \
static void WriteString(char* buffer, Type* str, size_t pos=0, int bytes=0) \
{ \
for (size_t i=0; i<bytes; ++i) Write(buffer, str[i], pos+i*sizeof(Type)); \
} \
static void Read(const vector<char>& buffer, Type& retVal, size_t pos=0, int bytes=0) \
{ \
retVal = Type(0); \
if (bytes == 0) bytes = sizeof(Type); \
for (size_t i=0; i<bytes; ++i) \
{ \
retVal |= ((Type)((unsigned char)buffer[pos+i])) << 8*i; \
} \
} \
static void ReadString(const vector<char>& buffer, Type* str, size_t pos=0, int bytes=0) \
{ \
for (size_t i=0; i<bytes; ++i) Read(buffer, str[i], pos+i*sizeof(Type)); \
} \
static void Write(vector<char>& buffer, Type val, size_t pos=0, int bytes=0) \
{ \
if (bytes == 0) bytes = sizeof(Type); \
for (size_t i=0; i<bytes; ++i) \
{ \
buffer[pos+i] = (unsigned char)val; \
val >>= 8; \
} \
} \
static void WriteString(vector<char>& buffer, Type* str, size_t pos=0, int bytes=0) \
{ \
for (size_t i=0; i<bytes; ++i) Write(buffer, str[i], pos+i*sizeof(Type)); \
} \
READWRITE(char)
READWRITE(unsigned char)
READWRITE(short)
READWRITE(int)
READWRITE(unsigned int)
READWRITE(long)
READWRITE(unsigned long)
READWRITE(__int64)
READWRITE(unsigned __int64)
#undef READWRITE
static void Read(const char* buffer, wchar_t& retVal, size_t pos=0, int bytes=0)
{
retVal = wchar_t(0);
if (bytes == 0)
bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i)
retVal |= ((wchar_t)((unsigned char)buffer[pos+i])) << 8*i;
}
static void ReadString(const char* buffer, wchar_t* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i)
Read(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Write(char* buffer, wchar_t val, size_t pos=0, int bytes=0)
{
if (bytes == 0)
bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i) {
buffer[pos+i] = (unsigned char)val;
val >>= 8;
}
}
static void WriteString(char* buffer, wchar_t* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i)
Write(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Read(const vector<char>& buffer, wchar_t& retVal, size_t pos=0, int bytes=0)
{
retVal = wchar_t(0);
if (bytes == 0) bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i)
{
if (pos+i < buffer.size()) //MF
retVal |= ((wchar_t)((unsigned char)buffer[pos+i])) << 8*i;
}
}
static void ReadString(const vector<char>& buffer, wchar_t* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i) Read(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Write(vector<char>& buffer, wchar_t val, size_t pos=0, int bytes=0)
{
if (bytes == 0)
bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i) {
buffer[pos+i] = (unsigned char)val;
val >>= 8;
}
}
static void WriteString(vector<char>& buffer, wchar_t* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i)
Write(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
#else
template<typename Type>
static void Read(const char* buffer, Type& retVal, size_t pos=0, int bytes=0)
{
retVal = Type(0);
if (bytes == 0)
bytes = sizeof(Type);
for (int i=0; i<bytes; ++i)
retVal |= ((Type)((unsigned char)buffer[pos+i])) << 8*i;
}
template<typename Type>
static void ReadString(const char* buffer, Type* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i)
Read(buffer, str[i], pos+i*sizeof(Type));
}
template<typename Type>
static void Write(char* buffer, Type val, size_t pos=0, int bytes=0)
{
if (bytes == 0)
bytes = sizeof(Type);
for (int i=0; i<bytes; ++i) {
buffer[pos+i] = (unsigned char)val;
val >>= 8;
}
}
template<typename Type>
static void WriteString(char* buffer, Type* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i)
Write(buffer, str[i], pos+i*sizeof(Type));
}
template<typename Type>
static void Read(const vector<char>& buffer, Type& retVal, size_t pos=0, int bytes=0)
{
retVal = Type(0);
if (bytes == 0)
bytes = sizeof(Type);
for (int i=0; i<bytes; ++i)
retVal |= ((Type)((unsigned char)buffer[pos+i])) << 8*i;
}
template<typename Type>
static void ReadString(const vector<char>& buffer, Type* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i)
Read(buffer, str[i], pos+i*sizeof(Type));
}
template<typename Type>
static void Write(vector<char>& buffer, Type val, size_t pos=0, int bytes=0)
{
if (bytes == 0)
bytes = sizeof(Type);
for (int i=0; i<bytes; ++i) {
buffer[pos+i] = (unsigned char)val;
val >>= 8;
}
}
template<typename Type>
static void WriteString(vector<char>& buffer, Type* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i) Write(buffer, str[i], pos+i*sizeof(Type));
}
static void Read(const char* buffer, wchar_t& retVal, size_t pos=0, int bytes=0)
{
retVal = wchar_t(0);
if (bytes == 0)
bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i)
retVal |= ((wchar_t)((unsigned char)buffer[pos+i])) << 8*i;
}
static void ReadString(const char* buffer, wchar_t* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i)
Read(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Write(char* buffer, wchar_t val, size_t pos=0, int bytes=0)
{
if (bytes == 0)
bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i) {
buffer[pos+i] = (unsigned char)val;
val >>= 8;
}
}
static void WriteString(char* buffer, wchar_t* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i) Write(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Read(const vector<char>& buffer, wchar_t& retVal, size_t pos=0, int bytes=0)
{
retVal = wchar_t(0);
if (bytes == 0)
bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i) {
if (pos+i < (int)buffer.size()) //MF
retVal |= ((wchar_t)((unsigned char)buffer[pos+i])) << 8*i;
}
}
static void ReadString(const vector<char>& buffer, wchar_t* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i) Read(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
static void Write(vector<char>& buffer, wchar_t val, size_t pos=0, int bytes=0)
{
if (bytes == 0)
bytes = SIZEOFWCHAR_T;
for (int i=0; i<bytes; ++i) {
buffer[pos+i] = (unsigned char)val;
val >>= 8;
}
}
static void WriteString(vector<char>& buffer, wchar_t* str, size_t pos=0, int bytes=0)
{
for (int i=0; i<bytes; ++i)
Write(buffer, str[i], pos+i*SIZEOFWCHAR_T);
}
#endif
};
#ifndef _WIN32
class Block
// PURPOSE: In charge of handling blocks of data from a file
{
public:
Block();
// File handling functions
bool Create(const wchar_t* filename);
bool Open(const wchar_t* filename, ios_base::openmode mode=ios_base::in | ios_base::out);
bool Close();
bool IsOpen();
// Block handling functions
bool Read(SECT index, char* block);
bool Write(SECT index, const char* block);
bool Swap(SECT index1, SECT index2);
bool Move(SECT from, SECT to);
bool Insert(SECT index, const char* block);
bool Erase(SECT index);
bool Erase(vector<SECT>& indices);
// Misc functions
ULONG GetBlockSize() const {return blockSize_;}
void SetBlockSize(ULONG size)
{
blockSize_ = size;
indexEnd_ = fileSize_/blockSize_ + (fileSize_%blockSize_? 1: 0);
}
protected:
vector<char> filename_;
ios_base::openmode mode_;
fstream file_;
ULONG blockSize_;
SECT indexEnd_;
ULONG fileSize_;
};
enum {
DUPLICATE_PROPERTY=-6,
NAME_TOO_LONG=-5, FILE_NOT_FOUND=-4,
DIRECTORY_NOT_EMPTY=-3, DIRECTORY_NOT_FOUND=-2,
INVALID_PATH=-1,
SUCCESS=1
};
class CompoundFile
{
public:
CompoundFile();
~CompoundFile();
// User accessible functions
public:
// Compound File functions
bool Create(const wchar_t* filename);
bool Open(const wchar_t* filename, ios_base::openmode mode=ios_base::in | ios_base::out);
bool Close();
bool IsOpen();
// Directory functions
int ChangeDirectory(const wchar_t* path);
int MakeDirectory(const wchar_t* path);
// File functions
int MakeFile(const wchar_t* path);
int FileSize(const wchar_t* path, ULONG& size);
int ReadFile(const wchar_t* path, char* data);
int ReadFile(const wchar_t* path, vector<char>&data);
int WriteFile(const wchar_t* path, const char* data, ULONG size);
int WriteFile(const wchar_t* path, const vector<char>&data, ULONG size);
// ANSI char functions
bool Create(const char* filename);
bool Open(const char* filename, ios_base::openmode mode=ios_base::in | ios_base::out);
int ChangeDirectory(const char* path);
int MakeDirectory(const char* path);
int MakeFile(const char* path);
int FileSize(const char* path, ULONG& size);
int ReadFile(const char* path, char* data);
int ReadFile(const char* path, vector<char>& data);
int WriteFile(const char* path, const char* data, ULONG size);
int WriteFile(const char* path, const vector<char>& data, ULONG size);
// Protected functions and data members
protected:
// General functions and data members
void IncreaseLocationReferences(vector<SECT> indices);
void DecreaseLocationReferences(vector<SECT> indices);
void SplitPath(const wchar_t* path, wchar_t*& parentpath, wchar_t*& propertyname);
vector<char> block_;
Block file_;
// Header related functions and data members
bool LoadHeader();
void SaveHeader();
class Header
{
public:
Header();
void Write(char* block);
void Read(char* block);
LONGINT _abSig; // 0x0000 Magic number identifying this as a compound file system
CLSID _clid; // 0x0008 class id (set with WriteClassStgm retrieved with GetClassFile/ReadClassStg)
USHORT _ulMinorVersion; // 0x0018 minor version of the format: 33 is written by reference implementation
USHORT _uDllVersion; // 0x001A major version of the dll/format: 3 is written by reference implementation
USHORT _uByteOrder; // 0x001C 0xFFFE: indicates Intel byte ordering
USHORT _uSectorShift; // 0x001E size of sectors in power-of-two, typically 9, indicating 512-byte sectors
USHORT _uMiniSectorShift; // 0x0020 size of mini-sectors in power-of-two, typically 67, indicating 64-byte mini-sectors
USHORT _usReserved; // 0x0022 reserved, must be zero
ULONG _ulReserved1; // 0x0024 reserved, must be zero
ULONG _ulReserved2; // 0x0028 reserved, must be zero
FSINDEX _csectFat; // 0x002C number of SECTs in the FAT chain / "Number of elements in the BAT array"
SECT _sectDirStat; // 0x0030 first SECT in the directory chain / "Block index of the first block of the property table"
DFSIGNATURE _signature; // 0x0034 signature used for transactioning: must be zero, not supported by reference implementation
ULONG _ulMiniSectorCutOff;// 0x0038 maximum size for mini-streams: typically 4096 bytes
SECT _sectMiniFatStart; // 0x003C first SECT in the mini-FAT chain / "Block index of first big block containing the small block allocation table (SBAT)"
FSINDEX _csectMiniFat; // 0x0040 number of SECTs in the mini-FAT chain / "Number of big blocks holding the SBAT"
SECT _sectDifStart; // 0x0044 first SECT in the DIFG chain / "Block index of the first block in the Extended Block Allocation Table (XBAT)"
FSINDEX _csectDif; // 0x0048 number of SECTs in the DIF chain / "Number of elements in the Extended Block Allocation Table (to be added to the BAT)"
SECT _sectFat[109]; // 0x004C..0x01FF the SECTs of the first 109 FAT sectors / "Array of block indices constituting the Block Allocation Table (BAT)"
ULONG bigBlockSize_;
ULONG smallBlockSize_;
private:
void Initialize();
};
Header header_;
// BAT related functions and data members
void LoadBAT();
void SaveBAT();
ULONG DataSize(SECT startIndex, bool isBig);
ULONG ReadData(SECT startIndex, char* data, bool isBig);
SECT WriteData(const char* data, ULONG size, SECT startIndex, bool isBig);
void GetBlockIndices(SECT startIndex, vector<SECT>& indices, bool isBig);
SECT GetFreeBlockIndex(bool isBig);
void ExpandBATArray(bool isBig);
void LinkBlocks(SECT from, SECT to, bool isBig);
void FreeBlocks(vector<SECT>& indices, bool isBig);
vector<SECT> blocksIndices_;
vector<SECT> sblocksIndices_;
// Properties related functions and data members
class DirectoryEntry // struct StructuredStorageDirectoryEntry
{
public:
DirectoryEntry();
void Write(char* block);
void Read(char* block);
friend bool operator==(const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs)
{
return (!wcscmp(lhs.name_, rhs.name_));
}
friend bool operator< (const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs)
{
size_t maxLen1 = wcslen(lhs.name_);
size_t maxLen2 = wcslen(rhs.name_);
if (maxLen1 < maxLen2) return true;
else if (maxLen1 > maxLen2) return false;
else
{
int result = wcscmp(lhs.name_, rhs.name_);
if (result <= 0) return true;
else return false;
}
}
friend bool operator!=(const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) {return !(lhs == rhs);}
friend bool operator> (const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) {return (rhs < lhs);}
friend bool operator<=(const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) {return !(rhs < lhs);}
friend bool operator>=(const COMPOUNDFILE DirectoryEntry& lhs, const COMPOUNDFILE DirectoryEntry& rhs) {return !(lhs < rhs);}
wchar_t name_[32]; // 0x00..0x3E the element name in Unicode, padded with zeros to fill the array / "A unicode null-terminated uncompressed 16bit string (lblocke the high bytes) containing the name of the property"
WORD _cb_namesize; // 0x40 length of the element name in characters, not bytes / "Number of characters in the NAME field"
BYTE _mse; // 0x42 type of object: value taken from the STGTY enumeration / "DirectoryEntry type (directory, file, or root) Byte 1 (directory), 2 (file), or 5 (root entry)"
BYTE _bflags; // 0x43 value taken form DECOLOR enumeration / "Node color"
CBF_SID _sidLeftSib; // 0x44 SID of the left-sibling of this entry in the directory tree / "Previous property index"
CBF_SID _sidRightSib; // 0x48 SID of the right-sibling of this entry in the directroy tree / "Next property index"
CBF_SID _sidChild; // 0x4C SID of the child acting as the root of all the children of this element (if _mse=STGTY_STORAGE) / "First child property index"
GUID _clsId; // 0x50 CLSID if this storage (if _mse=STGTY_STORAGE)
DWORD _dwUserFlags; // 0x60 user flags of this storage (if _mse=STGTY_STORAGE)
TIME_T _time[2]; // 0x64 create/modify time stamps (if _mse=STGTY_STORAGE)
SECT _sectStart; // 0x74 starting SECT of the stream (if _mse=STGTY_STORAGE) / "Starting block of the file, used as the first block in the file and the pointer to the next block from the BAT"
ULONG _ulSize; // 0x78 size of stream in bytes (if _mse=STGTY_STORAGE) / "Actual size of the file this property points to. (used to truncate the blocks to the real size)."
DFPROPTYPE _dptPropType; // 0x7C reserved for future use, must be zero
};
class PropertyTree
{
public:
PropertyTree();
~PropertyTree();
PropertyTree* parent_;
DirectoryEntry* self_;
SECT index_;
vector<PropertyTree*> children_;
};
void LoadProperties();
void SaveProperties();
int MakeProperty(const wchar_t* path, DirectoryEntry* property);
PropertyTree* FindProperty(SECT index);
PropertyTree* FindProperty(const wchar_t* path);
PropertyTree* FindProperty(PropertyTree* parentTree, wchar_t* name);
void InsertPropertyTree(PropertyTree* parentTree, DirectoryEntry* property, SECT index);
void DeletePropertyTree(PropertyTree* tree);
void UpdateChildrenIndices(PropertyTree* parentTree);
void IncreasePropertyReferences(PropertyTree* parentTree, SECT index);
void DecreasePropertyReferences(PropertyTree* parentTree, SECT index);
PropertyTree* propertyTrees_;
PropertyTree* currentDirectory_;
vector<DirectoryEntry*> dirEntries_;
vector<PropertyTree*> previousDirectories_;
};
#endif // _WIN32
} // namespace YCompoundFiles
// reference counting to implement smart pointers
namespace RefCount
{
// reference counter for SmartPtr managed objects
struct RefCnt
{
// On construction the reference counter is initialized with an usage count of 0.
RefCnt()
: _ref_cnt(0)
{
}
int _ref_cnt;
};
// reference counting smart pointer
template<typename T> struct SmartPtr
{
// default constructor
SmartPtr()
: _ptr(NULL)
{
}
// The initialized SmartPtr constructor increments the reference counter in struct RefCnt.
SmartPtr(T* p)
: _ptr(p)
{
if (p)
++_ptr->_ref_cnt;
}
// The copy constructor increments the reference counter.
SmartPtr(const SmartPtr& other)
: _ptr(other._ptr)
{
if (_ptr)
++_ptr->_ref_cnt;
}
// The destructor decreases the reference counter and
// frees the managed memory as the counter reaches zero.
~SmartPtr()
{
if (_ptr) {
if (!--_ptr->_ref_cnt)
delete _ptr;
}
}
// The assignment operator increments the reference counter.
SmartPtr& operator=(T* p)
{
if (_ptr) {
if (!--_ptr->_ref_cnt)
delete _ptr;
_ptr = NULL;
}
if (p) {
_ptr = p;
++_ptr->_ref_cnt;
}
return *this;
}
// operator bool() to check for non-empty smart pointers
operator bool() const {return _ptr != NULL;}
// operator!() to check for empty smart pointers
bool operator!() const {return !_ptr;}
// operator->() to access the managed objects
T* operator->() {return _ptr;}
const T* operator->() const {return _ptr;}
// Derefence pointed memory
T& operator*() {return *_ptr;}
const T& operator*() const {return *_ptr;}
private:
T* _ptr;
};
} // namespace RefCount
//MF
namespace ExcelFormat {
struct CellFormat;
}
namespace YExcel
{
using namespace YCompoundFiles;
#ifdef _WIN32
using namespace WinCompFiles;
#endif
struct CODE
{
enum { FORMULA=0x0006, //Token array and the result of a formula cell.
YEOF=0x000A, //End of a record block with leading BOF record.
CALCCOUNT=0x000C, //Maximum number of times the forumlas should be iteratively calculated
CALCMODE=0x000D, //Calculate formulas manually, automatically, or automatically except for multiple table operations
PRECISION=0x000E, //Whether formulas use the real cell values for calculation or the values displayed on the screen.
REFMODE=0x000F, //Method used to show cell addresses in formulas.
DELTA=0x0010, //Maximum change of the result to exit an iteration.
ITERATION=0x0011, //Whether iterations are allowed while calculating recursive formulas.
PROTECT=0x0012, //Whether worksheet or a workbook is protected against modification.
PASSWORD=0x0013, //16-bit hash value, calculated from the worksheet or workbook protection password.
HEADER=0x0014, //Page header string for the current worksheet.
FOOTER=0x0015, //Page footer string for the current worksheet.
EXTERNSHEET=0x0017, //List with indexes to SUPBOOK records
NAME=0x0018, //Name and token array of an internal defined name.
WINDOWPROTECT=0x0019, //Whether the window configuration of the document is protected.
SELECTION=0x001D, //Addresses of all selected cell ranges and position of the active cell for a pane in the current sheet.
DATEMODE=0x0022, //Base date for displaying date values.
EXTERNNAME=0x0023, //Name of an external defined name, name of an add-in function, a DDE item or an OLE object storage identifier.
LEFTMARGIN=0x0026, //Left page margin of the current worksheet.
RIGHTMARGIN=0x0027, //Right page margin of the current worksheet.
TOPMARGIN=0x0028, //Top page margin of the current worksheet.
BOTTOMMARGIN=0x0029, //Bottom page margin of current worksheet
PRINTHEADERS=0x002A, //Whether row and column headers (the areas with row numbers and column letters) will be printed.
PRINTGRIDLINES=0x002B, //Whether sheet grid lines will be printed.
FILEPASS=0x002F, //Information about the read/write password of the file.
FONT=0x0031, //Information about a used font, including character formatting.
TABLE=0x0036, //Information about a multiple operation table in the sheet.
CONTINUE=0x003C, //Continue from previous record
WINDOW1=0x003D, //General settings for the workbook global settings.
BACKUP=0x0040, //Make backup of file while saving?
PANE=0x0041, //Position of window panes.
CODEPAGE=0x0042, //Text encoding used to encode byte strings
DCONREF=0x0051,
DEFCOLWIDTH=0x0055, //Default column width for columns that do not have a specific width set
XCT=0x0059, //Number of immediately following CRN records.
CRN=0x005A, //Contents of an external cell or cell range.
FILESHARING=0x005B, //Information about write protection, for instance the write protection password.
WRITEACCESS=0x005C, //Name of the user that has saved the file.
UNCALCED=0x005E, //Formulas have not been recalculated before the document was saved.
SAVERECALC=0x005F, //"Recalculate before save" option
OBJECTPROTECT=0x0063, //Whether objects of the current sheet are protected.
COLINFO=0x007D, //Width for a given range of columns
GUTS=0x0080, //Layout of outline symbols.
WSBOOL=0x0081, //16-bit value with boolean options for the current sheet.
GRIDSET=0x0082, //Whether option to print sheet grid lines has ever been changed.
HCENTER=0x0083, //Sheet is centred horizontally when printed.
VCENTER=0x0084, //Whether sheet is centred vertically when printed.
BOUNDSHEET=0x0085, //Sheet inside of the workbook
WRITEPROT=0x0086, //Whether file is write protected.
COUNTRY=0x008C, //User interface language of the Excel version that has saved the file, system regional settings at the time the file was saved.
HIDEOBJ=0x008D, //Whether and how to show objects in the workbook.
SORT=0x0090, //Last settings from the "Sort" dialogue for each sheet.
PALETTE=0x0092, //Definition of all user-defined colours available for cell and object formatting.
SETUP=0x00A1, //Page format settings of the current sheet.
SHRFMLA=0x00BC, //Token array of a shared formula.
MULRK=0x00BD, //Cell range containing RK value cells. All cells are located in the same row.
MULBLANK=0x00BE, //Cell range of empty cells. All cells are located in the same row.
DBCELL=0x00D7, //Relative offsets to calculate stream position of the first cell record for each row.
BOOKBOOL=0x00DA, //Save values linked from external workbooks records and XCT records?
SCENPROTECT=0x00DD, //Whether scenarios of the current sheet are protected.
XF=0x00E0, //Formatting information for cells, rows, columns or styles.
MERGECELLS=0x00E5, //All merged cell ranges of the current sheet.
SST=0x00FC, //List of all strings used anywhere in the workbook.
LABELSST=0x00FD, //Cell that contains a string.
EXTSST=0x00FF, //Create a hash table with stream offsets to the SST record to optimise string search operations.
LABELRANGES=0x015F, //Addresses of all row and column label ranges in the current sheet.
USESELFS=0x0160, //Whether formulas in the workbook can use "natural language formulas".
DSF=0x0161, //Whether file contains an addition BIFF5/BIFF7 workbook stream.
SUPBOOK=0x01AE, //URL of an external document and a list of sheet names inside this document.
CONDFMT=0x01B0, //List of cell range addresses for all cells with equal conditional formatting.
CF=0x01B1, //Condition and the formatting attributes applied to the cells specified in the CONDFMT record, if the condition is met
DVAL=0x01B2, //List header of the data validity table in the current sheet.
HLINK=0x01B8, //One cell address or a cell range where all cells contain the same hyperlink.
DV=0x01BE, //Data validity settings and a list of cell ranges which contain these settings.
DIMENSIONS=0x0200, //Range address of the used area in the current sheet.
BLANK=0x0201, //Empty cell, contains cell address and formatting information
NUMBER=0x0203, //Cell that contains a floating-point value.
BOOLERR=0x0205, //Error value cell
STRING=0x0207, //Result of a string formula.
ROW=0x0208, //Properties of a single row in the sheet.
INDEX=0x020B, //Range of used rows and stream positions of several records of the current sheet.
ARRAY=0x0221, //Token array of an array formula
WINDOW2=0x023E, //Additional settings for the window of a specific worksheet.
RK=0x027E, //Cell that contains an RK value (encoded integer or floating point value).
STYLE=0x0293, //Name of a user-defined cell style or specific options for a built-in cell style.
FORMAT=0x041E, //Number format.
SHRFMLA1=0x04BC, //Token array of a shared formula (added).