-
Notifications
You must be signed in to change notification settings - Fork 1
/
OriginAnyParser.cpp
3006 lines (2613 loc) · 95.8 KB
/
OriginAnyParser.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* OriginAnyParser.cpp
*
* Copyright 2017 Miquel Garriga <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
*
* Parser for all versions. Based mainly on Origin750Parser.cpp
*/
#include "OriginAnyParser.h"
#include <sstream>
#include <cinttypes>
#include <iostream>
/* define a macro to get an int (or uint) from a istringstream in binary mode */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define GET_SHORT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 2);};
#define GET_INT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 4);};
#define GET_FLOAT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 4);};
#define GET_DOUBLE(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 8);};
#else
void inline swap_bytes(unsigned char* data, int size) {int i = 0, j = size - 1; while(i < j) {std::swap(data[i], data[j]); ++i, --j;}}
#define GET_SHORT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 2); swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 2);};
#define GET_INT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 4); swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 4);};
#define GET_FLOAT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 4); swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 4);};
#define GET_DOUBLE(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 8); swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 8);};
#endif
OriginAnyParser::OriginAnyParser(const string& fileName)
: file(fileName.c_str(),ios::binary),
logfile(nullptr),
d_file_size(0),
curpos(0),
objectIndex(0),
parseError(0),
ispread(-1),
imatrix(-1),
iexcel(-1),
igraph(-1),
ilayer(-1) {
}
bool OriginAnyParser::parse() {
#ifdef GENERATE_CODE_FOR_LOG
// append progress in log file
logfile = fopen("opjfile.log","a");
#endif // GENERATE_CODE_FOR_LOG
// get length of file:
file.seekg (0, ios_base::end);
d_file_size = file.tellg();
file.seekg(0, ios_base::beg);
LOG_PRINT(logfile, "File size: %" PRId64 "\n", d_file_size)
// get file and program version, check it is a valid file
readFileVersion();
if (parseError > 1) return false;
curpos = file.tellg();
LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
// get global header
readGlobalHeader();
if (parseError > 1) return false;
curpos = file.tellg();
LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
// get dataset list
unsigned int dataset_list_size = 0;
objectIndex = 0; // use it to count DataSets
LOG_PRINT(logfile, "Reading Data sets ...\n")
while (true) {
if (!readDataSetElement()) break;
dataset_list_size++;
}
if (parseError > 1) return false;
LOG_PRINT(logfile, " ... done. Data sets: %d\n", dataset_list_size)
curpos = file.tellg();
LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
for(unsigned int i = 0; i < spreadSheets.size(); ++i){
if(spreadSheets[i].sheets > 1){
LOG_PRINT(logfile, " CONVERT SPREADSHEET \"%s\" to EXCEL\n", spreadSheets[i].name.c_str());
convertSpreadToExcel(i);
--i;
}
}
// get window list
unsigned int window_list_size = 0;
objectIndex = 0; // reset it to count Windows (except Notes)
LOG_PRINT(logfile, "Reading Windows ...\n")
while (true) {
if (!readWindowElement()) break;
window_list_size++;
}
LOG_PRINT(logfile, " ... done. Windows: %d\n", window_list_size)
curpos = file.tellg();
LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
// get parameter list
unsigned int parameter_list_size = 0;
LOG_PRINT(logfile, "Reading Parameters ...\n")
while (true) {
if (!readParameterElement()) break;
parameter_list_size++;
}
LOG_PRINT(logfile, " ... done. Parameters: %d\n", parameter_list_size)
curpos = file.tellg();
LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
// Note windows were added between version >4.141 and 4.210,
// i.e., with Release 5.0
if (curpos < d_file_size) {
// get note windows list
unsigned int note_list_size = 0;
LOG_PRINT(logfile, "Reading Note windows ...\n")
objectIndex = 0; // reset it to count Notes
while (true) {
if (!readNoteElement()) break;
note_list_size++;
}
LOG_PRINT(logfile, " ... done. Note windows: %d\n", note_list_size)
curpos = file.tellg();
LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
}
// Project Tree was added between version >4.210 and 4.2616,
// i.e., with Release 6.0
if (curpos < d_file_size) {
// get project tree
readProjectTree();
curpos = file.tellg();
LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
}
// Attachments were added between version >4.2673_558 and 4.2764_623,
// i.e., with Release 7.0
if (curpos < d_file_size) {
readAttachmentList();
curpos = file.tellg();
LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
}
if (curpos >= d_file_size) LOG_PRINT(logfile, "Now at end of file\n")
#ifdef GENERATE_CODE_FOR_LOG
fclose(logfile);
#endif // GENERATE_CODE_FOR_LOG
return true;
}
string toLowerCase(string str){
for (unsigned int i = 0; i < str.length(); i++)
if (str[i] >= 0x41 && str[i] <= 0x5A)
str[i] = str[i] + 0x20;
return str;
}
OriginParser* createOriginAnyParser(const string& fileName)
{
return new OriginAnyParser(fileName);
}
unsigned int OriginAnyParser::readObjectSize() {
unsigned int obj_size = 0;
char c = 0;
file >> obj_size;
file >> c;
if (c != '\n') {
curpos = file.tellg();
LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, curpos)
parseError = 3;
return 0;
}
return obj_size;
}
string OriginAnyParser::readObjectAsString(unsigned int size) {
char c;
// read a size-byte blob of data followed by '\n'
if (size > 0) {
// get a string large enough to hold the result, initialize it to all 0's
string blob = string(size, '\0');
// read data into that string
// cannot use '>>' operator because iendianfstream truncates it at first '\0'
file.read(&blob[0], size);
// read the '\n'
file >> c;
if (c != '\n') {
curpos = file.tellg();
LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, curpos)
parseError = 4;
return string();
}
return blob;
}
return string();
}
void OriginAnyParser::readFileVersion() {
// get file and program version, check it is a valid file
string sFileVersion;
getline(file, sFileVersion);
if ((sFileVersion.substr(0,4) != "CPYA")) {
LOG_PRINT(logfile, "File, is not a valid OPJ file\n")
if ((sFileVersion.substr(0,5) != "CPYUA")) {
LOG_PRINT(logfile, "File, is not a valid OPJU file\n")
parseError = 2;
return;
}
}
if (*sFileVersion.rbegin() != '#') parseError = 1;
LOG_PRINT(logfile, "File version string: %s\n", sFileVersion.c_str())
}
void OriginAnyParser::readGlobalHeader() {
// get global header size
unsigned int gh_size = 0, gh_endmark = 0;
gh_size = readObjectSize();
curpos = file.tellg();
LOG_PRINT(logfile, "Global header size: %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "],", gh_size, gh_size, curpos, curpos)
// get global header data
string gh_data;
gh_data = readObjectAsString(gh_size);
curpos = file.tellg();
LOG_PRINT(logfile, " ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
// when gh_size > 0x1B, a double with fileVersion/100 can be read at gh_data[0x1B:0x23]
if (gh_size > 0x1B) {
istringstream stmp;
stmp.str(gh_data.substr(0x1B));
double dFileVersion;
GET_DOUBLE(stmp, dFileVersion)
if (dFileVersion > 8.5) {
fileVersion = (unsigned int)trunc(dFileVersion*100.);
} else {
fileVersion = 10*(unsigned int)trunc(dFileVersion*10.);
}
LOG_PRINT(logfile, "Project version as read from header: %.2f (%.6f)\n", fileVersion/100.0, dFileVersion)
}
// now read a zero size end mark
gh_endmark = readObjectSize();
if (gh_endmark != 0) {
curpos = file.tellg();
LOG_PRINT(logfile, "Wrong end of list mark %d at %" PRId64 " [0x%" PRIx64 "]\n", gh_endmark, curpos, curpos)
parseError = 5;
return;
}
}
bool OriginAnyParser::readDataSetElement() {
/* get info and values of a DataSet (worksheet column, matrix sheet, ...)
* return true if a DataSet is found, otherwise return false */
unsigned int dse_header_size = 0, dse_data_size = 0, dse_mask_size = 0;
std::streamoff dsh_start = 0, dsd_start = 0, dsm_start = 0;
string dse_header;
// get dataset header size
dse_header_size = readObjectSize();
if (dse_header_size == 0) return false;
curpos = file.tellg();
dsh_start = curpos;
LOG_PRINT(logfile, "Column: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "], ", dse_header_size, dse_header_size, curpos, curpos)
dse_header = readObjectAsString(dse_header_size);
// get known info
string name(25,0);
name = dse_header.substr(0x58,25);
// go to end of dataset header, get data size
file.seekg(dsh_start+dse_header_size+1, ios_base::beg);
dse_data_size = readObjectSize();
dsd_start = file.tellg();
string dse_data = readObjectAsString(dse_data_size);
curpos = file.tellg();
LOG_PRINT(logfile, "data size %d [0x%X], from %" PRId64 " [0x%" PRIx64 "] to %" PRId64 " [0x%" PRIx64 "],", dse_data_size, dse_data_size, dsd_start, dsd_start, curpos, curpos)
// get data values
getColumnInfoAndData(dse_header, dse_header_size, dse_data, dse_data_size);
// go to end of data values, get mask size (often zero)
file.seekg(dsd_start+dse_data_size, ios_base::beg); // dse_data_size can be zero
if (dse_data_size > 0) file.seekg(1, ios_base::cur);
dse_mask_size = readObjectSize();
dsm_start = file.tellg();
if (dse_mask_size > 0) LOG_PRINT(logfile, "\nmask size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]", dse_mask_size, dse_mask_size, dsm_start, dsm_start)
string dse_mask = readObjectAsString(dse_mask_size);
// get mask values
if (dse_mask_size > 0) {
curpos = file.tellg();
LOG_PRINT(logfile, ", ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
// TODO: extract mask values from dse_mask
// go to end of dataset mask
file.seekg(dsm_start+dse_mask_size+1, ios_base::beg);
}
curpos = file.tellg();
LOG_PRINT(logfile, " ends at %" PRId64 " [0x%" PRIx64 "]: ", curpos, curpos)
LOG_PRINT(logfile, "%s\n", name.c_str())
return true;
}
bool OriginAnyParser::readWindowElement() {
/* get general info and details of a window
* return true if a Window is found, otherwise return false */
unsigned int wde_header_size = 0;
std::streamoff wdh_start = 0;
// get window header size
wde_header_size = readObjectSize();
if (wde_header_size == 0) return false;
curpos = file.tellg();
wdh_start = curpos;
LOG_PRINT(logfile, "Window found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]: ", wde_header_size, wde_header_size, curpos, curpos)
string wde_header = readObjectAsString(wde_header_size);
// get known info
string name(25,0);
name = wde_header.substr(0x02,25).c_str();
LOG_PRINT(logfile, "%s\n", name.c_str())
// classify type of window
ispread = findSpreadByName(name);
imatrix = findMatrixByName(name);
iexcel = findExcelByName(name);
igraph = -1;
if (ispread != -1) {
LOG_PRINT(logfile, "\n Window is a Worksheet book\n")
getWindowProperties(spreadSheets[ispread], wde_header, wde_header_size);
} else if (imatrix != -1) {
LOG_PRINT(logfile, "\n Window is a Matrix book\n")
getWindowProperties(matrixes[imatrix], wde_header, wde_header_size);
} else if (iexcel != -1) {
LOG_PRINT(logfile, "\n Window is an Excel book\n")
getWindowProperties(excels[iexcel], wde_header, wde_header_size);
} else {
LOG_PRINT(logfile, "\n Window is a Graph\n")
graphs.push_back(Graph(name));
igraph = (int)graphs.size()-1;
getWindowProperties(graphs[igraph], wde_header, wde_header_size);
}
// go to end of window header
file.seekg(wdh_start+wde_header_size+1, ios_base::beg);
// get layer list
unsigned int layer_list_size = 0;
LOG_PRINT(logfile, " Reading Layers ...\n")
while (true) {
ilayer = layer_list_size;
if (!readLayerElement()) break;
layer_list_size++;
}
LOG_PRINT(logfile, " ... done. Layers: %d\n", layer_list_size)
curpos = file.tellg();
LOG_PRINT(logfile, "window ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
return true;
}
bool OriginAnyParser::readLayerElement() {
/* get general info and details of a layer
* return true if a Layer is found, otherwise return false */
unsigned int lye_header_size = 0;
std::streamoff lyh_start = 0;
// get layer header size
lye_header_size = readObjectSize();
if (lye_header_size == 0) return false;
curpos = file.tellg();
lyh_start = curpos;
LOG_PRINT(logfile, " Layer found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]\n", lye_header_size, lye_header_size, curpos, curpos)
string lye_header = readObjectAsString(lye_header_size);
// get known info
getLayerProperties(lye_header, lye_header_size);
// go to end of layer header
file.seekg(lyh_start+lye_header_size+1, ios_base::beg);
// get annotation list
unsigned int annotation_list_size = 0;
LOG_PRINT(logfile, " Reading Annotations ...\n")
/* Some annotations can be groups of annotations. We need a recursive function for those cases */
annotation_list_size = readAnnotationList();
if (annotation_list_size > 0) {
LOG_PRINT(logfile, " ... done. Annotations: %d\n", annotation_list_size)
}
// get curve list
unsigned int curve_list_size = 0;
LOG_PRINT(logfile, " Reading Curves ...\n")
while (true) {
if (!readCurveElement()) break;
curve_list_size++;
}
LOG_PRINT(logfile, " ... done. Curves: %d\n", curve_list_size)
// get axisbreak list
unsigned int axisbreak_list_size = 0;
LOG_PRINT(logfile, " Reading Axis breaks ...\n")
while (true) {
if (!readAxisBreakElement()) break;
axisbreak_list_size++;
}
LOG_PRINT(logfile, " ... done. Axis breaks: %d\n", axisbreak_list_size)
// get x axisparameter list
unsigned int axispar_x_list_size = 0;
LOG_PRINT(logfile, " Reading x-Axis parameters ...\n")
while (true) {
if (!readAxisParameterElement(1)) break;
axispar_x_list_size++;
}
LOG_PRINT(logfile, " ... done. x-Axis parameters: %d\n", axispar_x_list_size)
// get y axisparameter list
unsigned int axispar_y_list_size = 0;
LOG_PRINT(logfile, " Reading y-Axis parameters ...\n")
while (true) {
if (!readAxisParameterElement(2)) break;
axispar_y_list_size++;
}
LOG_PRINT(logfile, " ... done. y-Axis parameters: %d\n", axispar_y_list_size)
// get z axisparameter list
unsigned int axispar_z_list_size = 0;
LOG_PRINT(logfile, " Reading z-Axis parameters ...\n")
while (true) {
if (!readAxisParameterElement(3)) break;
axispar_z_list_size++;
}
LOG_PRINT(logfile, " ... done. z-Axis parameters: %d\n", axispar_z_list_size)
curpos = file.tellg();
LOG_PRINT(logfile, " layer ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
return true;
}
unsigned int OriginAnyParser::readAnnotationList() {
/* Purpose of this function is to allow recursive call for groups of annotation elements. */
unsigned int annotation_list_size = 0;
while (true) {
if (!readAnnotationElement()) break;
annotation_list_size++;
}
return annotation_list_size;
}
bool OriginAnyParser::readAnnotationElement() {
/* get general info and details of an Annotation
* return true if an Annotation is found, otherwise return false */
unsigned int ane_header_size = 0;
std::streamoff anh_start = 0;
// get annotation header size
ane_header_size = readObjectSize();
if (ane_header_size == 0) return false;
curpos = file.tellg();
anh_start = curpos;
LOG_PRINT(logfile, " Annotation found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]: ", ane_header_size, ane_header_size, curpos, curpos)
string ane_header = readObjectAsString(ane_header_size);
// get known info
string name(41,0);
name = ane_header.substr(0x46,41);
LOG_PRINT(logfile, "%s\n", name.c_str())
// go to end of annotation header
file.seekg(anh_start+ane_header_size+1, ios_base::beg);
// data of an annotation element is divided in three blocks
// first block
unsigned int ane_data_1_size = 0;
std::streamoff andt1_start = 0;
ane_data_1_size = readObjectSize();
andt1_start = file.tellg();
LOG_PRINT(logfile, " block 1 size %d [0x%X] at %" PRId64 " [0x%" PRIx64 "]\n", ane_data_1_size, ane_data_1_size, andt1_start, andt1_start)
string andt1_data = readObjectAsString(ane_data_1_size);
// TODO: get known info
// go to end of first data block
file.seekg(andt1_start+ane_data_1_size+1, ios_base::beg);
// second block
unsigned int ane_data_2_size = 0;
std::streamoff andt2_start = 0;
ane_data_2_size = readObjectSize();
andt2_start = file.tellg();
LOG_PRINT(logfile, " block 2 size %d [0x%X] at %" PRId64 " [0x%" PRIx64 "]\n", ane_data_2_size, ane_data_2_size, andt2_start, andt2_start)
string andt2_data;
// check for group of annotations
if (((ane_data_1_size == 0x5e) || (ane_data_1_size == 0x0A)) && (ane_data_2_size == 0x04)) {
curpos = file.tellg();
LOG_PRINT(logfile, " Annotation group found at %" PRId64 " [0x%" PRIx64 "] ...\n", curpos, curpos)
unsigned int angroup_size = readAnnotationList();
curpos = file.tellg();
if (angroup_size > 0) {
LOG_PRINT(logfile, " ... group end at %" PRId64 " [0x%" PRIx64 "]. Annotations: %d\n", curpos, curpos, angroup_size)
}
andt2_data = string();
} else {
andt2_data = readObjectAsString(ane_data_2_size);
// TODO: get known info
// go to end of second data block
file.seekg(andt2_start+ane_data_2_size, ios_base::beg);
if (ane_data_2_size > 0) file.seekg(1, ios_base::cur);
}
// third block
unsigned int ane_data_3_size = 0;
ane_data_3_size = readObjectSize();
std::streamoff andt3_start = file.tellg();
if (andt3_start > 0) {
LOG_PRINT(logfile, " block 3 size %d [0x%X] at %" PRId64 " [0x%" PRIx64 "]\n", ane_data_3_size, ane_data_3_size, andt3_start, andt3_start)
}
string andt3_data = readObjectAsString(ane_data_3_size);
curpos = file.tellg();
LOG_PRINT(logfile, " annotation ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
// get annotation info
getAnnotationProperties(ane_header, ane_header_size, andt1_data, ane_data_1_size, andt2_data, ane_data_2_size, andt3_data, ane_data_3_size);
return true;
}
bool OriginAnyParser::readCurveElement() {
/* get general info and details of a Curve
* return true if a Curve is found, otherwise return false */
unsigned int cve_header_size = 0, cve_data_size = 0;
std::streamoff cvh_start = 0, cvd_start = 0;
// get curve header size
cve_header_size = readObjectSize();
if (cve_header_size == 0) return false;
curpos = file.tellg();
cvh_start = curpos;
LOG_PRINT(logfile, " Curve: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "], ", cve_header_size, cve_header_size, curpos, curpos)
string cve_header = readObjectAsString(cve_header_size);
// TODO: get known info from curve header
string name = cve_header.substr(0x12,12);
// go to end of header, get curve data size
file.seekg(cvh_start+cve_header_size+1, ios_base::beg);
cve_data_size = readObjectSize();
cvd_start = file.tellg();
LOG_PRINT(logfile, "data size %d [0x%X], from %" PRId64 " [0x%" PRIx64 "]", cve_data_size, cve_data_size, cvd_start, cvd_start)
string cve_data = readObjectAsString(cve_data_size);
// TODO: get known info from curve data
// go to end of data
file.seekg(cvd_start+cve_data_size, ios_base::beg);
if (cve_data_size > 0) file.seekg(1, ios_base::cur);
curpos = file.tellg();
LOG_PRINT(logfile, "to %" PRId64 " [0x%" PRIx64 "]: %s\n", curpos, curpos, name.c_str())
// get curve (or column) info
getCurveProperties(cve_header, cve_header_size, cve_data, cve_data_size);
return true;
}
bool OriginAnyParser::readAxisBreakElement() {
/* get info of Axis breaks
* return true if an Axis break, otherwise return false */
unsigned int abe_data_size = 0;
std::streamoff abd_start = 0;
// get axis break data size
abe_data_size = readObjectSize();
if (abe_data_size == 0) return false;
curpos = file.tellg();
abd_start = curpos;
string abd_data = readObjectAsString(abe_data_size);
// get known info
// go to end of axis break data
file.seekg(abd_start+abe_data_size+1, ios_base::beg);
// get axis break info
getAxisBreakProperties(abd_data, abe_data_size);
return true;
}
bool OriginAnyParser::readAxisParameterElement(unsigned int naxis) {
/* get info of Axis parameters for naxis-axis (x,y,z) = (1,2,3)
* return true if an Axis break is found, otherwise return false */
unsigned int ape_data_size = 0;
std::streamoff apd_start = 0;
// get axis break data size
ape_data_size = readObjectSize();
if (ape_data_size == 0) return false;
curpos = file.tellg();
apd_start = curpos;
string apd_data = readObjectAsString(ape_data_size);
// get known info
// go to end of axis break data
file.seekg(apd_start+ape_data_size+1, ios_base::beg);
// get axis parameter info
getAxisParameterProperties(apd_data, ape_data_size, naxis);
return true;
}
bool OriginAnyParser::readParameterElement() {
// get parameter name
string par_name;
char c;
getline(file, par_name);
if (par_name[0] == '\0') {
unsigned int eof_parameters_mark = readObjectSize();
if (eof_parameters_mark != 0) {
LOG_PRINT(logfile, "Wrong end of parameters mark\n")
}
return false;
}
LOG_PRINT(logfile, " %s:", par_name.c_str())
// get value
double value;
file >> value;
LOG_PRINT(logfile, " %g\n", value)
// read the '\n'
file >> c;
if (c != '\n') {
curpos = file.tellg();
LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, curpos)
parseError = 6;
return false;
}
return true;
}
bool OriginAnyParser::readNoteElement() {
/* get info of Note windows, including "Results Log"
* return true if a Note window is found, otherwise return false */
unsigned int nwe_header_size = 0, nwe_label_size = 0, nwe_contents_size = 0;
std::streamoff nwh_start = 0, nwl_start = 0, nwc_start = 0;
// get note header size
nwe_header_size = readObjectSize();
if (nwe_header_size == 0) return false;
curpos = file.tellg();
nwh_start = curpos;
LOG_PRINT(logfile, " Note window found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]\n", nwe_header_size, nwe_header_size, curpos, curpos)
string nwe_header = readObjectAsString(nwe_header_size);
// TODO: get known info from header
// go to end of header
file.seekg(nwh_start+nwe_header_size+1, ios_base::beg);
// get label size
nwe_label_size = readObjectSize();
nwl_start = file.tellg();
string nwe_label = readObjectAsString(nwe_label_size);
LOG_PRINT(logfile, " label at %" PRId64 " [0x%" PRIx64 "]: %s\n", nwl_start, nwl_start, nwe_label.c_str())
// go to end of label
file.seekg(nwl_start+nwe_label_size, ios_base::beg);
if (nwe_label_size > 0) file.seekg(1, ios_base::cur);
// get contents size
nwe_contents_size = readObjectSize();
nwc_start = file.tellg();
string nwe_contents = readObjectAsString(nwe_contents_size);
if (nwc_start > 0) {
LOG_PRINT(logfile, " contents at %" PRId64 " [0x%" PRIx64 "]: \n%s\n", nwc_start, nwc_start, nwe_contents.c_str())
}
// get note window info
getNoteProperties(nwe_header, nwe_header_size, nwe_label, nwe_label_size, nwe_contents, nwe_contents_size);
return true;
}
void OriginAnyParser::readProjectTree() {
unsigned int pte_depth = 0;
// first preamble size and data (usually 4)
unsigned int pte_pre1_size = readObjectSize();
string pte_pre1 = readObjectAsString(pte_pre1_size);
// second preamble size and data (usually 16)
unsigned int pte_pre2_size = readObjectSize();
string pte_pre2 = readObjectAsString(pte_pre2_size);
// root element and children
unsigned int rootfolder = readFolderTree(
projectTree.insert(projectTree.begin(), ProjectNode("", ProjectNode::Folder)),
pte_depth
);
if (rootfolder > 0) {
LOG_PRINT(logfile, "Number of files at root: %d\n", rootfolder)
}
// epilogue (should be zero)
unsigned int pte_post_size = readObjectSize();
if (pte_post_size != 0) {
LOG_PRINT(logfile, "Wrong end of project tree mark\n")
}
// log info on project tree
#ifdef GENERATE_CODE_FOR_LOG
outputProjectTree(cout);
#endif // GENERATE_CODE_FOR_LOG
return;
}
unsigned int OriginAnyParser::readFolderTree(tree<ProjectNode>::iterator parent, unsigned int depth) {
unsigned int fle_header_size = 0, fle_eofh_size = 0, fle_name_size = 0, fle_prop_size = 0;
// folder header size, data, end mark
fle_header_size = readObjectSize();
string fle_header = readObjectAsString(fle_header_size);
fle_eofh_size = readObjectSize(); // (usually 0)
if (fle_eofh_size != 0) {
LOG_PRINT(logfile, "Wrong end of folder header mark")
}
// folder name size
fle_name_size = readObjectSize();
curpos = file.tellg();
string fle_name = readObjectAsString(fle_name_size);
LOG_PRINT(logfile, "Folder name at %" PRId64 " [0x%" PRIx64 "]: %s\n", curpos, curpos, fle_name.c_str());
// additional properties
fle_prop_size = readObjectSize();
for (unsigned int i = 0; i < fle_prop_size; i++) {
unsigned int obj_size = readObjectSize();
string obj_data = readObjectAsString(obj_size);
}
// get project folder properties
tree<ProjectNode>::iterator current_folder = projectTree.append_child(parent, ProjectNode(fle_name, ProjectNode::Folder));
getProjectFolderProperties(current_folder, fle_header, fle_header_size);
// file entries
unsigned int number_of_files_size = 0;
number_of_files_size = readObjectSize(); // should be 4 as number_of_files is an integer
curpos = file.tellg();
LOG_PRINT(logfile, "Number of files at %" PRId64 " [0x%" PRIx64 "] ", curpos, curpos)
string fle_nfiles = readObjectAsString(number_of_files_size);
istringstream stmp(ios_base::binary);
stmp.str(fle_nfiles);
unsigned int number_of_files = 0;
GET_INT(stmp, number_of_files)
LOG_PRINT(logfile, "%d\n", number_of_files)
for (unsigned int i=0; i < number_of_files; i++) {
readProjectLeaf(current_folder);
}
// subfolder entries
unsigned int number_of_folders_size = 0;
number_of_folders_size = readObjectSize(); // should be 4 as number_of_subfolders is an integer
curpos = file.tellg();
LOG_PRINT(logfile, "Number of subfolders at %" PRId64 " [0x%" PRIx64 "] ", curpos, curpos)
string fle_nfolders = readObjectAsString(number_of_folders_size);
stmp.str(fle_nfolders);
unsigned int number_of_folders = 0;
GET_INT(stmp, number_of_folders)
LOG_PRINT(logfile, "%d\n", number_of_folders)
for (unsigned int i=0; i < number_of_folders; i++) {
depth++;
unsigned int files_in_subfolder = readFolderTree(current_folder, depth);
if (files_in_subfolder > 0) {
LOG_PRINT(logfile, "Number of files in subfolder: %d\n", files_in_subfolder)
}
depth--;
}
return number_of_files;
}
void OriginAnyParser::readProjectLeaf(tree<ProjectNode>::iterator current_folder) {
// preamble size (usually 0) and data
unsigned int ptl_pre_size = readObjectSize();
string ptl_pre = readObjectAsString(ptl_pre_size);
// file data size (usually 8) and data
unsigned int ptl_data_size = readObjectSize();
curpos = file.tellg();
string ptl_data = readObjectAsString(ptl_data_size);
LOG_PRINT(logfile, "File at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
// epilogue (should be zero)
unsigned int ptl_post_size = readObjectSize();
if (ptl_post_size != 0) {
LOG_PRINT(logfile, "Wrong end of project leaf mark\n")
}
// get project node properties
getProjectLeafProperties(current_folder, ptl_data, ptl_data_size);
return;
}
void OriginAnyParser::readAttachmentList() {
/* Attachments are divided in two groups (which can be empty)
first group is preceded by two integers: 4096 (0x1000) and number_of_attachments followed as usual by a '\n' mark
second group is a series of (header, name, data) triplets without the '\n' mark.
*/
// figure out if first group is not empty. In this case we will read integer=8 at current file position
unsigned int att_1st_empty = 0;
file >> att_1st_empty;
file.seekg(-4, ios_base::cur);
istringstream stmp(ios_base::binary);
string att_header;
if (att_1st_empty == 8) {
// first group
unsigned int att_list1_size = 0;
// get two integers
// next line fails if first attachment group is empty: readObjectSize exits as there is no '\n' after 4 bytes for uint
att_list1_size = readObjectSize(); // should be 8 as we expect two integer values
curpos = file.tellg();
string att_list1 = readObjectAsString(att_list1_size);
LOG_PRINT(logfile, "First attachment group at %" PRId64 " [0x%" PRIx64 "]", curpos, curpos)
stmp.str(att_list1);
unsigned int att_mark = 0, number_of_atts = 0, iattno = 0, att_data_size = 0;
GET_INT(stmp, att_mark) // should be 4096
GET_INT(stmp, number_of_atts)
LOG_PRINT(logfile, " with %d attachments.\n", number_of_atts)
for (unsigned int i=0; i < number_of_atts; i++) {
/* Header is a group of 7 integers followed by \n
1st attachment mark (4096: 0x00 0x10 0x00 0x00)
2nd attachment number ( <num_of_att)
3rd attachment size
4th .. 7th ???
*/
// get header
att_header = readObjectAsString(7*4);
stmp.str(att_header);
GET_INT(stmp, att_mark) // should be 4096
GET_INT(stmp, iattno)
GET_INT(stmp, att_data_size)
curpos = file.tellg();
LOG_PRINT(logfile, "Attachment no %d (%d) at %" PRId64 " [0x%" PRIx64 "], size %d\n", i, iattno, curpos, curpos, att_data_size)
// get data
string att_data = readObjectAsString(att_data_size);
// even if att_data_size is zero, we get a '\n' mark
if (att_data_size == 0) file.seekg(1, ios_base::cur);
}
} else {
LOG_PRINT(logfile, "First attachment group is empty\n")
}
/* Second group is a series of (header, name, data) triplets
There is no number of attachments. It ends when we reach EOF. */
curpos = file.tellg();
LOG_PRINT(logfile, "Second attachment group starts at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
/* Header is a group of 3 integers, with no '\n' at end
1st attachment header+name size including itself
2nd attachment type (0x59 0x04 0xCA 0x7F for excel workbooks)
3rd size of data */
// get header
att_header = string(12,0);
while (true) {
// check for eof
if ((d_file_size == file.tellg()) || (file.eof())) break;
// cannot use readObjectAsString: there is no '\n' at end
file.read(reinterpret_cast<char*>(&att_header[0]), 12);
if (file.gcount() != 12) break;
// get header size, type and data size
unsigned int att_header_size=0, att_type=0, att_size=0;
stmp.str(att_header);
GET_INT(stmp, att_header_size)
GET_INT(stmp, att_type)
GET_INT(stmp, att_size)
// get name and data
unsigned int name_size = att_header_size - 3*4;
string att_name = string(name_size, 0);
file.read(&att_name[0], name_size);
curpos = file.tellg();
string att_data = string(att_size, 0);
file.read(&att_data[0], att_size);
LOG_PRINT(logfile, "attachment at %" PRId64 " [0x%" PRIx64 "], type 0x%X, size %d [0x%X]: %s\n", curpos, curpos, att_type, att_size, att_size, att_name.c_str())
}
return;
}
bool OriginAnyParser::getColumnInfoAndData(const string& col_header, unsigned int col_header_size, const string& col_data, unsigned int col_data_size) {
istringstream stmp(ios_base::binary);
short data_type;
char data_type_u;
unsigned char valuesize;
string name(25,0), column_name;
stmp.str(col_header.substr(0x16));
GET_SHORT(stmp, data_type);
data_type_u = col_header[0x3F];
if (fileVersion == 350) {
valuesize = col_header[0x36];
} else {
valuesize = col_header[0x3D];
}
if(valuesize == 0) {
LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize);
valuesize = 8;
}
if (fileVersion == 350) {
name = col_header.substr(0x57,25).c_str();
} else {
name = col_header.substr(0x58,25).c_str();
}
string dataset_name = name;
string::size_type colpos = name.find_last_of("_");
if(colpos != string::npos){
column_name = name.substr(colpos + 1);
name.resize(colpos);
}
LOG_PRINT(logfile, "\n data_type 0x%.4X, data_type_u 0x%.2X, valuesize %d [0x%X], %s [%s]\n", data_type, data_type_u, valuesize, valuesize, name.c_str(), column_name.c_str());
int total_rows, first_row, last_row;
stmp.str(col_header.substr(0x19));
GET_INT(stmp, total_rows);
GET_INT(stmp, first_row);
GET_INT(stmp, last_row);
LOG_PRINT(logfile, " total %d, first %d, last %d rows\n", total_rows, first_row, last_row)
unsigned short signature;