denyhosts/clamav/libclamav/xlm_extract.c

5001 lines
284 KiB
C

/*
* Extract XLM (Excel 4.0) macro source code for component MS Office Documents
*
* Copyright (C) 2020-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* Authors: Jonas Zaddach
*
* This code is partly based on and inspired by plugin_biff from ole_dump (Didier Stevens)
* https://github.com/DidierStevens/DidierStevensSuite/blob/master/plugin_biff.py
* plugin_biff.py is public domain without copyright.
*
* See https://www.loc.gov/preservation/digital/formats/digformatspecs/Excel97-2007BinaryFileFormat(xls)Specification.pdf .
* See https://www.openoffice.org/sc/excelfileformat.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include <fcntl.h>
#include <stdbool.h>
#include "fmap.h"
#include "entconv.h"
#include "xlm_extract.h"
#include "scanners.h"
#define min(x, y) (((x) < (y)) ? (x) : (y))
// clang-format off
const char *OPCODE_NAMES[] = {
NULL, //0
NULL, //1
NULL, //2
NULL, //3
NULL, //4
NULL, //5
"FORMULA : Cell Formula", //6
NULL, //7
NULL, //8
NULL, //9
"EOF : End of File", //10
NULL, //11
"CALCCOUNT : Iteration Count", //12
"CALCMODE : Calculation Mode", //13
"PRECISION : Precision", //14
"REFMODE : Reference Mode", //15
"DELTA : Iteration Increment", //16
"ITERATION : Iteration Mode", //17
"PROTECT : Protection Flag", //18
"PASSWORD : Protection Password", //19
"HEADER : Print Header on Each Page", //20
"FOOTER : Print Footer on Each Page", //21
"EXTERNCOUNT : Number of External References", //22
"EXTERNSHEET : External Reference", //23
"LABEL : Cell Value, String Constant", //24
"WINDOWPROTECT : Windows Are Protected", //25
"VERTICALPAGEBREAKS : Explicit Column Page Breaks", //26
"HORIZONTALPAGEBREAKS : Explicit Row Page Breaks", //27
"NOTE : Comment Associated with a Cell", //28
"SELECTION : Current Selection", //29
NULL, //30
NULL, //31
NULL, //32
NULL, //33
"1904 : 1904 Date System", //34
NULL, //35
NULL, //36
NULL, //37
"LEFTMARGIN : Left Margin Measurement", //38
"RIGHTMARGIN : Right Margin Measurement", //39
"TOPMARGIN : Top Margin Measurement", //40
"BOTTOMMARGIN : Bottom Margin Measurement", //41
"PRINTHEADERS : Print Row/Column Labels", //42
"PRINTGRIDLINES : Print Gridlines Flag", //43
NULL, //44
NULL, //45
NULL, //46
"FILEPASS : File Is Password-Protected", //47
NULL, //48
NULL, //49
NULL, //50
NULL, //51
NULL, //52
NULL, //53
NULL, //54
NULL, //55
NULL, //56
NULL, //57
NULL, //58
NULL, //59
"CONTINUE : Continues Long Records", //60
"WINDOW1 : Window Information", //61
NULL, //62
NULL, //63
"BACKUP : Save Backup Version of the File", //64
"PANE : Number of Panes and Their Position", //65
"CODEPAGE : Default Code Page", //66
NULL, //67
NULL, //68
NULL, //69
NULL, //70
NULL, //71
NULL, //72
NULL, //73
NULL, //74
NULL, //75
NULL, //76
"PLS : Environment-Specific Print Record", //77
NULL, //78
NULL, //79
"DCON : Data Consolidation Information", //80
"DCONREF : Data Consolidation References", //81
"DCONNAME : Data Consolidation Named References", //82
NULL, //83
NULL, //84
"DEFCOLWIDTH : Default Width for Columns", //85
NULL, //86
NULL, //87
NULL, //88
"XCT : CRN Record Count", //89
"CRN : Nonresident Operands", //90
"FILESHARING : File-Sharing Information", //91
"WRITEACCESS : Write Access User Name", //92
"OBJ : Describes a Graphic Object", //93
"UNCALCED : Recalculation Status", //94
"SAVERECALC : Recalculate Before Save", //95
"TEMPLATE : Workbook Is a Template", //96
NULL, //97
NULL, //98
"OBJPROTECT : Objects Are Protected", //99
NULL, //100
NULL, //101
NULL, //102
NULL, //103
NULL, //104
NULL, //105
NULL, //106
NULL, //107
NULL, //108
NULL, //109
NULL, //110
NULL, //111
NULL, //112
NULL, //113
NULL, //114
NULL, //115
NULL, //116
NULL, //117
NULL, //118
NULL, //119
NULL, //120
NULL, //121
NULL, //122
NULL, //123
NULL, //124
"COLINFO : Column Formatting Information", //125
"RK : Cell Value, RK Number", //126
"IMDATA : Image Data", //127
"GUTS : Size of Row and Column Gutters", //128
"WSBOOL : Additional Workspace Information", //129
"GRIDSET : State Change of Gridlines Option", //130
"HCENTER : Center Between Horizontal Margins", //131
"VCENTER : Center Between Vertical Margins", //132
"BOUNDSHEET : Sheet Information", //133
"WRITEPROT : Workbook Is Write-Protected", //134
"ADDIN : Workbook Is an Add-in Macro", //135
"EDG : Edition Globals", //136
"PUB : Publisher", //137
NULL, //138
NULL, //139
"COUNTRY : Default Country and WIN.INI Country", //140
"HIDEOBJ : Object Display Options", //141
NULL, //142
NULL, //143
"SORT : Sorting Options", //144
"SUB : Subscriber", //145
"PALETTE : Color Palette Definition", //146
NULL, //147
"LHRECORD : .WK? File Conversion Information", //148
"LHNGRAPH : Named Graph Information", //149
"SOUND : Sound Note", //150
NULL, //151
"LPR : Sheet Was Printed Using LINE.PRINT(", //152
"STANDARDWIDTH : Standard Column Width", //153
"FNGROUPNAME : Function Group Name", //154
"FILTERMODE : Sheet Contains Filtered List", //155
"FNGROUPCOUNT : Built-in Function Group Count", //156
"AUTOFILTERINFO : Drop-Down Arrow Count", //157
"AUTOFILTER : AutoFilter Data", //158
NULL, //159
"SCL : Window Zoom Magnification", //160
"SETUP : Page Setup", //161
NULL, //162
NULL, //163
NULL, //164
NULL, //165
NULL, //166
NULL, //167
NULL, //168
"COORDLIST : Polygon Object Vertex Coordinates", //169
NULL, //170
"GCW : Global Column-Width Flags", //171
NULL, //172
NULL, //173
"SCENMAN : Scenario Output Data", //174
"SCENARIO : Scenario Data", //175
"SXVIEW : View Definition", //176
"SXVD : View Fields", //177
"SXVI : View Item", //178
NULL, //179
"SXIVD : Row/Column Field IDs", //180
"SXLI : Line Item Array", //181
"SXPI : Page Item", //182
NULL, //183
"DOCROUTE : Routing Slip Information", //184
"RECIPNAME : Recipient Name", //185
NULL, //186
NULL, //187
"SHRFMLA : Shared Formula", //188
"MULRK : Multiple RK Cells", //189
"MULBLANK : Multiple Blank Cells", //190
NULL, //191
NULL, //192
"MMS : ADDMENU / DELMENU Record Group Count", //193
"ADDMENU : Menu Addition", //194
"DELMENU : Menu Deletion", //195
NULL, //196
"SXDI : Data Item", //197
"SXDB : PivotTable Cache Data", //198
NULL, //199
NULL, //200
NULL, //201
NULL, //202
NULL, //203
NULL, //204
"SXSTRING : String", //205
NULL, //206
NULL, //207
"SXTBL : Multiple Consolidation Source Info", //208
"SXTBRGIITM : Page Item Name Count", //209
"SXTBPG : Page Item Indexes", //210
"OBPROJ : Visual Basic Project", //211
NULL, //212
"SXIDSTM : Stream ID", //213
"RSTRING : Cell with Character Formatting", //214
"DBCELL : Stream Offsets", //215
NULL, //216
NULL, //217
"BOOKBOOL : Workbook Option Flag", //218
NULL, //219
"SXEXT : External Source Information", //220
"SCENPROTECT : Scenario Protection", //221
"OLESIZE : Size of OLE Object", //222
"UDDESC : Description String for Chart Autoformat", //223
"XF : Extended Format", //224
"INTERFACEHDR : Beginning of User Interface Records", //225
"INTERFACEEND : End of User Interface Records", //226
"SXVS : View Source", //227
NULL, //228
"MERGECELLS : Merged Cells", //229
NULL, //230
NULL, //231
NULL, //232
NULL, //233
"TABIDCONF : Sheet Tab ID of Conflict History", //234
"MSODRAWINGGROUP : Microsoft Office Drawing Group", //235
"MSODRAWING : Microsoft Office Drawing", //236
"MSODRAWINGSELECTION : Microsoft Office Drawing Selection", //237
NULL, //238
NULL, //239
"SXRULE : PivotTable Rule Data", //240
"SXEX : PivotTable View Extended Information", //241
"SXFILT : PivotTable Rule Filter", //242
NULL, //243
"SXDXF : Pivot Table Formatting", //244
"SXITM : Pivot Table Item Indexes", //245
"SXNAME : PivotTable Name", //246
"SXSELECT : PivotTable Selection Information", //247
"SXPAIR : PivotTable Name Pair", //248
"SXFMLA : Pivot Table Parsed Expression", //249
NULL, //250
"SXFORMAT : PivotTable Format Record", //251
"SST : Shared String Table", //252
"LABELSST : Cell Value, String Constant/ SST", //253
NULL, //254
"EXTSST : Extended Shared String Table", //255
"SXVDEX : Extended PivotTable View Fields", //256
NULL, //257
NULL, //258
"SXFORMULA : PivotTable Formula Record", //259
NULL, //260
NULL, //261
NULL, //262
NULL, //263
NULL, //264
NULL, //265
NULL, //266
NULL, //267
NULL, //268
NULL, //269
NULL, //270
NULL, //271
NULL, //272
NULL, //273
NULL, //274
NULL, //275
NULL, //276
NULL, //277
NULL, //278
NULL, //279
NULL, //280
NULL, //281
NULL, //282
NULL, //283
NULL, //284
NULL, //285
NULL, //286
NULL, //287
NULL, //288
NULL, //289
"SXDBEX : PivotTable Cache Data", //290
NULL, //291
NULL, //292
NULL, //293
NULL, //294
NULL, //295
NULL, //296
NULL, //297
NULL, //298
NULL, //299
NULL, //300
NULL, //301
NULL, //302
NULL, //303
NULL, //304
NULL, //305
NULL, //306
NULL, //307
NULL, //308
NULL, //309
NULL, //310
NULL, //311
NULL, //312
NULL, //313
NULL, //314
NULL, //315
NULL, //316
"TABID : Sheet Tab Index Array", //317
NULL, //318
NULL, //319
NULL, //320
NULL, //321
NULL, //322
NULL, //323
NULL, //324
NULL, //325
NULL, //326
NULL, //327
NULL, //328
NULL, //329
NULL, //330
NULL, //331
NULL, //332
NULL, //333
NULL, //334
NULL, //335
NULL, //336
NULL, //337
NULL, //338
NULL, //339
NULL, //340
NULL, //341
NULL, //342
NULL, //343
NULL, //344
NULL, //345
NULL, //346
NULL, //347
NULL, //348
NULL, //349
NULL, //350
NULL, //351
"USESELFS : Natural Language Formulas Flag", //352
"DSF : Double Stream File", //353
"XL5MODIFY : Flag for DSF", //354
NULL, //355
NULL, //356
NULL, //357
NULL, //358
NULL, //359
NULL, //360
NULL, //361
NULL, //362
NULL, //363
NULL, //364
NULL, //365
NULL, //366
NULL, //367
NULL, //368
NULL, //369
NULL, //370
NULL, //371
NULL, //372
NULL, //373
NULL, //374
NULL, //375
NULL, //376
NULL, //377
NULL, //378
NULL, //379
NULL, //380
NULL, //381
NULL, //382
NULL, //383
NULL, //384
NULL, //385
NULL, //386
NULL, //387
NULL, //388
NULL, //389
NULL, //390
NULL, //391
NULL, //392
NULL, //393
NULL, //394
NULL, //395
NULL, //396
NULL, //397
NULL, //398
NULL, //399
NULL, //400
NULL, //401
NULL, //402
NULL, //403
NULL, //404
NULL, //405
NULL, //406
NULL, //407
NULL, //408
NULL, //409
NULL, //410
NULL, //411
NULL, //412
NULL, //413
NULL, //414
NULL, //415
NULL, //416
NULL, //417
NULL, //418
NULL, //419
NULL, //420
"FILESHARING2 : File-Sharing Information for Shared Lists", //421
NULL, //422
NULL, //423
NULL, //424
"USERBVIEW : Workbook Custom View Settings", //425
"USERSVIEWBEGIN : Custom View Settings", //426
"USERSVIEWEND : End of Custom View Records", //427
NULL, //428
"QSI : External Data Range", //429
"SUPBOOK : Supporting Workbook", //430
"PROT4REV : Shared Workbook Protection Flag", //431
"CONDFMT : Conditional Formatting Range Information", //432
"CF : Conditional Formatting Conditions", //433
"DVAL : Data Validation Information", //434
NULL, //435
NULL, //436
"DCONBIN : Data Consolidation Information", //437
"TXO : Text Object", //438
"REFRESHALL : Refresh Flag", //439
"HLINK : Hyperlink", //440
NULL, //441
NULL, //442
"SXFDBTYPE : SQL Datatype Identifier", //443
"PROT4REVPASS : Shared Workbook Protection Password", //444
NULL, //445
"DV : Data Validation Criteria", //446
NULL, //447
"EXCEL9FILE : Excel 9 File", //448
"RECALCID : Recalc Information", //449
NULL, //450
NULL, //451
NULL, //452
NULL, //453
NULL, //454
NULL, //455
NULL, //456
NULL, //457
NULL, //458
NULL, //459
NULL, //460
NULL, //461
NULL, //462
NULL, //463
NULL, //464
NULL, //465
NULL, //466
NULL, //467
NULL, //468
NULL, //469
NULL, //470
NULL, //471
NULL, //472
NULL, //473
NULL, //474
NULL, //475
NULL, //476
NULL, //477
NULL, //478
NULL, //479
NULL, //480
NULL, //481
NULL, //482
NULL, //483
NULL, //484
NULL, //485
NULL, //486
NULL, //487
NULL, //488
NULL, //489
NULL, //490
NULL, //491
NULL, //492
NULL, //493
NULL, //494
NULL, //495
NULL, //496
NULL, //497
NULL, //498
NULL, //499
NULL, //500
NULL, //501
NULL, //502
NULL, //503
NULL, //504
NULL, //505
NULL, //506
NULL, //507
NULL, //508
NULL, //509
NULL, //510
NULL, //511
"DIMENSIONS : Cell Table Size", //512
"BLANK : Cell Value, Blank Cell", //513
NULL, //514
"NUMBER : Cell Value, Floating-Point Number", //515
"LABEL : Cell Value, String Constant", //516
"BOOLERR : Cell Value, Boolean or Error", //517
NULL, //518
"STRING : String Value of a Formula", //519
"ROW : Describes a Row", //520
NULL, //521
NULL, //522
"INDEX : Index Record", //523
NULL, //524
NULL, //525
NULL, //526
NULL, //527
NULL, //528
NULL, //529
NULL, //530
NULL, //531
NULL, //532
NULL, //533
NULL, //534
NULL, //535
"NAME : Defined Name", //536
NULL, //537
NULL, //538
NULL, //539
NULL, //540
NULL, //541
NULL, //542
NULL, //543
NULL, //544
"ARRAY : Array-Entered Formula", //545
NULL, //546
"EXTERNNAME : Externally Referenced Name", //547
NULL, //548
"DEFAULTROWHEIGHT : Default Row Height", //549
NULL, //550
NULL, //551
NULL, //552
NULL, //553
NULL, //554
NULL, //555
NULL, //556
NULL, //557
NULL, //558
NULL, //559
NULL, //560
"FONT : Font Description", //561
NULL, //562
NULL, //563
NULL, //564
NULL, //565
"TABLE : Data Table", //566
NULL, //567
NULL, //568
NULL, //569
NULL, //570
NULL, //571
NULL, //572
NULL, //573
"WINDOW2 : Sheet Window Information", //574
NULL, //575
NULL, //576
NULL, //577
NULL, //578
NULL, //579
NULL, //580
NULL, //581
NULL, //582
NULL, //583
NULL, //584
NULL, //585
NULL, //586
NULL, //587
NULL, //588
NULL, //589
NULL, //590
NULL, //591
NULL, //592
NULL, //593
NULL, //594
NULL, //595
NULL, //596
NULL, //597
NULL, //598
NULL, //599
NULL, //600
NULL, //601
NULL, //602
NULL, //603
NULL, //604
NULL, //605
NULL, //606
NULL, //607
NULL, //608
NULL, //609
NULL, //610
NULL, //611
NULL, //612
NULL, //613
NULL, //614
NULL, //615
NULL, //616
NULL, //617
NULL, //618
NULL, //619
NULL, //620
NULL, //621
NULL, //622
NULL, //623
NULL, //624
NULL, //625
NULL, //626
NULL, //627
NULL, //628
NULL, //629
NULL, //630
NULL, //631
NULL, //632
NULL, //633
NULL, //634
NULL, //635
NULL, //636
NULL, //637
NULL, //638
NULL, //639
NULL, //640
NULL, //641
NULL, //642
NULL, //643
NULL, //644
NULL, //645
NULL, //646
NULL, //647
NULL, //648
NULL, //649
NULL, //650
NULL, //651
NULL, //652
NULL, //653
NULL, //654
NULL, //655
NULL, //656
NULL, //657
NULL, //658
"STYLE : Style Information", //659
NULL, //660
NULL, //661
NULL, //662
NULL, //663
NULL, //664
NULL, //665
NULL, //666
NULL, //667
NULL, //668
NULL, //669
NULL, //670
NULL, //671
NULL, //672
NULL, //673
NULL, //674
NULL, //675
NULL, //676
NULL, //677
NULL, //678
NULL, //679
NULL, //680
NULL, //681
NULL, //682
NULL, //683
NULL, //684
NULL, //685
NULL, //686
NULL, //687
NULL, //688
NULL, //689
NULL, //690
NULL, //691
NULL, //692
NULL, //693
NULL, //694
NULL, //695
NULL, //696
NULL, //697
NULL, //698
NULL, //699
NULL, //700
NULL, //701
NULL, //702
NULL, //703
NULL, //704
NULL, //705
NULL, //706
NULL, //707
NULL, //708
NULL, //709
NULL, //710
NULL, //711
NULL, //712
NULL, //713
NULL, //714
NULL, //715
NULL, //716
NULL, //717
NULL, //718
NULL, //719
NULL, //720
NULL, //721
NULL, //722
NULL, //723
NULL, //724
NULL, //725
NULL, //726
NULL, //727
NULL, //728
NULL, //729
NULL, //730
NULL, //731
NULL, //732
NULL, //733
NULL, //734
NULL, //735
NULL, //736
NULL, //737
NULL, //738
NULL, //739
NULL, //740
NULL, //741
NULL, //742
NULL, //743
NULL, //744
NULL, //745
NULL, //746
NULL, //747
NULL, //748
NULL, //749
NULL, //750
NULL, //751
NULL, //752
NULL, //753
NULL, //754
NULL, //755
NULL, //756
NULL, //757
NULL, //758
NULL, //759
NULL, //760
NULL, //761
NULL, //762
NULL, //763
NULL, //764
NULL, //765
NULL, //766
NULL, //767
NULL, //768
NULL, //769
NULL, //770
NULL, //771
NULL, //772
NULL, //773
NULL, //774
NULL, //775
NULL, //776
NULL, //777
NULL, //778
NULL, //779
NULL, //780
NULL, //781
NULL, //782
NULL, //783
NULL, //784
NULL, //785
NULL, //786
NULL, //787
NULL, //788
NULL, //789
NULL, //790
NULL, //791
NULL, //792
NULL, //793
NULL, //794
NULL, //795
NULL, //796
NULL, //797
NULL, //798
NULL, //799
NULL, //800
NULL, //801
NULL, //802
NULL, //803
NULL, //804
NULL, //805
NULL, //806
NULL, //807
NULL, //808
NULL, //809
NULL, //810
NULL, //811
NULL, //812
NULL, //813
NULL, //814
NULL, //815
NULL, //816
NULL, //817
NULL, //818
NULL, //819
NULL, //820
NULL, //821
NULL, //822
NULL, //823
NULL, //824
NULL, //825
NULL, //826
NULL, //827
NULL, //828
NULL, //829
NULL, //830
NULL, //831
NULL, //832
NULL, //833
NULL, //834
NULL, //835
NULL, //836
NULL, //837
NULL, //838
NULL, //839
NULL, //840
NULL, //841
NULL, //842
NULL, //843
NULL, //844
NULL, //845
NULL, //846
NULL, //847
NULL, //848
NULL, //849
NULL, //850
NULL, //851
NULL, //852
NULL, //853
NULL, //854
NULL, //855
NULL, //856
NULL, //857
NULL, //858
NULL, //859
NULL, //860
NULL, //861
NULL, //862
NULL, //863
NULL, //864
NULL, //865
NULL, //866
NULL, //867
NULL, //868
NULL, //869
NULL, //870
NULL, //871
NULL, //872
NULL, //873
NULL, //874
NULL, //875
NULL, //876
NULL, //877
NULL, //878
NULL, //879
NULL, //880
NULL, //881
NULL, //882
NULL, //883
NULL, //884
NULL, //885
NULL, //886
NULL, //887
NULL, //888
NULL, //889
NULL, //890
NULL, //891
NULL, //892
NULL, //893
NULL, //894
NULL, //895
NULL, //896
NULL, //897
NULL, //898
NULL, //899
NULL, //900
NULL, //901
NULL, //902
NULL, //903
NULL, //904
NULL, //905
NULL, //906
NULL, //907
NULL, //908
NULL, //909
NULL, //910
NULL, //911
NULL, //912
NULL, //913
NULL, //914
NULL, //915
NULL, //916
NULL, //917
NULL, //918
NULL, //919
NULL, //920
NULL, //921
NULL, //922
NULL, //923
NULL, //924
NULL, //925
NULL, //926
NULL, //927
NULL, //928
NULL, //929
NULL, //930
NULL, //931
NULL, //932
NULL, //933
NULL, //934
NULL, //935
NULL, //936
NULL, //937
NULL, //938
NULL, //939
NULL, //940
NULL, //941
NULL, //942
NULL, //943
NULL, //944
NULL, //945
NULL, //946
NULL, //947
NULL, //948
NULL, //949
NULL, //950
NULL, //951
NULL, //952
NULL, //953
NULL, //954
NULL, //955
NULL, //956
NULL, //957
NULL, //958
NULL, //959
NULL, //960
NULL, //961
NULL, //962
NULL, //963
NULL, //964
NULL, //965
NULL, //966
NULL, //967
NULL, //968
NULL, //969
NULL, //970
NULL, //971
NULL, //972
NULL, //973
NULL, //974
NULL, //975
NULL, //976
NULL, //977
NULL, //978
NULL, //979
NULL, //980
NULL, //981
NULL, //982
NULL, //983
NULL, //984
NULL, //985
NULL, //986
NULL, //987
NULL, //988
NULL, //989
NULL, //990
NULL, //991
NULL, //992
NULL, //993
NULL, //994
NULL, //995
NULL, //996
NULL, //997
NULL, //998
NULL, //999
NULL, //1000
NULL, //1001
NULL, //1002
NULL, //1003
NULL, //1004
NULL, //1005
NULL, //1006
NULL, //1007
NULL, //1008
NULL, //1009
NULL, //1010
NULL, //1011
NULL, //1012
NULL, //1013
NULL, //1014
NULL, //1015
NULL, //1016
NULL, //1017
NULL, //1018
NULL, //1019
NULL, //1020
NULL, //1021
NULL, //1022
NULL, //1023
NULL, //1024
NULL, //1025
NULL, //1026
NULL, //1027
NULL, //1028
NULL, //1029
"FORMULA : Cell Formula", //1030
NULL, //1031
NULL, //1032
NULL, //1033
NULL, //1034
NULL, //1035
NULL, //1036
NULL, //1037
NULL, //1038
NULL, //1039
NULL, //1040
NULL, //1041
NULL, //1042
NULL, //1043
NULL, //1044
NULL, //1045
NULL, //1046
NULL, //1047
NULL, //1048
NULL, //1049
NULL, //1050
NULL, //1051
NULL, //1052
NULL, //1053
"FORMAT : Number Format", //1054
NULL, //1055
NULL, //1056
NULL, //1057
NULL, //1058
NULL, //1059
NULL, //1060
NULL, //1061
NULL, //1062
NULL, //1063
NULL, //1064
NULL, //1065
NULL, //1066
NULL, //1067
NULL, //1068
NULL, //1069
NULL, //1070
NULL, //1071
NULL, //1072
NULL, //1073
NULL, //1074
NULL, //1075
NULL, //1076
NULL, //1077
NULL, //1078
NULL, //1079
NULL, //1080
NULL, //1081
NULL, //1082
NULL, //1083
NULL, //1084
NULL, //1085
NULL, //1086
NULL, //1087
NULL, //1088
NULL, //1089
NULL, //1090
NULL, //1091
NULL, //1092
NULL, //1093
NULL, //1094
NULL, //1095
NULL, //1096
NULL, //1097
NULL, //1098
NULL, //1099
NULL, //1100
NULL, //1101
NULL, //1102
NULL, //1103
NULL, //1104
NULL, //1105
NULL, //1106
NULL, //1107
NULL, //1108
NULL, //1109
NULL, //1110
NULL, //1111
NULL, //1112
NULL, //1113
NULL, //1114
NULL, //1115
NULL, //1116
NULL, //1117
NULL, //1118
NULL, //1119
NULL, //1120
NULL, //1121
NULL, //1122
NULL, //1123
NULL, //1124
NULL, //1125
NULL, //1126
NULL, //1127
NULL, //1128
NULL, //1129
NULL, //1130
NULL, //1131
NULL, //1132
NULL, //1133
NULL, //1134
NULL, //1135
NULL, //1136
NULL, //1137
NULL, //1138
NULL, //1139
NULL, //1140
NULL, //1141
NULL, //1142
NULL, //1143
NULL, //1144
NULL, //1145
NULL, //1146
NULL, //1147
NULL, //1148
NULL, //1149
NULL, //1150
NULL, //1151
NULL, //1152
NULL, //1153
NULL, //1154
NULL, //1155
NULL, //1156
NULL, //1157
NULL, //1158
NULL, //1159
NULL, //1160
NULL, //1161
NULL, //1162
NULL, //1163
NULL, //1164
NULL, //1165
NULL, //1166
NULL, //1167
NULL, //1168
NULL, //1169
NULL, //1170
NULL, //1171
NULL, //1172
NULL, //1173
NULL, //1174
NULL, //1175
NULL, //1176
NULL, //1177
NULL, //1178
NULL, //1179
NULL, //1180
NULL, //1181
NULL, //1182
NULL, //1183
NULL, //1184
NULL, //1185
NULL, //1186
NULL, //1187
NULL, //1188
NULL, //1189
NULL, //1190
NULL, //1191
NULL, //1192
NULL, //1193
NULL, //1194
NULL, //1195
NULL, //1196
NULL, //1197
NULL, //1198
NULL, //1199
NULL, //1200
NULL, //1201
NULL, //1202
NULL, //1203
NULL, //1204
NULL, //1205
NULL, //1206
NULL, //1207
NULL, //1208
NULL, //1209
NULL, //1210
NULL, //1211
NULL, //1212
NULL, //1213
NULL, //1214
NULL, //1215
NULL, //1216
NULL, //1217
NULL, //1218
NULL, //1219
NULL, //1220
NULL, //1221
NULL, //1222
NULL, //1223
NULL, //1224
NULL, //1225
NULL, //1226
NULL, //1227
NULL, //1228
NULL, //1229
NULL, //1230
NULL, //1231
NULL, //1232
NULL, //1233
NULL, //1234
NULL, //1235
NULL, //1236
NULL, //1237
NULL, //1238
NULL, //1239
NULL, //1240
NULL, //1241
NULL, //1242
NULL, //1243
NULL, //1244
NULL, //1245
NULL, //1246
NULL, //1247
NULL, //1248
NULL, //1249
NULL, //1250
NULL, //1251
NULL, //1252
NULL, //1253
NULL, //1254
NULL, //1255
NULL, //1256
NULL, //1257
NULL, //1258
NULL, //1259
NULL, //1260
NULL, //1261
NULL, //1262
NULL, //1263
NULL, //1264
NULL, //1265
NULL, //1266
NULL, //1267
NULL, //1268
NULL, //1269
NULL, //1270
NULL, //1271
NULL, //1272
NULL, //1273
NULL, //1274
NULL, //1275
NULL, //1276
NULL, //1277
NULL, //1278
NULL, //1279
NULL, //1280
NULL, //1281
NULL, //1282
NULL, //1283
NULL, //1284
NULL, //1285
NULL, //1286
NULL, //1287
NULL, //1288
NULL, //1289
NULL, //1290
NULL, //1291
NULL, //1292
NULL, //1293
NULL, //1294
NULL, //1295
NULL, //1296
NULL, //1297
NULL, //1298
NULL, //1299
NULL, //1300
NULL, //1301
NULL, //1302
NULL, //1303
NULL, //1304
NULL, //1305
NULL, //1306
NULL, //1307
NULL, //1308
NULL, //1309
NULL, //1310
NULL, //1311
NULL, //1312
NULL, //1313
NULL, //1314
NULL, //1315
NULL, //1316
NULL, //1317
NULL, //1318
NULL, //1319
NULL, //1320
NULL, //1321
NULL, //1322
NULL, //1323
NULL, //1324
NULL, //1325
NULL, //1326
NULL, //1327
NULL, //1328
NULL, //1329
NULL, //1330
NULL, //1331
NULL, //1332
NULL, //1333
NULL, //1334
NULL, //1335
NULL, //1336
NULL, //1337
NULL, //1338
NULL, //1339
NULL, //1340
NULL, //1341
NULL, //1342
NULL, //1343
NULL, //1344
NULL, //1345
NULL, //1346
NULL, //1347
NULL, //1348
NULL, //1349
NULL, //1350
NULL, //1351
NULL, //1352
NULL, //1353
NULL, //1354
NULL, //1355
NULL, //1356
NULL, //1357
NULL, //1358
NULL, //1359
NULL, //1360
NULL, //1361
NULL, //1362
NULL, //1363
NULL, //1364
NULL, //1365
NULL, //1366
NULL, //1367
NULL, //1368
NULL, //1369
NULL, //1370
NULL, //1371
NULL, //1372
NULL, //1373
NULL, //1374
NULL, //1375
NULL, //1376
NULL, //1377
NULL, //1378
NULL, //1379
NULL, //1380
NULL, //1381
NULL, //1382
NULL, //1383
NULL, //1384
NULL, //1385
NULL, //1386
NULL, //1387
NULL, //1388
NULL, //1389
NULL, //1390
NULL, //1391
NULL, //1392
NULL, //1393
NULL, //1394
NULL, //1395
NULL, //1396
NULL, //1397
NULL, //1398
NULL, //1399
NULL, //1400
NULL, //1401
NULL, //1402
NULL, //1403
NULL, //1404
NULL, //1405
NULL, //1406
NULL, //1407
NULL, //1408
NULL, //1409
NULL, //1410
NULL, //1411
NULL, //1412
NULL, //1413
NULL, //1414
NULL, //1415
NULL, //1416
NULL, //1417
NULL, //1418
NULL, //1419
NULL, //1420
NULL, //1421
NULL, //1422
NULL, //1423
NULL, //1424
NULL, //1425
NULL, //1426
NULL, //1427
NULL, //1428
NULL, //1429
NULL, //1430
NULL, //1431
NULL, //1432
NULL, //1433
NULL, //1434
NULL, //1435
NULL, //1436
NULL, //1437
NULL, //1438
NULL, //1439
NULL, //1440
NULL, //1441
NULL, //1442
NULL, //1443
NULL, //1444
NULL, //1445
NULL, //1446
NULL, //1447
NULL, //1448
NULL, //1449
NULL, //1450
NULL, //1451
NULL, //1452
NULL, //1453
NULL, //1454
NULL, //1455
NULL, //1456
NULL, //1457
NULL, //1458
NULL, //1459
NULL, //1460
NULL, //1461
NULL, //1462
NULL, //1463
NULL, //1464
NULL, //1465
NULL, //1466
NULL, //1467
NULL, //1468
NULL, //1469
NULL, //1470
NULL, //1471
NULL, //1472
NULL, //1473
NULL, //1474
NULL, //1475
NULL, //1476
NULL, //1477
NULL, //1478
NULL, //1479
NULL, //1480
NULL, //1481
NULL, //1482
NULL, //1483
NULL, //1484
NULL, //1485
NULL, //1486
NULL, //1487
NULL, //1488
NULL, //1489
NULL, //1490
NULL, //1491
NULL, //1492
NULL, //1493
NULL, //1494
NULL, //1495
NULL, //1496
NULL, //1497
NULL, //1498
NULL, //1499
NULL, //1500
NULL, //1501
NULL, //1502
NULL, //1503
NULL, //1504
NULL, //1505
NULL, //1506
NULL, //1507
NULL, //1508
NULL, //1509
NULL, //1510
NULL, //1511
NULL, //1512
NULL, //1513
NULL, //1514
NULL, //1515
NULL, //1516
NULL, //1517
NULL, //1518
NULL, //1519
NULL, //1520
NULL, //1521
NULL, //1522
NULL, //1523
NULL, //1524
NULL, //1525
NULL, //1526
NULL, //1527
NULL, //1528
NULL, //1529
NULL, //1530
NULL, //1531
NULL, //1532
NULL, //1533
NULL, //1534
NULL, //1535
NULL, //1536
NULL, //1537
NULL, //1538
NULL, //1539
NULL, //1540
NULL, //1541
NULL, //1542
NULL, //1543
NULL, //1544
NULL, //1545
NULL, //1546
NULL, //1547
NULL, //1548
NULL, //1549
NULL, //1550
NULL, //1551
NULL, //1552
NULL, //1553
NULL, //1554
NULL, //1555
NULL, //1556
NULL, //1557
NULL, //1558
NULL, //1559
NULL, //1560
NULL, //1561
NULL, //1562
NULL, //1563
NULL, //1564
NULL, //1565
NULL, //1566
NULL, //1567
NULL, //1568
NULL, //1569
NULL, //1570
NULL, //1571
NULL, //1572
NULL, //1573
NULL, //1574
NULL, //1575
NULL, //1576
NULL, //1577
NULL, //1578
NULL, //1579
NULL, //1580
NULL, //1581
NULL, //1582
NULL, //1583
NULL, //1584
NULL, //1585
NULL, //1586
NULL, //1587
NULL, //1588
NULL, //1589
NULL, //1590
NULL, //1591
NULL, //1592
NULL, //1593
NULL, //1594
NULL, //1595
NULL, //1596
NULL, //1597
NULL, //1598
NULL, //1599
NULL, //1600
NULL, //1601
NULL, //1602
NULL, //1603
NULL, //1604
NULL, //1605
NULL, //1606
NULL, //1607
NULL, //1608
NULL, //1609
NULL, //1610
NULL, //1611
NULL, //1612
NULL, //1613
NULL, //1614
NULL, //1615
NULL, //1616
NULL, //1617
NULL, //1618
NULL, //1619
NULL, //1620
NULL, //1621
NULL, //1622
NULL, //1623
NULL, //1624
NULL, //1625
NULL, //1626
NULL, //1627
NULL, //1628
NULL, //1629
NULL, //1630
NULL, //1631
NULL, //1632
NULL, //1633
NULL, //1634
NULL, //1635
NULL, //1636
NULL, //1637
NULL, //1638
NULL, //1639
NULL, //1640
NULL, //1641
NULL, //1642
NULL, //1643
NULL, //1644
NULL, //1645
NULL, //1646
NULL, //1647
NULL, //1648
NULL, //1649
NULL, //1650
NULL, //1651
NULL, //1652
NULL, //1653
NULL, //1654
NULL, //1655
NULL, //1656
NULL, //1657
NULL, //1658
NULL, //1659
NULL, //1660
NULL, //1661
NULL, //1662
NULL, //1663
NULL, //1664
NULL, //1665
NULL, //1666
NULL, //1667
NULL, //1668
NULL, //1669
NULL, //1670
NULL, //1671
NULL, //1672
NULL, //1673
NULL, //1674
NULL, //1675
NULL, //1676
NULL, //1677
NULL, //1678
NULL, //1679
NULL, //1680
NULL, //1681
NULL, //1682
NULL, //1683
NULL, //1684
NULL, //1685
NULL, //1686
NULL, //1687
NULL, //1688
NULL, //1689
NULL, //1690
NULL, //1691
NULL, //1692
NULL, //1693
NULL, //1694
NULL, //1695
NULL, //1696
NULL, //1697
NULL, //1698
NULL, //1699
NULL, //1700
NULL, //1701
NULL, //1702
NULL, //1703
NULL, //1704
NULL, //1705
NULL, //1706
NULL, //1707
NULL, //1708
NULL, //1709
NULL, //1710
NULL, //1711
NULL, //1712
NULL, //1713
NULL, //1714
NULL, //1715
NULL, //1716
NULL, //1717
NULL, //1718
NULL, //1719
NULL, //1720
NULL, //1721
NULL, //1722
NULL, //1723
NULL, //1724
NULL, //1725
NULL, //1726
NULL, //1727
NULL, //1728
NULL, //1729
NULL, //1730
NULL, //1731
NULL, //1732
NULL, //1733
NULL, //1734
NULL, //1735
NULL, //1736
NULL, //1737
NULL, //1738
NULL, //1739
NULL, //1740
NULL, //1741
NULL, //1742
NULL, //1743
NULL, //1744
NULL, //1745
NULL, //1746
NULL, //1747
NULL, //1748
NULL, //1749
NULL, //1750
NULL, //1751
NULL, //1752
NULL, //1753
NULL, //1754
NULL, //1755
NULL, //1756
NULL, //1757
NULL, //1758
NULL, //1759
NULL, //1760
NULL, //1761
NULL, //1762
NULL, //1763
NULL, //1764
NULL, //1765
NULL, //1766
NULL, //1767
NULL, //1768
NULL, //1769
NULL, //1770
NULL, //1771
NULL, //1772
NULL, //1773
NULL, //1774
NULL, //1775
NULL, //1776
NULL, //1777
NULL, //1778
NULL, //1779
NULL, //1780
NULL, //1781
NULL, //1782
NULL, //1783
NULL, //1784
NULL, //1785
NULL, //1786
NULL, //1787
NULL, //1788
NULL, //1789
NULL, //1790
NULL, //1791
NULL, //1792
NULL, //1793
NULL, //1794
NULL, //1795
NULL, //1796
NULL, //1797
NULL, //1798
NULL, //1799
NULL, //1800
NULL, //1801
NULL, //1802
NULL, //1803
NULL, //1804
NULL, //1805
NULL, //1806
NULL, //1807
NULL, //1808
NULL, //1809
NULL, //1810
NULL, //1811
NULL, //1812
NULL, //1813
NULL, //1814
NULL, //1815
NULL, //1816
NULL, //1817
NULL, //1818
NULL, //1819
NULL, //1820
NULL, //1821
NULL, //1822
NULL, //1823
NULL, //1824
NULL, //1825
NULL, //1826
NULL, //1827
NULL, //1828
NULL, //1829
NULL, //1830
NULL, //1831
NULL, //1832
NULL, //1833
NULL, //1834
NULL, //1835
NULL, //1836
NULL, //1837
NULL, //1838
NULL, //1839
NULL, //1840
NULL, //1841
NULL, //1842
NULL, //1843
NULL, //1844
NULL, //1845
NULL, //1846
NULL, //1847
NULL, //1848
NULL, //1849
NULL, //1850
NULL, //1851
NULL, //1852
NULL, //1853
NULL, //1854
NULL, //1855
NULL, //1856
NULL, //1857
NULL, //1858
NULL, //1859
NULL, //1860
NULL, //1861
NULL, //1862
NULL, //1863
NULL, //1864
NULL, //1865
NULL, //1866
NULL, //1867
NULL, //1868
NULL, //1869
NULL, //1870
NULL, //1871
NULL, //1872
NULL, //1873
NULL, //1874
NULL, //1875
NULL, //1876
NULL, //1877
NULL, //1878
NULL, //1879
NULL, //1880
NULL, //1881
NULL, //1882
NULL, //1883
NULL, //1884
NULL, //1885
NULL, //1886
NULL, //1887
NULL, //1888
NULL, //1889
NULL, //1890
NULL, //1891
NULL, //1892
NULL, //1893
NULL, //1894
NULL, //1895
NULL, //1896
NULL, //1897
NULL, //1898
NULL, //1899
NULL, //1900
NULL, //1901
NULL, //1902
NULL, //1903
NULL, //1904
NULL, //1905
NULL, //1906
NULL, //1907
NULL, //1908
NULL, //1909
NULL, //1910
NULL, //1911
NULL, //1912
NULL, //1913
NULL, //1914
NULL, //1915
NULL, //1916
NULL, //1917
NULL, //1918
NULL, //1919
NULL, //1920
NULL, //1921
NULL, //1922
NULL, //1923
NULL, //1924
NULL, //1925
NULL, //1926
NULL, //1927
NULL, //1928
NULL, //1929
NULL, //1930
NULL, //1931
NULL, //1932
NULL, //1933
NULL, //1934
NULL, //1935
NULL, //1936
NULL, //1937
NULL, //1938
NULL, //1939
NULL, //1940
NULL, //1941
NULL, //1942
NULL, //1943
NULL, //1944
NULL, //1945
NULL, //1946
NULL, //1947
NULL, //1948
NULL, //1949
NULL, //1950
NULL, //1951
NULL, //1952
NULL, //1953
NULL, //1954
NULL, //1955
NULL, //1956
NULL, //1957
NULL, //1958
NULL, //1959
NULL, //1960
NULL, //1961
NULL, //1962
NULL, //1963
NULL, //1964
NULL, //1965
NULL, //1966
NULL, //1967
NULL, //1968
NULL, //1969
NULL, //1970
NULL, //1971
NULL, //1972
NULL, //1973
NULL, //1974
NULL, //1975
NULL, //1976
NULL, //1977
NULL, //1978
NULL, //1979
NULL, //1980
NULL, //1981
NULL, //1982
NULL, //1983
NULL, //1984
NULL, //1985
NULL, //1986
NULL, //1987
NULL, //1988
NULL, //1989
NULL, //1990
NULL, //1991
NULL, //1992
NULL, //1993
NULL, //1994
NULL, //1995
NULL, //1996
NULL, //1997
NULL, //1998
NULL, //1999
NULL, //2000
NULL, //2001
NULL, //2002
NULL, //2003
NULL, //2004
NULL, //2005
NULL, //2006
NULL, //2007
NULL, //2008
NULL, //2009
NULL, //2010
NULL, //2011
NULL, //2012
NULL, //2013
NULL, //2014
NULL, //2015
NULL, //2016
NULL, //2017
NULL, //2018
NULL, //2019
NULL, //2020
NULL, //2021
NULL, //2022
NULL, //2023
NULL, //2024
NULL, //2025
NULL, //2026
NULL, //2027
NULL, //2028
NULL, //2029
NULL, //2030
NULL, //2031
NULL, //2032
NULL, //2033
NULL, //2034
NULL, //2035
NULL, //2036
NULL, //2037
NULL, //2038
NULL, //2039
NULL, //2040
NULL, //2041
NULL, //2042
NULL, //2043
NULL, //2044
NULL, //2045
NULL, //2046
NULL, //2047
"HLINKTOOLTIP : Hyperlink Tooltip", //2048
"WEBPUB : Web Publish Item", //2049
"QSISXTAG : PivotTable and Query Table Extensions", //2050
"DBQUERYEXT : Database Query Extensions", //2051
"EXTSTRING : FRT String", //2052
"TXTQUERY : Text Query Information", //2053
"QSIR : Query Table Formatting", //2054
"QSIF : Query Table Field Formatting", //2055
NULL, //2056
"BOF : Beginning of File", //2057
"OLEDBCONN : OLE Database Connection", //2058
"WOPT : Web Options", //2059
"SXVIEWEX : Pivot Table OLAP Extensions", //2060
"SXTH : PivotTable OLAP Hierarchy", //2061
"SXPIEX : OLAP Page Item Extensions", //2062
"SXVDTEX : View Dimension OLAP Extensions", //2063
"SXVIEWEX9 : Pivot Table Extensions", //2064
NULL, //2065
"CONTINUEFRT : Continued FRT", //2066
"REALTIMEDATA : Real-Time Data (RTD)", //2067
NULL, //2068
NULL, //2069
NULL, //2070
NULL, //2071
NULL, //2072
NULL, //2073
NULL, //2074
NULL, //2075
NULL, //2076
NULL, //2077
NULL, //2078
NULL, //2079
NULL, //2080
NULL, //2081
NULL, //2082
NULL, //2083
NULL, //2084
NULL, //2085
NULL, //2086
NULL, //2087
NULL, //2088
NULL, //2089
NULL, //2090
NULL, //2091
NULL, //2092
NULL, //2093
NULL, //2094
NULL, //2095
NULL, //2096
NULL, //2097
NULL, //2098
NULL, //2099
NULL, //2100
NULL, //2101
NULL, //2102
NULL, //2103
NULL, //2104
NULL, //2105
NULL, //2106
NULL, //2107
NULL, //2108
NULL, //2109
NULL, //2110
NULL, //2111
NULL, //2112
NULL, //2113
NULL, //2114
NULL, //2115
NULL, //2116
NULL, //2117
NULL, //2118
NULL, //2119
NULL, //2120
NULL, //2121
NULL, //2122
NULL, //2123
NULL, //2124
NULL, //2125
NULL, //2126
NULL, //2127
NULL, //2128
NULL, //2129
NULL, //2130
NULL, //2131
NULL, //2132
NULL, //2133
NULL, //2134
NULL, //2135
NULL, //2136
NULL, //2137
NULL, //2138
NULL, //2139
NULL, //2140
NULL, //2141
NULL, //2142
NULL, //2143
NULL, //2144
NULL, //2145
"SHEETEXT : Extra Sheet Info", //2146
"BOOKEXT : Extra Book Info", //2147
"SXADDL : Pivot Table Additional Info", //2148
"CRASHRECERR : Crash Recovery Error", //2149
"HFPicture : Header / Footer Picture", //2150
"FEATHEADR : Shared Feature Header", //2151
"FEAT : Shared Feature Record", //2152
NULL, //2153
"DATALABEXT : Chart Data Label Extension", //2154
"DATALABEXTCONTENTS : Chart Data Label Extension Contents", //2155
"CELLWATCH : Cell Watch", //2156
"FEATINFO : Shared Feature Info Record", //2157
NULL, //2158
NULL, //2159
NULL, //2160
"FEATHEADR11 : Shared Feature Header 11", //2161
"FEAT11 : Shared Feature 11 Record", //2162
"FEATINFO11 : Shared Feature Info 11 Record", //2163
"DROPDOWNOBJIDS : Drop Down Object", //2164
"CONTINUEFRT11 : Continue FRT 11", //2165
"DCONN : Data Connection", //2166
"LIST12 : Extra Table Data Introduced in Excel 2007", //2167
"FEAT12 : Shared Feature 12 Record", //2168
"CONDFMT12 : Conditional Formatting Range Information 12", //2169
"CF12 : Conditional Formatting Condition 12", //2170
"CFEX : Conditional Formatting Extension", //2171
"XFCRC : XF Extensions Checksum", //2172
"XFEXT : XF Extension", //2173
"EZFILTER12 : AutoFilter Data Introduced in Excel 2007", //2174
"CONTINUEFRT12 : Continue FRT 12", //2175
NULL, //2176
"SXADDL12 : Additional Workbook Connections Information", //2177
NULL, //2178
NULL, //2179
"MDTINFO : Information about a Metadata Type", //2180
"MDXSTR : MDX Metadata String", //2181
"MDXTUPLE : Tuple MDX Metadata", //2182
"MDXSET : Set MDX Metadata", //2183
"MDXPROP : Member Property MDX Metadata", //2184
"MDXKPI : Key Performance Indicator MDX Metadata", //2185
"MDTB : Block of Metadata Records", //2186
"PLV : Page Layout View Settings in Excel 2007", //2187
"COMPAT12 : Compatibility Checker 12", //2188
"DXF : Differential XF", //2189
"TABLESTYLES : Table Styles", //2190
"TABLESTYLE : Table Style", //2191
"TABLESTYLEELEMENT : Table Style Element", //2192
NULL, //2193
"STYLEEXT : Named Cell Style Extension", //2194
"NAMEPUBLISH : Publish To Excel Server Data for Name", //2195
"NAMECMT : Name Comment", //2196
"SORTDATA12 : Sort Data 12", //2197
"THEME : Theme", //2198
"GUIDTYPELIB : VB Project Typelib GUID", //2199
"FNGRP12 : Function Group", //2200
"NAMEFNGRP12 : Extra Function Group", //2201
"MTRSETTINGS : Multi-Threaded Calculation Settings", //2202
"COMPRESSPICTURES : Automatic Picture Compression Mode", //2203
"HEADERFOOTER : Header Footer", //2204
NULL, //2205
NULL, //2206
NULL, //2207
NULL, //2208
NULL, //2209
NULL, //2210
"FORCEFULLCALCULATION : Force Full Calculation Settings", //2211
NULL, //2212
NULL, //2213
NULL, //2214
NULL, //2215
NULL, //2216
NULL, //2217
NULL, //2218
NULL, //2219
NULL, //2220
NULL, //2221
NULL, //2222
NULL, //2223
NULL, //2224
NULL, //2225
NULL, //2226
NULL, //2227
NULL, //2228
NULL, //2229
NULL, //2230
NULL, //2231
NULL, //2232
NULL, //2233
NULL, //2234
NULL, //2235
NULL, //2236
NULL, //2237
NULL, //2238
NULL, //2239
NULL, //2240
"LISTOBJ : List Object", //2241
"LISTFIELD : List Field", //2242
"LISTDV : List Data Validation", //2243
"LISTCONDFMT : List Conditional Formatting", //2244
"LISTCF : List Cell Formatting", //2245
"FMQRY : Filemaker queries", //2246
"FMSQRY : File maker queries", //2247
"PLV : Page Layout View in Mac Excel 11", //2248
"LNEXT : Extension information for borders in Mac Office 11", //2249
"MKREXT : Extension information for markers in Mac Office 11",//2250
};
char *FUNCTIONS[] = {
"COUNT", //0
"IF", //1
"ISNA", //2
"ISERROR", //3
"SUM", //4
"AVERAGE", //5
"MIN", //6
"MAX", //7
"ROW", //8
"COLUMN", //9
"NA", //10
"NPV", //11
"STDEV", //12
"DOLLAR", //13
"FIXED", //14
"SIN", //15
"COS", //16
"TAN", //17
"ATAN", //18
"PI", //19
"SQRT", //20
"EXP", //21
"LN", //22
"LOG10", //23
"ABS", //24
"INT", //25
"SIGN", //26
"ROUND", //27
"LOOKUP", //28
"INDEX", //29
"REPT", //30
"MID", //31
"LEN", //32
"VALUE", //33
"TRUE", //34
"FALSE", //35
"AND", //36
"OR", //37
"NOT", //38
"MOD", //39
"DCOUNT", //40
"DSUM", //41
"DAVERAGE", //42
"DMIN", //43
"DMAX", //44
"DSTDEV", //45
"VAR", //46
"DVAR", //47
"TEXT", //48
"LINEST", //49
"TREND", //50
"LOGEST", //51
"GROWTH", //52
"GOTO", //53
"HALT", //54
"RETURN", //55
"PV", //56
"FV", //57
"NPER", //58
"PMT", //59
"RATE", //60
"MIRR", //61
"IRR", //62
"RAND", //63
"MATCH", //64
"DATE", //65
"TIME", //66
"DAY", //67
"MONTH", //68
"YEAR", //69
"WEEKDAY", //70
"HOUR", //71
"MINUTE", //72
"SECOND", //73
"NOW", //74
"AREAS", //75
"ROWS", //76
"COLUMNS", //77
"OFFSET", //78
"ABSREF", //79
"RELREF", //80
"ARGUMENT", //81
"SEARCH", //82
"TRANSPOSE", //83
"ERROR", //84
"STEP", //85
"TYPE", //86
"ECHO", //87
"SET.NAME", //88
"CALLER", //89
"DEREF", //90
"WINDOWS", //91
"SERIES", //92
"DOCUMENTS", //93
"ACTIVE.CELL", //94
"SELECTION", //95
"RESULT", //96
"ATAN2", //97
"ASIN", //98
"ACOS", //99
"CHOOSE", //100
"HLOOKUP", //101
"VLOOKUP", //102
"LINKS", //103
"INPUT", //104
"ISREF", //105
"GET.FORMULA", //106
"GET.NAME", //107
"SET.VALUE", //108
"LOG", //109
"EXEC", //110
"CHAR", //111
"LOWER", //112
"UPPER", //113
"PROPER", //114
"LEFT", //115
"RIGHT", //116
"EXACT", //117
"TRIM", //118
"REPLACE", //119
"SUBSTITUTE", //120
"CODE", //121
"NAMES", //122
"DIRECTORY", //123
"FIND", //124
"CELL", //125
"ISERR", //126
"ISTEXT", //127
"ISNUMBER", //128
"ISBLANK", //129
"T", //130
"N", //131
"FOPEN", //132
"FCLOSE", //133
"FSIZE", //134
"FREADLN", //135
"FREAD", //136
"FWRITELN", //137
"FWRITE", //138
"FPOS", //139
"DATEVALUE", //140
"TIMEVALUE", //141
"SLN", //142
"SYD", //143
"DDB", //144
"GET.DEF", //145
"REFTEXT", //146
"TEXTREF", //147
"INDIRECT", //148
"REGISTER", //149
"CALL", //150
"ADD.BAR", //151
"ADD.MENU", //152
"ADD.COMMAND", //153
"ENABLE.COMMAND", //154
"CHECK.COMMAND", //155
"RENAME.COMMAND", //156
"SHOW.BAR", //157
"DELETE.MENU", //158
"DELETE.COMMAND", //159
"GET.CHART.ITEM", //160
"DIALOG.BOX", //161
"CLEAN", //162
"MDETERM", //163
"MINVERSE", //164
"MMULT", //165
"FILES", //166
"IPMT", //167
"PPMT", //168
"COUNTA", //169
"CANCEL.KEY", //170
"FOR", //171
"WHILE", //172
"BREAK", //173
"NEXT", //174
"INITIATE", //175
"REQUEST", //176
"POKE", //177
"EXECUTE", //178
"TERMINATE", //179
"RESTART", //180
"HELP", //181
"GET.BAR", //182
"PRODUCT", //183
"FACT", //184
"GET.CELL", //185
"GET.WORKSPACE", //186
"GET.WINDOW", //187
"GET.DOCUMENT", //188
"DPRODUCT", //189
"ISNONTEXT", //190
"GET.NOTE", //191
"NOTE", //192
"STDEVP", //193
"VARP", //194
"DSTDEVP", //195
"DVARP", //196
"TRUNC", //197
"ISLOGICAL", //198
"DCOUNTA", //199
"DELETE.BAR", //200
"UNREGISTER", //201
NULL,
NULL,
"USDOLLAR", //204
"FINDB", //205
"SEARCHB", //206
"REPLACEB", //207
"LEFTB", //208
"RIGHTB", //209
"MIDB", //210
"LENB", //211
"ROUNDUP", //212
"ROUNDDOWN", //213
"ASC", //214
"DBCS", //215
"RANK", //216
NULL,
NULL,
"ADDRESS", //219
"DAYS360", //220
"TODAY", //221
"VDB", //222
"ELSE", //223
"ELSE.IF", //224
"END.IF", //225
"FOR.CELL", //226
"MEDIAN", //227
"SUMPRODUCT", //228
"SINH", //229
"COSH", //230
"TANH", //231
"ASINH", //232
"ACOSH", //233
"ATANH", //234
"DGET", //235
"CREATE.OBJECT", //236
"VOLATILE", //237
"LAST.ERROR", //238
"CUSTOM.UNDO", //239
"CUSTOM.REPEAT", //240
"FORMULA.CONVERT", //241
"GET.LINK.INFO", //242
"TEXT.BOX", //243
"INFO", //244
"GROUP", //245
"GET.OBJECT", //246
"DB", //247
"PAUSE", //248
NULL,
NULL,
"RESUME", //251
"FREQUENCY", //252
"ADD.TOOLBAR", //253
"DELETE.TOOLBAR", //254
"User Defined Function", //255
"RESET.TOOLBAR", //256
"EVALUATE", //257
"GET.TOOLBAR", //258
"GET.TOOL", //259
"SPELLING.CHECK", //260
"ERROR.TYPE", //261
"APP.TITLE", //262
"WINDOW.TITLE", //263
"SAVE.TOOLBAR", //264
"ENABLE.TOOL", //265
"PRESS.TOOL", //266
"REGISTER.ID", //267
"GET.WORKBOOK", //268
"AVEDEV", //269
"BETADIST", //270
"GAMMALN", //271
"BETAINV", //272
"BINOMDIST", //273
"CHIDIST", //274
"CHIINV", //275
"COMBIN", //276
"CONFIDENCE", //277
"CRITBINOM", //278
"EVEN", //279
"EXPONDIST", //280
"FDIST", //281
"FINV", //282
"FISHER", //283
"FISHERINV", //284
"FLOOR", //285
"GAMMADIST", //286
"GAMMAINV", //287
"CEILING", //288
"HYPGEOMDIST", //289
"LOGNORMDIST", //290
"LOGINV", //291
"NEGBINOMDIST", //292
"NORMDIST", //293
"NORMSDIST", //294
"NORMINV", //295
"NORMSINV", //296
"STANDARDIZE", //297
"ODD", //298
"PERMUT", //299
"POISSON", //300
"TDIST", //301
"WEIBULL", //302
"SUMXMY2", //303
"SUMX2MY2", //304
"SUMX2PY2", //305
"CHITEST", //306
"CORREL", //307
"COVAR", //308
"FORECAST", //309
"FTEST", //310
"INTERCEPT", //311
"PEARSON", //312
"RSQ", //313
"STEYX", //314
"SLOPE", //315
"TTEST", //316
"PROB", //317
"DEVSQ", //318
"GEOMEAN", //319
"HARMEAN", //320
"SUMSQ", //321
"KURT", //322
"SKEW", //323
"ZTEST", //324
"LARGE", //325
"SMALL", //326
"QUARTILE", //327
"PERCENTILE", //328
"PERCENTRANK", //329
"MODE", //330
"TRIMMEAN", //331
"TINV", //332
NULL,
"MOVIE.COMMAND", //334
"GET.MOVIE", //335
"CONCATENATE", //336
"POWER", //337
"PIVOT.ADD.DATA", //338
"GET.PIVOT.TABLE", //339
"GET.PIVOT.FIELD", //340
"GET.PIVOT.ITEM", //341
"RADIANS", //342
"DEGREES", //343
"SUBTOTAL", //344
"SUMIF", //345
"COUNTIF", //346
"COUNTBLANK", //347
"SCENARIO.GET", //348
"OPTIONS.LISTS.GET", //349
"ISPMT", //350
"DATEDIF", //351
"DATESTRING", //352
"NUMBERSTRING", //353
"ROMAN", //354
"OPEN.DIALOG", //355
"SAVE.DIALOG", //356
"VIEW.GET", //357
"GETPIVOTDATA", //358
"HYPERLINK", //359
"PHONETIC", //360
"AVERAGEA", //361
"MAXA", //362
"MINA", //363
"STDEVPA", //364
"VARPA", //365
"STDEVA", //366
"VARA", //367
"BAHTTEXT", //368
"THAIDAYOFWEEK", //369
"THAIDIGIT", //370
"THAIMONTHOFYEAR", //371
"THAINUMSOUND", //372
"THAINUMSTRING", //373
"THAISTRINGLENGTH", //374
"ISTHAIDIGIT", //375
"ROUNDBAHTDOWN", //376
"ROUNDBAHTUP", //377
"THAIYEAR", //378
"RTD", //379
};
// clang-format on
// clang-format off
char *EXTENDED_FUNCTIONS[] = {
"BEEP", //32768
"OPEN", //32769
"OPEN.LINKS", //32770
"CLOSE.ALL", //32771
"SAVE", //32772
"SAVE.AS", //32773
"FILE.DELETE", //32774
"PAGE.SETUP", //32775
"PRINT", //32776
"PRINTER.SETUP", //32777
"QUIT", //32778
"NEW.WINDOW", //32779
"ARRANGE.ALL", //32780
"WINDOW.SIZE", //32781
"WINDOW.MOVE", //32782
"FULL", //32783
"CLOSE", //32784
"RUN", //32785
NULL,
NULL,
NULL,
NULL,
"SET.PRINT.AREA", //32790
"SET.PRINT.TITLES", //32791
"SET.PAGE.BREAK", //32792
"REMOVE.PAGE.BREAK", //32793
"FONT", //32794
"DISPLAY", //32795
"PROTECT.DOCUMENT", //32796
"PRECISION", //32797
"A1.R1C1", //32798
"CALCULATE.NOW", //32799
"CALCULATION", //32800
NULL,
"DATA.FIND", //32802
"EXTRACT", //32803
"DATA.DELETE", //32804
"SET.DATABASE", //32805
"SET.CRITERIA", //32806
"SORT", //32807
"DATA.SERIES", //32808
"TABLE", //32809
"FORMAT.NUMBER", //32810
"ALIGNMENT", //32811
"STYLE", //32812
"BORDER", //32813
"CELL.PROTECTION", //32814
"COLUMN.WIDTH", //32815
"UNDO", //32816
"CUT", //32817
"COPY", //32818
"PASTE", //32819
"CLEAR", //32820
"PASTE.SPECIAL", //32821
"EDIT.DELETE", //32822
"INSERT", //32823
"FILL.RIGHT", //32824
"FILL.DOWN", //32825
NULL,
NULL,
NULL,
"DEFINE.NAME", //32829
"CREATE.NAMES", //32830
"FORMULA.GOTO", //32831
"FORMULA.FIND", //32832
"SELECT.LAST.CELL", //32833
"SHOW.ACTIVE.CELL", //32834
"GALLERY.AREA", //32835
"GALLERY.BAR", //32836
"GALLERY.COLUMN", //32837
"GALLERY.LINE", //32838
"GALLERY.PIE", //32839
"GALLERY.SCATTER", //32840
"COMBINATION", //32841
"PREFERRED", //32842
"ADD.OVERLAY", //32843
"GRIDLINES", //32844
"SET.PREFERRED", //32845
"AXES", //32846
"LEGEND", //32847
"ATTACH.TEXT", //32848
"ADD.ARROW", //32849
"SELECT.CHART", //32850
"SELECT.PLOT.AREA", //32851
"PATTERNS", //32852
"MAIN.CHART", //32853
"OVERLAY", //32854
"SCALE", //32855
"FORMAT.LEGEND", //32856
"FORMAT.TEXT", //32857
"EDIT.REPEAT", //32858
"PARSE", //32859
"JUSTIFY", //32860
"HIDE", //32861
"UNHIDE", //32862
"WORKSPACE", //32863
"FORMULA", //32864
"FORMULA.FILL", //32865
"FORMULA.ARRAY", //32866
"DATA.FIND.NEXT", //32867
"DATA.FIND.PREV", //32868
"FORMULA.FIND.NEXT", //32869
"FORMULA.FIND.PREV", //32870
"ACTIVATE", //32871
"ACTIVATE.NEXT", //32872
"ACTIVATE.PREV", //32873
"UNLOCKED.NEXT", //32874
"UNLOCKED.PREV", //32875
"COPY.PICTURE", //32876
"SELECT", //32877
"DELETE.NAME", //32878
"DELETE.FORMAT", //32879
"VLINE", //32880
"HLINE", //32881
"VPAGE", //32882
"HPAGE", //32883
"VSCROLL", //32884
"HSCROLL", //32885
"ALERT", //32886
"NEW", //32887
"CANCEL.COPY", //32888
"SHOW.CLIPBOARD", //32889
"MESSAGE", //32890
NULL,
"PASTE.LINK", //32892
"APP.ACTIVATE", //32893
"DELETE.ARROW", //32894
"ROW.HEIGHT", //32895
"FORMAT.MOVE", //32896
"FORMAT.SIZE", //32897
"FORMULA.REPLACE", //32898
"SEND.KEYS", //32899
"SELECT.SPECIAL", //32900
"APPLY.NAMES", //32901
"REPLACE.FONT", //32902
"FREEZE.PANES", //32903
"SHOW.INFO", //32904
"SPLIT", //32905
"ON.WINDOW", //32906
"ON.DATA", //32907
"DISABLE.INPUT", //32908
NULL,
"OUTLINE", //32910
"LIST.NAMES", //32911
"FILE.CLOSE", //32912
"SAVE.WORKBOOK", //32913
"DATA.FORM", //32914
"COPY.CHART", //32915
"ON.TIME", //32916
"WAIT", //32917
"FORMAT.FONT", //32918
"FILL.UP", //32919
"FILL.LEFT", //32920
"DELETE.OVERLAY", //32921
NULL,
"SHORT.MENUS", //32923
NULL,
NULL,
NULL,
"SET.UPDATE.STATUS", //32927
NULL,
"COLOR.PALETTE", //32929
"DELETE.STYLE", //32930
"WINDOW.RESTORE", //32931
"WINDOW.MAXIMIZE", //32932
NULL,
"CHANGE.LINK", //32934
"CALCULATE.DOCUMENT", //32935
"ON.KEY", //32936
"APP.RESTORE", //32937
"APP.MOVE", //32938
"APP.SIZE", //32939
"APP.MINIMIZE", //32940
"APP.MAXIMIZE", //32941
"BRING.TO.FRONT", //32942
"SEND.TO.BACK", //32943
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"MAIN.CHART.TYPE", //32953
"OVERLAY.CHART.TYPE", //32954
"SELECT.END", //32955
"OPEN.MAIL", //32956
"SEND.MAIL", //32957
"STANDARD.FONT", //32958
"CONSOLIDATE", //32959
"SORT.SPECIAL", //32960
"GALLERY.3D.AREA", //32961
"GALLERY.3D.COLUMN", //32962
"GALLERY.3D.LINE", //32963
"GALLERY.3D.PIE", //32964
"VIEW.3D", //32965
"GOAL.SEEK", //32966
"WORKGROUP", //32967
"FILL.GROUP", //32968
"UPDATE.LINK", //32969
"PROMOTE", //32970
"DEMOTE", //32971
"SHOW.DETAIL", //32972
NULL,
"UNGROUP", //32974
"OBJECT.PROPERTIES", //32975
"SAVE.NEW.OBJECT", //32976
"SHARE", //32977
"SHARE.NAME", //32978
"DUPLICATE", //32979
"APPLY.STYLE", //32980
"ASSIGN.TO.OBJECT", //32981
"OBJECT.PROTECTION", //32982
"HIDE.OBJECT", //32983
"SET.EXTRACT", //32984
"CREATE.PUBLISHER", //32985
"SUBSCRIBE.TO", //32986
"ATTRIBUTES", //32987
"SHOW.TOOLBAR", //32988
NULL,
"PRINT.PREVIEW", //32990
"EDIT.COLOR", //32991
"SHOW.LEVELS", //32992
"FORMAT.MAIN", //32993
"FORMAT.OVERLAY", //32994
"ON.RECALC", //32995
"EDIT.SERIES", //32996
"DEFINE.STYLE", //32997
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"LINE.PRINT", //33008
NULL,
NULL,
"ENTER.DATA", //33011
NULL,
NULL,
NULL,
NULL,
NULL,
"GALLERY.RADAR", //33017
"MERGE.STYLES", //33018
"EDITION.OPTIONS", //33019
"PASTE.PICTURE", //33020
"PASTE.PICTURE.LINK", //33021
"SPELLING", //33022
NULL,
"ZOOM", //33024
NULL,
NULL,
"INSERT.OBJECT", //33027
"WINDOW.MINIMIZE", //33028
NULL,
NULL,
NULL,
NULL,
"SOUND.NOTE", //33033
"SOUND.PLAY", //33034
"FORMAT.SHAPE", //33035
"EXTEND.POLYGON", //33036
"FORMAT.AUTO", //33037
NULL,
NULL,
"GALLERY.3D.BAR", //33040
"GALLERY.3D.SURFACE", //33041
"FILL.AUTO", //33042
NULL,
"CUSTOMIZE.TOOLBAR", //33044
"ADD.TOOL", //33045
"EDIT.OBJECT", //33046
"ON.DOUBLECLICK", //33047
"ON.ENTRY", //33048
"WORKBOOK.ADD", //33049
"WORKBOOK.MOVE", //33050
"WORKBOOK.COPY", //33051
"WORKBOOK.OPTIONS", //33052
"SAVE.WORKSPACE", //33053
NULL,
NULL,
"CHART.WIZARD", //33056
"DELETE.TOOL", //33057
"MOVE.TOOL", //33058
"WORKBOOK.SELECT", //33059
"WORKBOOK.ACTIVATE", //33060
"ASSIGN.TO.TOOL", //33061
NULL,
"COPY.TOOL", //33063
"RESET.TOOL", //33064
"CONSTRAIN.NUMERIC", //33065
"PASTE.TOOL", //33066
NULL,
NULL,
NULL,
"WORKBOOK.NEW", //33070
NULL,
NULL,
"SCENARIO.CELLS", //33073
"SCENARIO.DELETE", //33074
"SCENARIO.ADD", //33075
"SCENARIO.EDIT", //33076
"SCENARIO.SHOW", //33077
"SCENARIO.SHOW.NEXT", //33078
"SCENARIO.SUMMARY", //33079
"PIVOT.TABLE.WIZARD", //33080
"PIVOT.FIELD.PROPERTIES", //33081
"PIVOT.FIELD", //33082
"PIVOT.ITEM", //33083
"PIVOT.ADD.FIELDS", //33084
NULL,
"OPTIONS.CALCULATION", //33086
"OPTIONS.EDIT", //33087
"OPTIONS.VIEW", //33088
"ADDIN.MANAGER", //33089
"MENU.EDITOR", //33090
"ATTACH.TOOLBARS", //33091
"VBAActivate", //33092
"OPTIONS.CHART", //33093
NULL,
NULL,
"VBA.INSERT.FILE", //33096
NULL,
"VBA.PROCEDURE.DEFINITION", //33098
NULL,
NULL,
NULL,
NULL,
NULL,
"ROUTING.SLIP", //33104
NULL,
"ROUTE.DOCUMENT", //33106
"MAIL.LOGON", //33107
NULL,
NULL,
"INSERT.PICTURE", //33110
"EDIT.TOOL", //33111
"GALLERY.DOUGHNUT", //33112
NULL,
NULL,
NULL,
NULL,
NULL,
"CHART.TREND", //33118
NULL,
"PIVOT.ITEM.PROPERTIES", //33120
NULL,
"WORKBOOK.INSERT", //33122
"OPTIONS.TRANSITION", //33123
"OPTIONS.GENERAL", //33124
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"FILTER.ADVANCED", //33138
NULL,
NULL,
"MAIL.ADD.MAILER", //33141
"MAIL.DELETE.MAILER", //33142
"MAIL.REPLY", //33143
"MAIL.REPLY.ALL", //33144
"MAIL.FORWARD", //33145
"MAIL.NEXT.LETTER", //33146
"DATA.LABEL", //33147
"INSERT.TITLE", //33148
"FONT.PROPERTIES", //33149
"MACRO.OPTIONS", //33150
"WORKBOOK.HIDE", //33151
"WORKBOOK.UNHIDE", //33152
"WORKBOOK.DELETE", //33153
"WORKBOOK.NAME", //33154
NULL,
"GALLERY.CUSTOM", //33156
NULL,
"ADD.CHART.AUTOFORMAT", //33158
"DELETE.CHART.AUTOFORMAT", //33159
"CHART.ADD.DATA", //33160
"AUTO.OUTLINE", //33161
"TAB.ORDER", //33162
"SHOW.DIALOG", //33163
"SELECT.ALL", //33164
"UNGROUP.SHEETS", //33165
"SUBTOTAL.CREATE", //33166
"SUBTOTAL.REMOVE", //33167
"RENAME.OBJECT", //33168
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"WORKBOOK.SCROLL", //33180
"WORKBOOK.NEXT", //33181
"WORKBOOK.PREV", //33182
"WORKBOOK.TAB.SPLIT", //33183
"FULL.SCREEN", //33184
"WORKBOOK.PROTECT", //33185
NULL,
NULL,
"SCROLLBAR.PROPERTIES", //33188
"PIVOT.SHOW.PAGES", //33189
"TEXT.TO.COLUMNS", //33190
"FORMAT.CHARTTYPE", //33191
"LINK.FORMAT", //33192
"TRACER.DISPLAY", //33193
NULL,
NULL,
NULL,
NULL,
"TRACER.NAVIGATE", //33198
"TRACER.CLEAR", //33199
"TRACER.ERROR", //33200
"PIVOT.FIELD.GROUP", //33201
"PIVOT.FIELD.UNGROUP", //33202
"CHECKBOX.PROPERTIES", //33203
"LABEL.PROPERTIES", //33204
"LISTBOX.PROPERTIES", //33205
"EDITBOX.PROPERTIES", //33206
"PIVOT.REFRESH", //33207
"LINK.COMBO", //33208
"OPEN.TEXT", //33209
"HIDE.DIALOG", //33210
"SET.DIALOG.FOCUS", //33211
"ENABLE.OBJECT", //33212
"PUSHBUTTON.PROPERTIES", //33213
"SET.DIALOG.DEFAULT", //33214
"FILTER", //33215
"FILTER.SHOW.ALL", //33216
"CLEAR.OUTLINE", //33217
"FUNCTION.WIZARD", //33218
"ADD.LIST.ITEM", //33219
"SET.LIST.ITEM", //33220
"REMOVE.LIST.ITEM", //33221
"SELECT.LIST.ITEM", //33222
"SET.CONTROL.VALUE", //33223
"SAVE.COPY.AS", //33224
NULL,
"OPTIONS.LISTS.ADD", //33226
"OPTIONS.LISTS.DELETE", //33227
"SERIES.AXES", //33228
"SERIES.X", //33229
"SERIES.Y", //33230
"ERRORBAR.X", //33231
"ERRORBAR.Y", //33232
"FORMAT.CHART", //33233
"SERIES.ORDER", //33234
"MAIL.LOGOFF", //33235
"CLEAR.ROUTING.SLIP", //33236
"APP.ACTIVATE.MICROSOFT", //33237
"MAIL.EDIT.MAILER", //33238
"ON.SHEET", //33239
"STANDARD.WIDTH", //33240
"SCENARIO.MERGE", //33241
"SUMMARY.INFO", //33242
"FIND.FILE", //33243
"ACTIVE.CELL.FONT", //33244
"ENABLE.TIPWIZARD", //33245
"VBA.MAKE.ADDIN", //33246
NULL,
"INSERTDATATABLE", //33248
"WORKGROUP.OPTIONS", //33249
"MAIL.SEND.MAILER", //33250
NULL,
NULL,
"AUTOCORRECT", //33253
NULL,
NULL,
NULL,
"POST.DOCUMENT", //33257
NULL,
"PICKLIST", //33259
NULL,
"VIEW.SHOW", //33261
"VIEW.DEFINE", //33262
"VIEW.DELETE", //33263
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"SHEET.BACKGROUND", //33277
"INSERT.MAP.OBJECT", //33278
"OPTIONS.MENONO", //33279
NULL,
NULL,
NULL,
NULL,
NULL,
"MSOCHECKS", //33285
"NORMAL", //33286
"LAYOUT", //33287
"RM.PRINT.AREA", //33288
"CLEAR.PRINT.AREA", //33289
"ADD.PRINT.AREA", //33290
"MOVE.BRK", //33291
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"HIDECURR.NOTE", //33313
"HIDEALL.NOTES", //33314
"DELETE.NOTE", //33315
"TRAVERSE.NOTES", //33316
"ACTIVATE.NOTES", //33317
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"PROTECT.REVISIONS", //33388
"UNPROTECT.REVISIONS", //33389
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"OPTIONS.ME", //33415
NULL,
NULL,
NULL,
NULL,
NULL,
"WEB.PUBLISH", //33421
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"NEWWEBQUERY", //33435
NULL,
NULL,
NULL,
NULL,
NULL,
"PIVOT.TABLE.CHART", //33441
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"OPTIONS.SAVE", //33521
NULL,
"OPTIONS.SPELL", //33523
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"HIDEALL.INKANNOTS", //33576
};
char *TOKENS[] = {
NULL,
"ptgExp", //1
"ptgTbl", //2
"ptgAdd", //3
"ptgSub", //4
"ptgMul", //5
"ptgDiv", //6
"ptgPower", //7
"ptgConcat", //8
"ptgLT", //9
"ptgLE", //10
"ptgEQ", //11
"ptgGE", //12
"ptgGT", //13
"ptgNE", //14
"ptgIsect", //15
"ptgUnion", //16
"ptgRange", //17
"ptgUplus", //18
"ptgUminus", //19
"ptgPercent", //20
"ptgParen", //21
"ptgMissArg", //22
"ptgStr", //23
NULL,
"ptgAttr", //25
"ptgSheet", //26
"ptgEndSheet", //27
"ptgErr", //28
"ptgBool", //29
"ptgInt", //30
"ptgNum", //31
"ptgArray", //32
"ptgFunc", //33
"ptgFuncVar", //34
"ptgName", //35
"ptgRef", //36
"ptgArea", //37
"ptgMemArea", //38
"ptgMemErr", //39
"ptgMemNoMem", //40
"ptgMemFunc", //41
"ptgRefErr", //42
"ptgAreaErr", //43
"ptgRefN", //44
"ptgAreaN", //45
"ptgMemAreaN", //46
"ptgMemNoMemN", //47
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"ptgNameX", //57
"ptgRef3d", //58
"ptgArea3d", //59
"ptgRefErr3d", //60
"ptgAreaErr3d", //61
NULL,
NULL,
"ptgArrayV", //64
"ptgFuncV", //65
"ptgFuncVarV", //66
"ptgNameV", //67
"ptgRefV", //68
"ptgAreaV", //69
"ptgMemAreaV", //70
"ptgMemErrV", //71
"ptgMemNoMemV", //72
"ptgMemFuncV", //73
"ptgRefErrV", //74
"ptgAreaErrV", //75
"ptgRefNV", //76
"ptgAreaNV", //77
"ptgMemAreaNV", //78
"ptgMemNoMemNV", //79
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"ptgFuncCEV", //88
"ptgNameXV", //89
"ptgRef3dV", //90
"ptgArea3dV", //91
"ptgRefErr3dV", //92
"ptgAreaErr3dV", //93
NULL,
NULL,
"ptgArrayA", //96
"ptgFuncA", //97
"ptgFuncVarA", //98
"ptgNameA", //99
"ptgRefA", //100
"ptgAreaA", //101
"ptgMemAreaA", //102
"ptgMemErrA", //103
"ptgMemNoMemA", //104
"ptgMemFuncA", //105
"ptgRefErrA", //106
"ptgAreaErrA", //107
"ptgRefNA", //108
"ptgAreaNA", //109
"ptgMemAreaNA", //110
"ptgMemNoMemNA", //111
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"ptgFuncCEA", //120
"ptgNameXA", //121
"ptgRef3dA", //122
"ptgArea3dA", //123
"ptgRefErr3dA", //124
"ptgAreaErr3dA", //125
};
// clang-format on
typedef enum ptg_expr {
ptgExp = 0x01,
ptgTbl = 0x02,
ptgAdd = 0x03,
ptgSub = 0x04,
ptgMul = 0x05,
ptgDiv = 0x06,
ptgPower = 0x07,
ptgConcat = 0x08,
ptgLt = 0x09,
ptgLe = 0x0A,
ptgEq = 0x0B,
ptgGe = 0x0C,
ptgGt = 0x0D,
ptgNe = 0x0E,
ptgIsect = 0x0F,
ptgUnion = 0x10,
ptgRange = 0x11,
ptgUplus = 0x12,
ptgUminus = 0x13,
ptgPercent = 0x14,
ptgParen = 0x15,
ptgMissArg = 0x16,
ptgStr = 0x17,
ptgEscape1 = 0x18,
ptgAttr = 0x19,
ptgErr = 0x1C,
ptgBool = 0x1D,
ptgInt = 0x1E,
ptgNum = 0x1F,
ptgArray = 0x20,
ptgFunc = 0x21,
ptgFuncVar = 0x22,
ptgName = 0x23,
ptgRef = 0x24,
ptgArea = 0x25,
ptgMemArea = 0x26,
ptgMemErr = 0x27,
ptgMemNoMem = 0x28,
ptgMemFunc = 0x29,
ptgRefErr = 0x2A,
ptgAreaErr = 0x2B,
ptgRefN = 0x2C,
ptgAreaN = 0x2D,
ptgNameX = 0x39,
ptgRef3d = 0x3A,
ptgArea3d = 0x3B,
ptgRefErr3d = 0x3C,
ptgAreaErr3d = 0x3D,
ptgArrayV = 0x40,
ptgFuncV = 0x41,
ptgFuncVarV = 0x42,
ptgNameV = 0x43,
ptgRefV = 0x44,
ptgAreaV = 0x45,
ptgMemAreaV = 0x46,
ptgMemErrV = 0x47,
ptgMemNoMemV = 0x48,
ptgMemFuncV = 0x49,
ptgRefErrV = 0x4A,
ptgAreaErrV = 0x4B,
ptgRefNV = 0x4C,
ptgAreaNV = 0x4D,
ptgNameXV = 0x59,
ptgRef3dV = 0x5A,
ptgArea3dV = 0x5B,
ptgRefErr3dV = 0x5C,
ptgAreaErr3dV = 0x5D,
ptgArrayA = 0x60,
ptgFuncA = 0x61,
ptgFuncVarA = 0x62,
ptgNameA = 0x63,
ptgRefA = 0x64,
ptgAreaA = 0x65,
ptgMemAreaA = 0x66,
ptgMemErrA = 0x67,
ptgMemNoMemA = 0x68,
ptgMemFuncA = 0x69,
ptgRefErrA = 0x6A,
ptgAreaErrA = 0x6B,
ptgRefNA = 0x6C,
ptgAreaNA = 0x6D,
ptgNameXA = 0x79,
ptgRef3dA = 0x7A,
ptgArea3dA = 0x7B,
ptgRefErr3dA = 0x7C,
ptgAreaErr3dA = 0x7D,
} ptg_expr;
#ifndef HAVE_ATTRIB_PACKED
#define __attribute__(x)
#endif
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
#ifdef HAVE_PRAGMA_PACK_HPPA
#pragma pack 1
#endif
/**
* @brief The OfficeArtRecordHeader fined on page 27 of the MSO-ODRAW specification:
* https://interoperability.blob.core.windows.net/files/MS-ODRAW/%5bMS-ODRAW%5d.pdf
*
* We'll use this to extract images found in office documents.
*/
struct OfficeArtRecordHeader_PackedLittleEndian {
uint16_t recVerAndInstance; // 4 bytes for recVer, 12 bytes for recInstance
uint16_t recType;
uint32_t recLen;
} __attribute__((packed));
/**
* @brief The OfficeArtFBSE structure following its record header.
* See section 2.2.32 OfficeArtFBSE in:
* https://interoperability.blob.core.windows.net/files/MS-ODRAW/%5bMS-ODRAW%5d.pdf
*
* Does not include the variable size nameData
*/
struct OfficeArtFBSE_PackedLittleEndian {
uint8_t btWin32; // 1-byte enum containing a mso_blip_type value
uint8_t btMacOS; // 1-byte enum containing a mso_blip_type value
unsigned char rgbUid[16];
uint16_t tag;
uint32_t size; // size of the Blip stream
uint32_t cRef; // number of references to the Blip
uint32_t foDelay; // An MSOFOstructure, as defined in section 2.1.4, must be 0x00000000
uint8_t unused1; // unused
uint8_t cbName; // length of the name field, in bytes.
uint8_t unused2; // unused
uint8_t unused3; // unused
} __attribute__((packed));
#ifdef HAVE_PRAGMA_PACK
#pragma pack()
#endif
#ifdef HAVE_PRAGMA_PACK_HPPA
#pragma pack
#endif
struct OfficeArtRecordHeader_Unpacked {
uint16_t recVer;
uint16_t recInstance;
uint16_t recType;
uint32_t recLen;
} __attribute__((packed));
typedef enum {
msoblip_ERROR = 0x00, // Error reading the file.
msoblip_UNKNOWN = 0x01, // Unknown BLIPtype.
msoblip_EMF = 0x02, // EMF.
msoblip_WMF = 0x03, // WMF.
msoblip_PICT = 0x04, // Macintosh PICT.
msoblip_JPEG = 0x05, // JPEG.
msoblip_PNG = 0x06, // PNG.
msoblip_DIB = 0x07, // DIB
msoblip_TIFF = 0x11, // TIFF
msoblip_CMYKJPEG = 0x12, // JPEG in the YCCK or CMYK color space.
} mso_blip_type;
/**
* @brief Read the office art record header information from a buffer
*
* @param data data buffer starting with the record header
* @param data_len length of the buffer
* @param[in,out] unpacked_header fill this
* @return cl_error_t CL_SUCCESS if successfull, else some error code.
*/
static cl_error_t
read_office_art_record_header(const unsigned char *data, size_t data_len, struct OfficeArtRecordHeader_Unpacked *unpacked_header)
{
cl_error_t status = CL_EARG;
uint16_t recVerAndInstance;
struct OfficeArtRecordHeader_PackedLittleEndian *rawHeader;
if ((NULL == data) ||
(sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) > data_len) ||
(NULL == unpacked_header)) {
// invalid args
goto done;
}
rawHeader = (struct OfficeArtRecordHeader_PackedLittleEndian *)data;
recVerAndInstance = le16_to_host(rawHeader->recVerAndInstance);
unpacked_header->recVer = recVerAndInstance & 0x000F;
unpacked_header->recInstance = (recVerAndInstance & 0xFFF0) >> 4;
unpacked_header->recType = le16_to_host(rawHeader->recType);
unpacked_header->recLen = le32_to_host(rawHeader->recLen);
cli_dbgmsg("read_office_art_record_header: office art record:\n");
cli_dbgmsg("read_office_art_record_header: recVer 0x%x\n", unpacked_header->recVer);
cli_dbgmsg("read_office_art_record_header: recInstance 0x%x\n", unpacked_header->recInstance);
cli_dbgmsg("read_office_art_record_header: recType 0x%x\n", unpacked_header->recType);
cli_dbgmsg("read_office_art_record_header: recLen %u\n", unpacked_header->recLen);
status = CL_SUCCESS;
done:
return status;
}
static const char *get_function_name(unsigned index)
{
if (index < sizeof(FUNCTIONS) / sizeof(FUNCTIONS[0])) {
return FUNCTIONS[index];
} else if (index >= 0x8000 &&
(index - 0x8000 < sizeof(EXTENDED_FUNCTIONS) / sizeof(EXTENDED_FUNCTIONS[0]))) {
return EXTENDED_FUNCTIONS[index - 0x8000];
} else {
return NULL;
}
}
static cl_error_t parse_formula(FILE *out_file, char data[], unsigned data_size)
{
cl_error_t status = CL_EFORMAT;
unsigned data_pos = 0;
int len;
size_t size_written;
while (data_pos < data_size) {
ptg_expr ptg = data[data_pos] & 0x7f;
if (((uint8_t)data[data_pos]) < sizeof(TOKENS) / sizeof(TOKENS[0])) {
len = fprintf(out_file, " %s", TOKENS[ptg]);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting token name\n");
goto done;
}
}
switch (ptg) {
case ptgAdd:
case ptgSub:
case ptgMul:
case ptgDiv:
case ptgConcat:
case ptgLt:
case ptgLe:
case ptgEq:
case ptgGe:
case ptgGt:
case ptgNe:
case ptgMissArg:
case ptgRange:
data_pos += 1;
break;
case ptgStr:
if (data_pos + 2 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgStr record\n");
goto done;
}
if (data[data_pos + 2] == 1 && data_pos + 2 + 2 * data[data_pos + 1] <= data_size) {
char *utf8 = NULL;
size_t utf8_size = 0;
// TODO: Is this really times two here? Or is the string length in bytes?
size_t str_len = data[data_pos + 1] * 2;
if (str_len > data_size - data_pos) {
str_len = data_size - data_pos;
}
if (CL_SUCCESS == cli_codepage_to_utf8(&data[data_pos + 3], str_len, CODEPAGE_UTF16_LE, &utf8, &utf8_size)) {
if (0 < utf8_size) {
size_written = fwrite(utf8, 1, utf8_size, out_file);
free(utf8);
if (size_written < utf8_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error writing STRING record message with UTF16LE content\n");
goto done;
}
}
} else {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Failed to decode UTF16LE string in formula\n");
len = fprintf(out_file, "<Failed to decode UTF16LE string>");
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgStr message with UTF16LE content\n");
goto done;
}
}
data_pos += 3 + str_len;
} else if (data[data_pos + 2] == 0 && data_pos + 2 + data[data_pos + 1] <= data_size) {
unsigned str_len = data[data_pos + 1];
if (str_len > data_size - data_pos) {
str_len = data_size - data_pos;
}
if (0 < str_len) {
size_written = fwrite(&data[data_pos], 1, str_len, out_file);
if (size_written < str_len) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error writing STRING record message with UTF16LE content\n");
goto done;
}
}
data_pos += 3 + str_len;
} else {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Invalid or truncated string record!\n");
goto done;
}
break;
case ptgAttr:
if (data_pos + 1 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgAttr record\n");
goto done;
}
if (data[data_pos + 1] & 0x40) {
uint16_t coffset;
if (data_pos + 3 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgAttrChoose record\n");
goto done;
}
coffset = data[data_pos + 2] | (data[data_pos + 3] << 8);
len = fprintf(out_file, " CHOOSE (%u)", (unsigned)(coffset + 1));
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgAttr message\n");
goto done;
}
data_pos += 4 + 2 * (coffset + 1);
} else {
data_pos += 4;
}
break;
case ptgBool:
if (data_pos + 1 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgBool record\n");
goto done;
}
len = fprintf(out_file, " %s", data[data_pos + 1] ? "TRUE" : "FALSE");
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgBool message\n");
goto done;
}
data_pos += 2;
break;
case ptgInt:
if (data_pos + 2 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgInt record\n");
goto done;
}
len = fprintf(out_file, " %d", data[data_pos + 1] | (data[data_pos + 2] << 8));
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgInt message\n");
goto done;
}
data_pos += 3;
break;
case ptgFunc:
case ptgFuncV:
case ptgFuncA: {
if (data_pos + 2 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgFunc record\n");
goto done;
}
uint16_t func_id = data[data_pos + 1] | (data[data_pos + 2] << 8);
const char *func_name = get_function_name(func_id);
len = fprintf(out_file, " %s (0x%04x)", func_name == NULL ? "<unknown function>" : func_name, func_id);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgFunc message\n");
goto done;
}
data_pos += 3;
break;
}
case ptgFuncVar:
case ptgFuncVarV:
case ptgFuncVarA: {
if (data_pos + 3 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgFuncVar record\n");
goto done;
}
uint16_t func_id = data[data_pos + 2] | (data[data_pos + 3] << 8);
const char *func_name = get_function_name(func_id);
len = fprintf(
out_file,
" args %u func %s (0x%04x)",
(unsigned)data[data_pos + 1],
func_name == NULL ? "<unknown function>" : func_name,
func_id);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgFuncVar message\n");
goto done;
}
data_pos += 4;
if (func_id == 0x806d) {
data_pos += 9;
}
break;
}
case ptgName: {
if (data_pos + 4 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgName record\n");
goto done;
}
uint32_t val = data[data_pos + 1] | (data[data_pos + 2] << 8) | (data[data_pos + 3] << 16) | (data[data_pos + 4] << 24);
len = fprintf(out_file, " 0x%08x", val);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgName message\n");
goto done;
}
data_pos += 5;
break;
}
case ptgNum: {
if (data_pos + 8 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgNum record\n");
goto done;
}
double val = *(double *)&data[data_pos + 1];
len = fprintf(out_file, " %f", val);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgNum message\n");
goto done;
}
data_pos += 9;
break;
}
case ptgMemArea: {
if (data_pos + 6 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgMemArea record\n");
goto done;
}
len = fprintf(out_file, " REFERENCE-EXPRESSION");
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgMemArea message\n");
goto done;
}
data_pos += 7;
break;
}
case ptgExp: {
if (data_pos + 4 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgExp record\n");
goto done;
}
uint16_t row = data[data_pos + 1] | (data[data_pos + 2] << 8);
uint16_t column = data[data_pos + 3] | (data[data_pos + 4] << 8);
len = fprintf(out_file, " R%uC%u", (unsigned)(row + 1), (unsigned)(column + 1));
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgExp message\n");
goto done;
}
data_pos += 5;
break;
}
case ptgRef:
case ptgRefV: {
if (data_pos + 4 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgRef record\n");
goto done;
}
uint16_t row = data[data_pos + 1] | (data[data_pos + 2] << 8);
uint16_t column = data[data_pos + 3] | (data[data_pos + 4] << 8);
len = fprintf(
out_file,
" R%s%uC%s%u",
(row & (1 << 14)) ? "~" : "",
(unsigned)((row & 0x3fff) + ((row & (1 << 14)) ? 0 : 1)),
(row & (1 << 15)) ? "~" : "",
(unsigned)(column + ((row & (1 << 15)) ? 0 : 1)));
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgRef message\n");
goto done;
}
data_pos += 5;
break;
}
case ptgArea: {
if (data_pos + 8 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgArea record\n");
goto done;
}
uint16_t row1 = data[data_pos + 1] | (data[data_pos + 2] << 8);
uint16_t column1 = data[data_pos + 3] | (data[data_pos + 4] << 8);
uint16_t row2 = data[data_pos + 5] | (data[data_pos + 6] << 8);
uint16_t column2 = data[data_pos + 7] | (data[data_pos + 8] << 8);
len = fprintf(
out_file,
" R%s%uC%s%u:R%s%uC%s%u",
(row1 & (1 << 14)) ? "~" : "",
(unsigned)((row1 & 0x3fff) + ((row1 & (1 << 14)) ? 0 : 1)),
(row1 & (1 << 15)) ? "~" : "",
(unsigned)(column1 + ((row1 & (1 << 15)) ? 0 : 1)),
(row2 & (1 << 14)) ? "~" : "",
(unsigned)((row2 & 0x3fff) + ((row2 & (1 << 14)) ? 0 : 1)),
(row2 & (1 << 15)) ? "~" : "",
(unsigned)(column2 + ((row2 & (1 << 15)) ? 0 : 1)));
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgArea message\n");
goto done;
}
data_pos += 9;
break;
}
case ptgRef3d:
case ptgRef3dV: {
if (data_pos + 6 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgRef3d record\n");
goto done;
}
uint16_t row = data[data_pos + 3] | (data[data_pos + 4] << 8);
uint16_t column = data[data_pos + 5] | (data[data_pos + 6] << 8);
len = fprintf(
out_file,
" R%s%uC%s%u",
(row & (1 << 14)) ? "~" : "",
(unsigned)((row & 0x3fff) + ((row & (1 << 14)) ? 0 : 1)),
(row & (1 << 15)) ? "~" : "",
(unsigned)(column + ((row & (1 << 15)) ? 0 : 1)));
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgRef3d message\n");
goto done;
}
data_pos += 7;
break;
}
case ptgNameX: {
if (data_pos + 6 >= data_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Malformed ptgNameX record\n");
goto done;
}
uint16_t name = data[data_pos + 3] | (data[data_pos + 4] << 8);
len = fprintf(
out_file,
" NAMEIDX %u",
(unsigned)name);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Error formatting ptgNameX message\n");
goto done;
}
data_pos += 7;
break;
}
default:
if (ptg < sizeof(TOKENS) / sizeof(char *)) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Encountered unexpected ptg token: %s\n", TOKENS[ptg]);
} else {
cli_dbgmsg("[cli_extract_xlm_macros_and_images:parse_formula] Encountered unknown ptg token: 0x%02x\n", ptg);
}
goto done;
}
}
status = CL_SUCCESS;
done:
return status;
}
/**
* @brief Handle each type of Blip record. See section 2.2.23 OfficeArtBlip in:
* https://interoperability.blob.core.windows.net/files/MS-ODRAW/%5bMS-ODRAW%5d.pdf
*
* @param blip_store_container
* @param blip_store_container_len
* @param ctx
* @return cl_error_t
*/
cl_error_t process_blip_record(struct OfficeArtRecordHeader_Unpacked *rh, const unsigned char *index, size_t remaining, cli_ctx *ctx)
{
cl_error_t status = CL_EARG;
cl_error_t ret;
char *extracted_image_filepath = NULL;
int extracted_image_tempfd = -1;
size_t blip_bytes_before_image = 0; /* the number of bytes between the record header and the image */
const unsigned char *start_of_image = NULL;
size_t size_of_image = 0;
const char *extracted_image_type = NULL;
if (0x0 != rh->recVer) {
cli_dbgmsg("process_blip_store_container: Invalid recVer for Blip record header: %u\n", rh->recVer);
}
switch (rh->recType) {
case 0xF01A: { /* OfficeArtBlipEMF */
cli_dbgmsg("process_blip_store_container: Found OfficeArtBlipEMF (Enhanced Metafile Format)\n");
if (0x3D4 == rh->recInstance) {
blip_bytes_before_image += 16 + 34; /* 1 16-byte UID + 34-byte metafile header */
} else if (0x3D5 == rh->recInstance) {
blip_bytes_before_image += 32 + 34; /* 2 16-byte UIDs + 34-byte metafile header */
} else {
cli_dbgmsg("process_blip_store_container: Invalid recInstance for OfficeArtBlipEMF\n");
}
extracted_image_type = "EMF";
break;
}
case 0xF01B: { /* OfficeArtBlipWMF */
cli_dbgmsg("process_blip_store_container: Found OfficeArtBlipWMF (Windows Metafile Format)\n");
if (0x216 == rh->recInstance) {
blip_bytes_before_image += 16 + 34; /* 1 16-byte UID + 34-byte metafile header */
} else if (0x217 == rh->recInstance) {
blip_bytes_before_image += 32 + 34; /* 2 16-byte UIDs + 34-byte metafile header */
} else {
cli_dbgmsg("process_blip_store_container: Invalid recInstance for OfficeArtBlipWMF\n");
}
extracted_image_type = "WMF";
break;
}
case 0xF01C: { /* OfficeArtBlipPICT */
cli_dbgmsg("process_blip_store_container: Found OfficeArtBlipPICT (Macintosh PICT)\n");
if (0x542 == rh->recInstance) {
blip_bytes_before_image += 16 + 34; /* 1 16-byte UID + 34-byte metafile header */
} else if (0x543 == rh->recInstance) {
blip_bytes_before_image += 32 + 34; /* 2 16-byte UIDs + 34-byte metafile header */
} else {
cli_dbgmsg("process_blip_store_container: Invalid recInstance for OfficeArtBlipPICT\n");
}
extracted_image_type = "PICT";
break;
}
case 0xF01D: /* OfficeArtBlipJPEG */
case 0xF02A: { /* OfficeArtBlipJPEG */
cli_dbgmsg("process_blip_store_container: Found OfficeArtBlipJPEG\n");
if (0x46A == rh->recInstance || 0x6E2 == rh->recInstance) {
blip_bytes_before_image += 16 + 1; /* 1 16-byte UID + 1-byte tag */
} else if (0x46B == rh->recInstance || 0x6E3 == rh->recInstance) {
blip_bytes_before_image += 32 + 1; /* 2 16-byte UIDs + 1-byte tag */
} else {
cli_dbgmsg("process_blip_store_container: Invalid recInstance for OfficeArtBlipJPEG\n");
}
extracted_image_type = "JPEG";
break;
}
case 0xF01E: { /* OfficeArtBlipPNG */
cli_dbgmsg("process_blip_store_container: Found OfficeArtBlipPNG\n");
if (0x6E0 == rh->recInstance) {
blip_bytes_before_image += 16 + 1; /* 1 16-byte UID + 1-byte tag */
} else if (0x6E1 == rh->recInstance) {
blip_bytes_before_image += 32 + 1; /* 2 16-byte UIDs + 1-byte tag */
} else {
cli_dbgmsg("process_blip_store_container: Invalid recInstance for OfficeArtBlipPNG\n");
}
extracted_image_type = "PNG";
break;
}
case 0xF01F: { /* OfficeArtBlipDIB */
cli_dbgmsg("process_blip_store_container: Found OfficeArtBlipDIB (device independent bitmap)\n");
if (0x7A8 == rh->recInstance) {
blip_bytes_before_image += 16 + 1; /* 1 16-byte UID + 1-byte tag */
} else if (0x7A9 == rh->recInstance) {
blip_bytes_before_image += 32 + 1; /* 2 16-byte UIDs + 1-byte tag */
} else {
cli_dbgmsg("process_blip_store_container: Invalid recInstance for OfficeArtBlipDIB\n");
}
extracted_image_type = "DIB";
break;
}
case 0xF029: { /* OfficeArtBlipTIFF */
cli_dbgmsg("process_blip_store_container: Found OfficeArtBlipTIFF\n");
if (0x6E4 == rh->recInstance) {
blip_bytes_before_image += 16 + 1; /* 1 16-byte UID + 1-byte tag */
} else if (0x6E5 == rh->recInstance) {
blip_bytes_before_image += 32 + 1; /* 2 16-byte UIDs + 1-byte tag */
} else {
cli_dbgmsg("process_blip_store_container: Invalid recInstance for OfficeArtBlipTIFF\n");
}
extracted_image_type = "TIFF";
break;
}
default: {
cli_dbgmsg("Unknown OfficeArtBlip type!\n");
}
}
if (0 == blip_bytes_before_image) {
cli_dbgmsg("Was not able to identify the Blip type, skipping...\n");
} else if (remaining < sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + blip_bytes_before_image) {
cli_dbgmsg("Not enough remaining bytes in blip array for image data\n");
} else {
start_of_image = index + sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + blip_bytes_before_image;
size_of_image = MIN(rh->recLen, remaining - (sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + blip_bytes_before_image));
cli_dbgmsg("Scanning extracted image of size %zu\n", size_of_image);
if (ctx->engine->keeptmp) {
/* Drop a temp file and scan that */
if (CL_SUCCESS != (ret = cli_gentempfd_with_prefix(
ctx->sub_tmpdir,
extracted_image_type,
&extracted_image_filepath,
&extracted_image_tempfd))) {
cli_warnmsg("Failed to create temp file for extracted %s file\n", extracted_image_type);
status = CL_EOPEN;
goto done;
}
if (cli_writen(extracted_image_tempfd, start_of_image, size_of_image) != size_of_image) {
cli_errmsg("failed to write output file\n");
status = CL_EWRITE;
goto done;
}
ret = cli_magic_scan_desc_type(extracted_image_tempfd, extracted_image_filepath, ctx, CL_TYPE_ANY,
NULL, LAYER_ATTRIBUTES_NONE);
} else {
/* Scan the buffer */
ret = cli_magic_scan_buff(start_of_image, size_of_image, ctx, NULL, LAYER_ATTRIBUTES_NONE);
}
if (CL_SUCCESS != ret) {
status = ret;
goto done;
}
}
if (remaining < sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh->recLen) {
remaining = 0;
} else {
remaining -= sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh->recLen;
index += sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh->recLen;
}
status = CL_SUCCESS;
done:
if (-1 != extracted_image_tempfd) {
close(extracted_image_tempfd);
}
if (NULL != extracted_image_filepath) {
free(extracted_image_filepath);
}
return status;
}
/**
* @brief Process each Blip Store Container File Block in a Blip Store Container
*
* @param blip_store_container
* @param blip_store_container_len
* @param ctx
* @return cl_error_t
*/
cl_error_t process_blip_store_container(const unsigned char *blip_store_container, size_t blip_store_container_len, cli_ctx *ctx)
{
cl_error_t status = CL_EARG;
struct OfficeArtRecordHeader_Unpacked rh;
const unsigned char *index = blip_store_container;
size_t remaining = blip_store_container_len;
while (0 < remaining) {
if (CL_SUCCESS != read_office_art_record_header(index, remaining, &rh)) {
/* Failed to get header, abort. */
cli_dbgmsg("process_blip_store_container: Failed to get header\n");
goto done;
}
if (0x0 != rh.recVer) {
cli_dbgmsg("process_blip_store_container: Invalid recVer for Blip record header: %u\n", rh.recVer);
}
/*
* Handle each type of Blip Store Container File Block. See section 2.2.22 OfficeArtBStoreContainerFileBlock in:
* https://interoperability.blob.core.windows.net/files/MS-ODRAW/%5bMS-ODRAW%5d.pdf
*/
if (0xF007 == rh.recType) {
/* it's an OfficeArtFBSErecord */
cli_dbgmsg("process_blip_store_container: Found a File Blip Store Entry (FBSE) record\n");
if (0x2 != rh.recVer) {
cli_dbgmsg("process_blip_store_container: Invalid recVer for OfficeArtFBSErecord: 0x%x\n", rh.recVer);
}
if (sizeof(struct OfficeArtFBSE_PackedLittleEndian) > remaining - sizeof(struct OfficeArtRecordHeader_PackedLittleEndian)) {
cli_dbgmsg("process_blip_store_container: Not enough bytes for FSBE record data\n");
} else {
struct OfficeArtFBSE_PackedLittleEndian *FBSE_record_data = (struct OfficeArtFBSE_PackedLittleEndian *)(index + sizeof(struct OfficeArtRecordHeader_PackedLittleEndian));
if (FBSE_record_data->cbName > remaining - sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) - sizeof(struct OfficeArtFBSE_PackedLittleEndian)) {
cli_dbgmsg("process_blip_store_container: Not enough bytes for FSBE record data + blip file name\n");
} else {
struct OfficeArtRecordHeader_Unpacked embeddedBlip_rh;
const unsigned char *embeddedBlip;
size_t embeddedBlip_size;
char *blip_file_name = NULL;
char blip_name_buffer[256] = {0};
if (FBSE_record_data->cbName > 0) {
memcpy(blip_name_buffer,
(char *)(index +
sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) +
sizeof(struct OfficeArtFBSE_PackedLittleEndian)),
(size_t)FBSE_record_data->cbName);
blip_name_buffer[FBSE_record_data->cbName] = '\0';
blip_file_name = blip_name_buffer;
cli_dbgmsg("Blip file name: %s\n", blip_file_name);
}
embeddedBlip = (const unsigned char *)(index +
sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) +
sizeof(struct OfficeArtFBSE_PackedLittleEndian) +
(size_t)FBSE_record_data->cbName);
embeddedBlip_size = remaining -
sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) -
sizeof(struct OfficeArtFBSE_PackedLittleEndian) -
(size_t)FBSE_record_data->cbName;
if (le32_to_host(FBSE_record_data->size) > embeddedBlip_size) {
cli_dbgmsg("process_blip_store_container: WARNING: The File Blip Store Entry claims that the Blip data is bigger than the remaining bytes in the record!\n");
cli_dbgmsg("process_blip_store_container: %d > %zu!\n", le32_to_host(FBSE_record_data->size), embeddedBlip_size);
} else {
/* limit embeddedBlip_size to the size of what's actually left */
embeddedBlip_size = le32_to_host(FBSE_record_data->size);
}
if (CL_SUCCESS != read_office_art_record_header(embeddedBlip, embeddedBlip_size, &embeddedBlip_rh)) {
/* Failed to get header, abort. */
cli_dbgmsg("process_blip_store_container: Failed to get header\n");
goto done;
}
status = process_blip_record(&embeddedBlip_rh, embeddedBlip, embeddedBlip_size, ctx);
if (CL_SUCCESS != status) {
goto done;
}
}
}
} else if ((0xF018 <= rh.recType) && (0xF117 >= rh.recType)) {
/* it's an OfficeArtBlip record */
cli_dbgmsg("process_blip_store_container: Found a Blip record\n");
status = process_blip_record(&rh, index, remaining, ctx);
if (CL_SUCCESS != status) {
goto done;
}
} else {
/* unexpected record type. */
cli_dbgmsg("process_blip_store_container: Unexpected record type\n");
}
if (remaining < sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh.recLen) {
remaining = 0;
} else {
remaining -= sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh.recLen;
index += sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh.recLen;
}
}
status = CL_SUCCESS;
done:
return status;
}
cl_error_t cli_extract_images_from_drawing_group(const unsigned char *drawinggroup, size_t drawinggroup_len, cli_ctx *ctx)
{
cl_error_t status = CL_EARG;
struct OfficeArtRecordHeader_Unpacked rh;
const unsigned char *index = drawinggroup;
size_t remaining = drawinggroup_len;
if (NULL == drawinggroup || 0 == drawinggroup_len) {
cli_dbgmsg("cli_extract_images_from_drawing_group: Invalid arguments\n");
goto done;
}
if (CL_SUCCESS != read_office_art_record_header(drawinggroup, drawinggroup_len, &rh)) {
/* Failed to get header, abort. */
cli_dbgmsg("cli_extract_images_from_drawing_group: Failed to get drawing group record header\n");
goto done;
}
if (!((0xF == rh.recVer) &&
(0x000 == rh.recInstance) &&
(0xF000 == rh.recType))) {
/* Invalid record values for drawing group record header */
cli_dbgmsg("cli_extract_images_from_drawing_group: Invalid record values for drawing group record header\n");
goto done;
}
if (rh.recLen > drawinggroup_len) {
/* Record header claims to be longer than our drawing group buffer */
cli_dbgmsg("cli_extract_images_from_drawing_group: Record header claims to be longer than our drawing group buffer:\n");
cli_dbgmsg("cli_extract_images_from_drawing_group: %u > %zu\n", rh.recLen, drawinggroup_len);
}
/* Looks like we really found an Office Art Drawing Group (container).
* See section 2.2.12 OfficeArtDggContainer in:
* https://interoperability.blob.core.windows.net/files/MS-ODRAW/%5bMS-ODRAW%5d.pdf */
cli_dbgmsg("cli_extract_images_from_drawing_group: Found drawing group of size %u bytes\n", rh.recLen);
/* Just skip over this first header */
if (remaining < sizeof(struct OfficeArtRecordHeader_PackedLittleEndian)) {
remaining = 0;
} else {
remaining -= sizeof(struct OfficeArtRecordHeader_PackedLittleEndian);
index += sizeof(struct OfficeArtRecordHeader_PackedLittleEndian);
}
while (0 < remaining) {
if (CL_SUCCESS != read_office_art_record_header(index, remaining, &rh)) {
/* Failed to get header, abort. */
cli_dbgmsg("cli_extract_images_from_drawing_group: Failed to get header\n");
goto done;
}
if (sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) > remaining) {
cli_dbgmsg("cli_extract_images_from_drawing_group: Not enough data remaining for BLIP store.\n");
goto done;
}
if ((0xF == rh.recVer) &&
(0xF001 == rh.recType)) {
/* Looks like we found a BLIP store container (array of OfficeArtBStoreContainerFileBlock records)
* See section 2.2.20 OfficeArtBStoreContainer in:
* https://interoperability.blob.core.windows.net/files/MS-ODRAW/%5bMS-ODRAW%5d.pdf */
const unsigned char *start_of_blip_store_container = index + sizeof(struct OfficeArtRecordHeader_PackedLittleEndian);
size_t blip_store_container_len = remaining - sizeof(struct OfficeArtRecordHeader_PackedLittleEndian);
cli_dbgmsg("cli_extract_images_from_drawing_group: Found an OfficeArtBStoreContainerFileBlock (Blip store).\n");
cli_dbgmsg("cli_extract_images_from_drawing_group: size: %u bytes, contains: %u file block records\n",
rh.recLen, rh.recInstance);
if (rh.recLen > blip_store_container_len) {
cli_dbgmsg("cli_extract_images_from_drawing_group: WARNING: The blip store header claims to be bigger than the remaining bytes in the drawing group!\n");
cli_dbgmsg("cli_extract_images_from_drawing_group: %d > %zu!\n", rh.recLen, blip_store_container_len);
} else {
/* limit rgfb enumeration to the size of the blip store */
blip_store_container_len = rh.recLen;
}
status = process_blip_store_container(start_of_blip_store_container, blip_store_container_len, ctx);
if (CL_SUCCESS != status) {
goto done;
}
}
if (remaining < sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh.recLen) {
remaining = 0;
} else {
remaining -= sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh.recLen;
index += sizeof(struct OfficeArtRecordHeader_PackedLittleEndian) + rh.recLen;
}
}
status = CL_SUCCESS;
done:
return status;
}
cl_error_t cli_extract_xlm_macros_and_images(const char *dir, cli_ctx *ctx, char *hash, uint32_t which)
{
cl_error_t status = CL_SUCCESS;
cl_error_t ret;
char fullname[PATH_MAX];
int in_fd = -1, out_fd = -1;
FILE *out_file = NULL;
const char *opcode_name;
char *tempfile = NULL;
char *data = NULL;
int len;
size_t size_written;
size_t size_read;
struct {
uint16_t opcode;
uint16_t length;
} __attribute__((packed)) biff_header;
const char FILE_HEADER[] = "-- BIFF content extracted and disassembled from CL_TYPE_MSXL .xls file because a XLM macro was found in the document\n";
unsigned char *drawinggroup = NULL;
size_t drawinggroup_len = 0;
biff8_opcode previous_biff8_opcode = 0x0; // Initialize to 0x0, which isn't even in our enum.
// This variable will allow the OPC_CONTINUE record
// to know which record it is continuing.
snprintf(fullname, sizeof(fullname), "%s" PATHSEP "%s_%u", dir, hash, which);
fullname[sizeof(fullname) - 1] = '\0';
in_fd = open(fullname, O_RDONLY | O_BINARY);
if (in_fd == -1) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Failed to open input file\n");
/* Don't return an error. If the file is missing, an error probably occured
* earlier, such as a UTF8 conversion error in parse_formula() and so the file was never written.
* There are no macros to scan, so report SUCCESS / CLEAN. */
goto done;
}
if ((ret = cli_gentempfd_with_prefix(ctx->sub_tmpdir, "xlm_macros", &tempfile, &out_fd)) != CL_SUCCESS) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Failed to open output file descriptor\n");
status = ret;
goto done;
}
out_file = fdopen(out_fd, "wb");
if (NULL == out_file) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Failed to open output file pointer\n");
goto done;
}
if ((data = malloc(BIFF8_MAX_RECORD_LENGTH)) == NULL) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Failed to allocate memory for BIFF data\n");
status = CL_EMEM;
goto done;
}
if (cli_writen(out_fd, FILE_HEADER, sizeof(FILE_HEADER) - 1) != sizeof(FILE_HEADER) - 1) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Failed to write header\n");
status = CL_EWRITE;
goto done;
}
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Extracting macros to %s\n", tempfile);
while (sizeof(biff_header) == (size_read = cli_readn(in_fd, &biff_header, sizeof(biff_header)))) {
biff_header.opcode = le16_to_host(biff_header.opcode);
biff_header.length = le16_to_host(biff_header.length);
if (biff_header.opcode < sizeof(OPCODE_NAMES) / sizeof(OPCODE_NAMES[0])) {
opcode_name = OPCODE_NAMES[biff_header.opcode];
} else {
opcode_name = NULL;
}
len = fprintf(out_file, "%04x %6d %s", biff_header.opcode, biff_header.length, opcode_name == NULL ? "<unknown>" : opcode_name);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error formatting opcode message\n");
status = CL_EFORMAT;
goto done;
}
len = 0;
if (biff_header.length > BIFF8_MAX_RECORD_LENGTH) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Record size exceeds maximum allowed\n");
status = CL_EFORMAT;
goto done;
}
if (cli_readn(in_fd, data, biff_header.length) != biff_header.length) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Failed to read BIFF record data\n");
status = CL_EREAD;
goto done;
}
switch (biff_header.opcode) {
case OPC_FORMULA: {
struct {
uint16_t row;
uint16_t column;
uint16_t length;
} formula_header;
if (biff_header.length >= 21) {
formula_header.row = data[0] | (data[1] << 8);
formula_header.column = data[2] | (data[3] << 8);
formula_header.length = data[20] | (data[21] << 8);
len = fprintf(
out_file,
" - R%dC%d len=%d ",
(unsigned)(formula_header.row + 1),
(unsigned)(formula_header.column + 1),
formula_header.length);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error formatting FORMULA record message\n");
// Move along to the next record.
break;
}
ret = parse_formula(out_file, &data[22], biff_header.length - 21);
if (CL_SUCCESS != ret) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error parsing formula in FORMULA record message\n");
// Move along to the next record.
break;
}
// formula successfully parsed.
}
break;
}
case OPC_NAME: {
if (biff_header.length >= 16) {
if (data[0] & 0x20) {
char code = data[14] != 0 ? data[14] : data[15];
char *name;
switch (code) {
case 1:
name = "auto_open";
break;
case 2:
name = "auto_close";
break;
default:
name = "?";
break;
}
len = fprintf(out_file, " - built-in-name %u %s", (unsigned)code, name);
} else {
int name_len = data[3] | (data[4] << 8);
size_t offset = data[14] != 0 ? 14 : 15;
name_len = min(name_len, (int)(biff_header.length - offset));
len = fprintf(out_file, " - %.*s", name_len, &data[offset]);
}
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error formatting NAME record message\n");
// Move along to the next record.
break;
}
// name record successfully parsed
} else {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Skipping broken NAME record (length %u)\n", biff_header.length);
}
break;
}
case OPC_MSODRAWINGGROUP: {
/*
* Extract the entire drawing group before we parse it.
*/
if (NULL == drawinggroup) {
/* Found beginning of a drawing group */
drawinggroup_len = (size_t)biff_header.length;
drawinggroup = malloc(drawinggroup_len);
memcpy(drawinggroup, data, drawinggroup_len);
// cli_dbgmsg("Collected %zu drawing group bytes\n", drawinggroup_len);
} else {
/* already found the beginning of a drawing group, extract the remaining chunks */
drawinggroup_len += biff_header.length;
CLI_REALLOC(drawinggroup, drawinggroup_len, status = CL_EMEM);
memcpy(drawinggroup + (drawinggroup_len - biff_header.length), data, biff_header.length);
// cli_dbgmsg("Collected %d drawing group bytes\n", biff_header.length);
}
break;
}
case OPC_CONTINUE: {
if ((OPC_MSODRAWINGGROUP == previous_biff8_opcode) &&
(NULL != drawinggroup)) {
/* already found the beginning of an image, extract the remaining chunks */
drawinggroup_len += biff_header.length;
CLI_REALLOC(drawinggroup, drawinggroup_len, status = CL_EMEM);
memcpy(drawinggroup + (drawinggroup_len - biff_header.length), data, biff_header.length);
// cli_dbgmsg("Collected %d image bytes\n", biff_header.length);
}
break;
}
case OPC_BOUNDSHEET: {
if (biff_header.length >= 6) {
const char *sheet_type;
const char *sheet_state;
switch (data[4]) {
case 0:
sheet_state = "visible";
break;
case 1:
sheet_state = "hidden";
break;
case 2:
sheet_state = "very hidden";
break;
default:
sheet_state = "unknown visibility";
break;
}
switch (data[5]) {
case 0:
sheet_type = "worksheet or dialog sheet";
break;
case 1:
sheet_type = "Excel 4.0 macro sheet";
break;
case 2:
sheet_type = "chart";
break;
case 6:
sheet_type = "Visual Basic module";
break;
default:
sheet_type = "unknown type";
break;
}
len = fprintf(out_file, " - %s, %s", sheet_type, sheet_state);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error formatting BOUNDSHEET record message\n");
// Move along to the next record.
break;
}
// boundsheet record successfully parsed
} else {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Skipping broken BOUNDSHEET record (length %u)\n", biff_header.length);
}
break;
}
case OPC_STRING: {
// Documented in Microsoft Office Excel97-2007Binary File Format (.xls) Specification
// Page 17: Unicode Strings in BIFF8
if (biff_header.length >= 4) {
uint16_t string_length = data[0] | (data[1] << 8);
uint8_t flags = data[2];
if (flags & 0x4) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] East Asian extended strings not implemented\n");
}
if (flags & 0x8) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Rich strings not implemented\n");
}
if (!(flags & 0x1)) {
// String is compressed
len = fprintf(out_file, " - \"%.*s\"", (int)(biff_header.length - 3), &data[6]);
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error formatting STRING record message with ANSI content\n");
// Move along to the next record.
break;
}
} else {
char *utf8 = NULL;
size_t utf8_size = 0;
len = fprintf(out_file, " - ");
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error formatting STRING record message with UTF16 content\n");
// Move along to the next record.
break;
}
if (string_length > biff_header.length - 3) {
string_length = biff_header.length - 3;
}
if (CL_SUCCESS == cli_codepage_to_utf8(&data[3], string_length, CODEPAGE_UTF16_LE, &utf8, &utf8_size)) {
if (0 < utf8_size) {
size_written = fwrite(utf8, 1, utf8_size, out_file);
free(utf8);
if (size_written < utf8_size) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error writing STRING record message with UTF16LE content\n");
goto done;
}
}
} else {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Failed to decode UTF16LE string\n");
len = fprintf(out_file, "<Failed to decode UTF16LE string>");
if (len < 0) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error formatting STRING record message with UTF16LE content\n");
goto done;
}
}
}
} else {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Skipping broken STRING record (length %u)\n", biff_header.length);
// Move along to the next record.
break;
}
// Not implemented. See Microsoft Office Excel97-2007Binary File Format (.xls) Specification Page 18 for details.
break;
}
default: {
break;
}
}
len = fputc('\n', out_file);
if (len == EOF) {
cli_dbgmsg("[cli_extract_xlm_macros_and_images] Error writing new line to out file\n");
goto done;
}
/* Keep track of which biff record we're continuing if we encounter OPC_CONTINUE */
if (OPC_CONTINUE != biff_header.opcode) {
previous_biff8_opcode = biff_header.opcode;
}
}
/* Scan the extracted content */
if (lseek(out_fd, 0, SEEK_SET) != 0) {
cli_dbgmsg("cli_extract_xlm_macros_and_images: Failed to seek to beginning of temporary file\n");
status = CL_ESEEK;
goto done;
}
if (CL_VIRUS == cli_scan_desc(out_fd, ctx, CL_TYPE_SCRIPT, false, NULL, AC_SCAN_VIR,
NULL, NULL, LAYER_ATTRIBUTES_NONE)) {
status = CL_VIRUS;
goto done;
}
/* If a read failed, return with an error. */
if (size_read == (size_t)-1) {
cli_dbgmsg("cli_extract_xlm_macros_and_images: Read error occured when trying to read BIFF header. Truncated or malformed XLM macro file?\n");
status = CL_EREAD;
goto done;
}
if (NULL != drawinggroup) {
/*
* A drawing group was extracted, now we need to find all the images inside.
* If we fail to extract images, that's fine.
*/
ret = cli_extract_images_from_drawing_group(drawinggroup, drawinggroup_len, ctx);
if (CL_SUCCESS != ret) {
status = ret;
goto done;
}
}
status = CL_SUCCESS;
done:
FREE(drawinggroup);
if (in_fd != -1) {
close(in_fd);
in_fd = -1;
}
if (NULL != out_file) {
fclose(out_file);
out_file = NULL;
} else if (-1 != out_fd) {
close(out_fd);
out_fd = -1;
}
FREE(data);
FREE(tempfile);
return status;
}