1 /*
2 * OriginAnyParser.cpp
3 *
4 * Copyright 2017 Miquel Garriga <gbmiquel@gmail.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Parser for all versions. Based mainly on Origin750Parser.cpp
20 */
21
22 #include "OriginAnyParser.h"
23 #include <sstream>
24 #include <cinttypes>
25
26 /* define a macro to get an int (or uint) from a istringstream in binary mode */
27 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
28 #define GET_SHORT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 2);};
29 #define GET_INT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 4);};
30 #define GET_FLOAT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 4);};
31 #define GET_DOUBLE(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 8);};
32 #else
swap_bytes(unsigned char * data,int size)33 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;}}
34 #define GET_SHORT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 2); swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 2);};
35 #define GET_INT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 4); swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 4);};
36 #define GET_FLOAT(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 4); swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 4);};
37 #define GET_DOUBLE(iss, ovalue) {iss.read(reinterpret_cast<char *>(&ovalue), 8); swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 8);};
38 #endif
39
OriginAnyParser(const string & fileName)40 OriginAnyParser::OriginAnyParser(const string& fileName)
41 : file(fileName.c_str(),ios::binary),
42 logfile(nullptr),
43 d_file_size(0),
44 curpos(0),
45 objectIndex(0),
46 parseError(0),
47 ispread(-1),
48 imatrix(-1),
49 iexcel(-1),
50 igraph(-1),
51 ilayer(-1) {
52 }
53
parse()54 bool OriginAnyParser::parse() {
55 #ifdef GENERATE_CODE_FOR_LOG
56 // append progress in log file
57 logfile = fopen("opjfile.log","a");
58 #endif // GENERATE_CODE_FOR_LOG
59
60 // get length of file:
61 file.seekg (0, ios_base::end);
62 d_file_size = file.tellg();
63 file.seekg(0, ios_base::beg);
64
65 LOG_PRINT(logfile, "File size: %" PRId64 "\n", d_file_size)
66
67 // get file and program version, check it is a valid file
68 readFileVersion();
69 if (parseError > 1) return false;
70 curpos = file.tellg();
71 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
72
73 // get global header
74 readGlobalHeader();
75 if (parseError > 1) return false;
76 curpos = file.tellg();
77 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
78
79 // get dataset list
80 unsigned int dataset_list_size = 0;
81 objectIndex = 0; // use it to count DataSets
82
83 LOG_PRINT(logfile, "Reading Data sets ...\n")
84 while (true) {
85 if (!readDataSetElement()) break;
86 dataset_list_size++;
87 }
88 if (parseError > 1) return false;
89 LOG_PRINT(logfile, " ... done. Data sets: %d\n", dataset_list_size)
90 curpos = file.tellg();
91 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
92
93 for(unsigned int i = 0; i < spreadSheets.size(); ++i){
94 if(spreadSheets[i].sheets > 1){
95 LOG_PRINT(logfile, " CONVERT SPREADSHEET \"%s\" to EXCEL\n", spreadSheets[i].name.c_str());
96 convertSpreadToExcel(i);
97 --i;
98 }
99 }
100
101 // get window list
102 unsigned int window_list_size = 0;
103 objectIndex = 0; // reset it to count Windows (except Notes)
104
105 LOG_PRINT(logfile, "Reading Windows ...\n")
106 while (true) {
107 if (!readWindowElement()) break;
108 window_list_size++;
109 }
110 LOG_PRINT(logfile, " ... done. Windows: %d\n", window_list_size)
111 curpos = file.tellg();
112 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
113
114 // get parameter list
115 unsigned int parameter_list_size = 0;
116
117 LOG_PRINT(logfile, "Reading Parameters ...\n")
118 while (true) {
119 if (!readParameterElement()) break;
120 parameter_list_size++;
121 }
122 LOG_PRINT(logfile, " ... done. Parameters: %d\n", parameter_list_size)
123 curpos = file.tellg();
124 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
125
126 // Note windows were added between version >4.141 and 4.210,
127 // i.e., with Release 5.0
128 if (curpos < d_file_size) {
129 // get note windows list
130 unsigned int note_list_size = 0;
131
132 LOG_PRINT(logfile, "Reading Note windows ...\n")
133 objectIndex = 0; // reset it to count Notes
134 while (true) {
135 if (!readNoteElement()) break;
136 note_list_size++;
137 }
138 LOG_PRINT(logfile, " ... done. Note windows: %d\n", note_list_size)
139 curpos = file.tellg();
140 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
141 }
142
143 // Project Tree was added between version >4.210 and 4.2616,
144 // i.e., with Release 6.0
145 if (curpos < d_file_size) {
146 // get project tree
147 readProjectTree();
148 curpos = file.tellg();
149 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
150 }
151
152 // Attachments were added between version >4.2673_558 and 4.2764_623,
153 // i.e., with Release 7.0
154 if (curpos < d_file_size) {
155 readAttachmentList();
156 curpos = file.tellg();
157 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
158 }
159
160 if (curpos >= d_file_size) LOG_PRINT(logfile, "Now at end of file\n")
161
162 #ifdef GENERATE_CODE_FOR_LOG
163 fclose(logfile);
164 #endif // GENERATE_CODE_FOR_LOG
165
166 return true;
167 }
168
toLowerCase(string str)169 string toLowerCase(string str){
170 for (unsigned int i = 0; i < str.length(); i++)
171 if (str[i] >= 0x41 && str[i] <= 0x5A)
172 str[i] = str[i] + 0x20;
173 return str;
174 }
175
createOriginAnyParser(const string & fileName)176 OriginParser* createOriginAnyParser(const string& fileName)
177 {
178 return new OriginAnyParser(fileName);
179 }
180
readObjectSize()181 unsigned int OriginAnyParser::readObjectSize() {
182 unsigned int obj_size = 0;
183
184 char c = 0;
185 file >> obj_size;
186 file >> c;
187 if (c != '\n') {
188 curpos = file.tellg();
189 LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, curpos)
190 parseError = 3;
191 return 0;
192 }
193 return obj_size;
194 }
195
readObjectAsString(unsigned int size)196 string OriginAnyParser::readObjectAsString(unsigned int size) {
197 char c;
198 // read a size-byte blob of data followed by '\n'
199 if (size > 0) {
200 // get a string large enough to hold the result, initialize it to all 0's
201 string blob = string(size, '\0');
202 // read data into that string
203 // cannot use '>>' operator because iendianfstream truncates it at first '\0'
204 file.read(&blob[0], size);
205 // read the '\n'
206 file >> c;
207 if (c != '\n') {
208 curpos = file.tellg();
209 LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, curpos)
210 parseError = 4;
211 return string();
212 }
213 return blob;
214 }
215 return string();
216 }
217
readFileVersion()218 void OriginAnyParser::readFileVersion() {
219 // get file and program version, check it is a valid file
220 string sFileVersion;
221 getline(file, sFileVersion);
222
223 if ((sFileVersion.substr(0,4) != "CPYA")) {
224 LOG_PRINT(logfile, "File, is not a valid OPJ file\n")
225 if ((sFileVersion.substr(0,5) != "CPYUA")) {
226 LOG_PRINT(logfile, "File, is not a valid OPJU file\n")
227 parseError = 2;
228 return;
229 }
230 }
231
232 if (*sFileVersion.rbegin() != '#') parseError = 1;
233 LOG_PRINT(logfile, "File version string: %s\n", sFileVersion.c_str())
234 }
235
readGlobalHeader()236 void OriginAnyParser::readGlobalHeader() {
237 // get global header size
238 unsigned int gh_size = 0, gh_endmark = 0;
239 gh_size = readObjectSize();
240 curpos = file.tellg();
241 LOG_PRINT(logfile, "Global header size: %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "],", gh_size, gh_size, curpos, curpos)
242
243 // get global header data
244 string gh_data;
245 gh_data = readObjectAsString(gh_size);
246
247 curpos = file.tellg();
248 LOG_PRINT(logfile, " ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
249
250 // when gh_size > 0x1B, a double with fileVersion/100 can be read at gh_data[0x1B:0x23]
251 if (gh_size > 0x1B) {
252 istringstream stmp;
253 stmp.str(gh_data.substr(0x1B));
254 double dFileVersion;
255 GET_DOUBLE(stmp, dFileVersion)
256 if (dFileVersion > 8.5) {
257 fileVersion = (unsigned int)trunc(dFileVersion*100.);
258 } else {
259 fileVersion = 10*(unsigned int)trunc(dFileVersion*10.);
260 }
261 LOG_PRINT(logfile, "Project version as read from header: %.2f (%.6f)\n", fileVersion/100.0, dFileVersion)
262 }
263
264 // now read a zero size end mark
265 gh_endmark = readObjectSize();
266 if (gh_endmark != 0) {
267 curpos = file.tellg();
268 LOG_PRINT(logfile, "Wrong end of list mark %d at %" PRId64 " [0x%" PRIx64 "]\n", gh_endmark, curpos, curpos)
269 parseError = 5;
270 return;
271 }
272 }
273
readDataSetElement()274 bool OriginAnyParser::readDataSetElement() {
275 /* get info and values of a DataSet (worksheet column, matrix sheet, ...)
276 * return true if a DataSet is found, otherwise return false */
277 unsigned int dse_header_size = 0, dse_data_size = 0, dse_mask_size = 0;
278 std::streamoff dsh_start = 0, dsd_start = 0, dsm_start = 0;
279 string dse_header;
280
281 // get dataset header size
282 dse_header_size = readObjectSize();
283 if (dse_header_size == 0) return false;
284
285 curpos = file.tellg();
286 dsh_start = curpos;
287 LOG_PRINT(logfile, "Column: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "], ", dse_header_size, dse_header_size, curpos, curpos)
288 dse_header = readObjectAsString(dse_header_size);
289
290 // get known info
291 string name(25,0);
292 name = dse_header.substr(0x58,25);
293
294 // go to end of dataset header, get data size
295 file.seekg(dsh_start+dse_header_size+1, ios_base::beg);
296 dse_data_size = readObjectSize();
297 dsd_start = file.tellg();
298 string dse_data = readObjectAsString(dse_data_size);
299 curpos = file.tellg();
300 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)
301
302 // get data values
303 getColumnInfoAndData(dse_header, dse_header_size, dse_data, dse_data_size);
304
305 // go to end of data values, get mask size (often zero)
306 file.seekg(dsd_start+dse_data_size, ios_base::beg); // dse_data_size can be zero
307 if (dse_data_size > 0) file.seekg(1, ios_base::cur);
308 dse_mask_size = readObjectSize();
309 dsm_start = file.tellg();
310 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)
311 string dse_mask = readObjectAsString(dse_mask_size);
312
313 // get mask values
314 if (dse_mask_size > 0) {
315 curpos = file.tellg();
316 LOG_PRINT(logfile, ", ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
317 // TODO: extract mask values from dse_mask
318 // go to end of dataset mask
319 file.seekg(dsm_start+dse_mask_size+1, ios_base::beg);
320 }
321 curpos = file.tellg();
322 LOG_PRINT(logfile, " ends at %" PRId64 " [0x%" PRIx64 "]: ", curpos, curpos)
323 LOG_PRINT(logfile, "%s\n", name.c_str())
324
325 return true;
326 }
327
readWindowElement()328 bool OriginAnyParser::readWindowElement() {
329 /* get general info and details of a window
330 * return true if a Window is found, otherwise return false */
331 unsigned int wde_header_size = 0;
332 std::streamoff wdh_start = 0;
333
334 // get window header size
335 wde_header_size = readObjectSize();
336 if (wde_header_size == 0) return false;
337
338 curpos = file.tellg();
339 wdh_start = curpos;
340 LOG_PRINT(logfile, "Window found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]: ", wde_header_size, wde_header_size, curpos, curpos)
341 string wde_header = readObjectAsString(wde_header_size);
342
343 // get known info
344 string name(25,0);
345 name = wde_header.substr(0x02,25).c_str();
346 LOG_PRINT(logfile, "%s\n", name.c_str())
347
348 // classify type of window
349 ispread = findSpreadByName(name);
350 imatrix = findMatrixByName(name);
351 iexcel = findExcelByName(name);
352 igraph = -1;
353
354 if (ispread != -1) {
355 LOG_PRINT(logfile, "\n Window is a Worksheet book\n")
356 getWindowProperties(spreadSheets[ispread], wde_header, wde_header_size);
357 } else if (imatrix != -1) {
358 LOG_PRINT(logfile, "\n Window is a Matrix book\n")
359 getWindowProperties(matrixes[imatrix], wde_header, wde_header_size);
360 } else if (iexcel != -1) {
361 LOG_PRINT(logfile, "\n Window is an Excel book\n")
362 getWindowProperties(excels[iexcel], wde_header, wde_header_size);
363 } else {
364 LOG_PRINT(logfile, "\n Window is a Graph\n")
365 graphs.push_back(Graph(name));
366 igraph = (int)graphs.size()-1;
367 getWindowProperties(graphs[igraph], wde_header, wde_header_size);
368 }
369
370 // go to end of window header
371 file.seekg(wdh_start+wde_header_size+1, ios_base::beg);
372
373 // get layer list
374 unsigned int layer_list_size = 0;
375
376 LOG_PRINT(logfile, " Reading Layers ...\n")
377 while (true) {
378 ilayer = layer_list_size;
379 if (!readLayerElement()) break;
380 layer_list_size++;
381 }
382 LOG_PRINT(logfile, " ... done. Layers: %d\n", layer_list_size)
383 curpos = file.tellg();
384 LOG_PRINT(logfile, "window ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
385
386 return true;
387 }
388
readLayerElement()389 bool OriginAnyParser::readLayerElement() {
390 /* get general info and details of a layer
391 * return true if a Layer is found, otherwise return false */
392 unsigned int lye_header_size = 0;
393 std::streamoff lyh_start = 0;
394
395 // get layer header size
396 lye_header_size = readObjectSize();
397 if (lye_header_size == 0) return false;
398
399 curpos = file.tellg();
400 lyh_start = curpos;
401 LOG_PRINT(logfile, " Layer found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]\n", lye_header_size, lye_header_size, curpos, curpos)
402 string lye_header = readObjectAsString(lye_header_size);
403
404 // get known info
405 getLayerProperties(lye_header, lye_header_size);
406
407 // go to end of layer header
408 file.seekg(lyh_start+lye_header_size+1, ios_base::beg);
409
410 // get annotation list
411 unsigned int annotation_list_size = 0;
412
413 LOG_PRINT(logfile, " Reading Annotations ...\n")
414 /* Some annotations can be groups of annotations. We need a recursive function for those cases */
415 annotation_list_size = readAnnotationList();
416 if (annotation_list_size > 0) {
417 LOG_PRINT(logfile, " ... done. Annotations: %d\n", annotation_list_size)
418 }
419
420 // get curve list
421 unsigned int curve_list_size = 0;
422
423 LOG_PRINT(logfile, " Reading Curves ...\n")
424 while (true) {
425 if (!readCurveElement()) break;
426 curve_list_size++;
427 }
428 LOG_PRINT(logfile, " ... done. Curves: %d\n", curve_list_size)
429
430 // get axisbreak list
431 unsigned int axisbreak_list_size = 0;
432
433 LOG_PRINT(logfile, " Reading Axis breaks ...\n")
434 while (true) {
435 if (!readAxisBreakElement()) break;
436 axisbreak_list_size++;
437 }
438 LOG_PRINT(logfile, " ... done. Axis breaks: %d\n", axisbreak_list_size)
439
440 // get x axisparameter list
441 unsigned int axispar_x_list_size = 0;
442
443 LOG_PRINT(logfile, " Reading x-Axis parameters ...\n")
444 while (true) {
445 if (!readAxisParameterElement(1)) break;
446 axispar_x_list_size++;
447 }
448 LOG_PRINT(logfile, " ... done. x-Axis parameters: %d\n", axispar_x_list_size)
449
450 // get y axisparameter list
451 unsigned int axispar_y_list_size = 0;
452
453 LOG_PRINT(logfile, " Reading y-Axis parameters ...\n")
454 while (true) {
455 if (!readAxisParameterElement(2)) break;
456 axispar_y_list_size++;
457 }
458 LOG_PRINT(logfile, " ... done. y-Axis parameters: %d\n", axispar_y_list_size)
459
460 // get z axisparameter list
461 unsigned int axispar_z_list_size = 0;
462
463 LOG_PRINT(logfile, " Reading z-Axis parameters ...\n")
464 while (true) {
465 if (!readAxisParameterElement(3)) break;
466 axispar_z_list_size++;
467 }
468 LOG_PRINT(logfile, " ... done. z-Axis parameters: %d\n", axispar_z_list_size)
469
470 curpos = file.tellg();
471 LOG_PRINT(logfile, " layer ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
472
473 return true;
474 }
475
readAnnotationList()476 unsigned int OriginAnyParser::readAnnotationList() {
477 /* Purpose of this function is to allow recursive call for groups of annotation elements. */
478 unsigned int annotation_list_size = 0;
479
480 while (true) {
481 if (!readAnnotationElement()) break;
482 annotation_list_size++;
483 }
484 return annotation_list_size;
485 }
486
readAnnotationElement()487 bool OriginAnyParser::readAnnotationElement() {
488 /* get general info and details of an Annotation
489 * return true if an Annotation is found, otherwise return false */
490 unsigned int ane_header_size = 0;
491 std::streamoff anh_start = 0;
492
493 // get annotation header size
494 ane_header_size = readObjectSize();
495 if (ane_header_size == 0) return false;
496
497 curpos = file.tellg();
498 anh_start = curpos;
499 LOG_PRINT(logfile, " Annotation found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]: ", ane_header_size, ane_header_size, curpos, curpos)
500 string ane_header = readObjectAsString(ane_header_size);
501
502 // get known info
503 string name(41,0);
504 name = ane_header.substr(0x46,41);
505 LOG_PRINT(logfile, "%s\n", name.c_str())
506
507 // go to end of annotation header
508 file.seekg(anh_start+ane_header_size+1, ios_base::beg);
509
510 // data of an annotation element is divided in three blocks
511 // first block
512 unsigned int ane_data_1_size = 0;
513 std::streamoff andt1_start = 0;
514 ane_data_1_size = readObjectSize();
515
516 andt1_start = file.tellg();
517 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)
518 string andt1_data = readObjectAsString(ane_data_1_size);
519
520 // TODO: get known info
521
522 // go to end of first data block
523 file.seekg(andt1_start+ane_data_1_size+1, ios_base::beg);
524
525 // second block
526 unsigned int ane_data_2_size = 0;
527 std::streamoff andt2_start = 0;
528 ane_data_2_size = readObjectSize();
529 andt2_start = file.tellg();
530 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)
531 string andt2_data;
532
533 // check for group of annotations
534 if (((ane_data_1_size == 0x5e) || (ane_data_1_size == 0x0A)) && (ane_data_2_size == 0x04)) {
535 curpos = file.tellg();
536 LOG_PRINT(logfile, " Annotation group found at %" PRId64 " [0x%" PRIx64 "] ...\n", curpos, curpos)
537 unsigned int angroup_size = readAnnotationList();
538 curpos = file.tellg();
539 if (angroup_size > 0) {
540 LOG_PRINT(logfile, " ... group end at %" PRId64 " [0x%" PRIx64 "]. Annotations: %d\n", curpos, curpos, angroup_size)
541 }
542 andt2_data = string();
543 } else {
544 andt2_data = readObjectAsString(ane_data_2_size);
545 // TODO: get known info
546 // go to end of second data block
547 file.seekg(andt2_start+ane_data_2_size, ios_base::beg);
548 if (ane_data_2_size > 0) file.seekg(1, ios_base::cur);
549 }
550
551 // third block
552 unsigned int ane_data_3_size = 0;
553 ane_data_3_size = readObjectSize();
554
555 std::streamoff andt3_start = file.tellg();
556 if (andt3_start > 0) {
557 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)
558 }
559 string andt3_data = readObjectAsString(ane_data_3_size);
560
561 curpos = file.tellg();
562 LOG_PRINT(logfile, " annotation ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
563
564 // get annotation info
565 getAnnotationProperties(ane_header, ane_header_size, andt1_data, ane_data_1_size, andt2_data, ane_data_2_size, andt3_data, ane_data_3_size);
566
567 return true;
568 }
569
readCurveElement()570 bool OriginAnyParser::readCurveElement() {
571 /* get general info and details of a Curve
572 * return true if a Curve is found, otherwise return false */
573 unsigned int cve_header_size = 0, cve_data_size = 0;
574 std::streamoff cvh_start = 0, cvd_start = 0;
575
576 // get curve header size
577 cve_header_size = readObjectSize();
578 if (cve_header_size == 0) return false;
579
580 curpos = file.tellg();
581 cvh_start = curpos;
582 LOG_PRINT(logfile, " Curve: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "], ", cve_header_size, cve_header_size, curpos, curpos)
583 string cve_header = readObjectAsString(cve_header_size);
584
585 // TODO: get known info from curve header
586 string name = cve_header.substr(0x12,12);
587
588 // go to end of header, get curve data size
589 file.seekg(cvh_start+cve_header_size+1, ios_base::beg);
590 cve_data_size = readObjectSize();
591 cvd_start = file.tellg();
592 LOG_PRINT(logfile, "data size %d [0x%X], from %" PRId64 " [0x%" PRIx64 "]", cve_data_size, cve_data_size, cvd_start, cvd_start)
593 string cve_data = readObjectAsString(cve_data_size);
594
595 // TODO: get known info from curve data
596
597 // go to end of data
598 file.seekg(cvd_start+cve_data_size, ios_base::beg);
599 if (cve_data_size > 0) file.seekg(1, ios_base::cur);
600
601 curpos = file.tellg();
602 LOG_PRINT(logfile, "to %" PRId64 " [0x%" PRIx64 "]: %s\n", curpos, curpos, name.c_str())
603
604 // get curve (or column) info
605 getCurveProperties(cve_header, cve_header_size, cve_data, cve_data_size);
606
607 return true;
608 }
609
readAxisBreakElement()610 bool OriginAnyParser::readAxisBreakElement() {
611 /* get info of Axis breaks
612 * return true if an Axis break, otherwise return false */
613 unsigned int abe_data_size = 0;
614 std::streamoff abd_start = 0;
615
616 // get axis break data size
617 abe_data_size = readObjectSize();
618 if (abe_data_size == 0) return false;
619
620 curpos = file.tellg();
621 abd_start = curpos;
622 string abd_data = readObjectAsString(abe_data_size);
623
624 // get known info
625
626 // go to end of axis break data
627 file.seekg(abd_start+abe_data_size+1, ios_base::beg);
628
629 // get axis break info
630 getAxisBreakProperties(abd_data, abe_data_size);
631
632 return true;
633 }
634
readAxisParameterElement(unsigned int naxis)635 bool OriginAnyParser::readAxisParameterElement(unsigned int naxis) {
636 /* get info of Axis parameters for naxis-axis (x,y,z) = (1,2,3)
637 * return true if an Axis break is found, otherwise return false */
638 unsigned int ape_data_size = 0;
639 std::streamoff apd_start = 0;
640
641 // get axis break data size
642 ape_data_size = readObjectSize();
643 if (ape_data_size == 0) return false;
644
645 curpos = file.tellg();
646 apd_start = curpos;
647 string apd_data = readObjectAsString(ape_data_size);
648
649 // get known info
650
651 // go to end of axis break data
652 file.seekg(apd_start+ape_data_size+1, ios_base::beg);
653
654 // get axis parameter info
655 getAxisParameterProperties(apd_data, ape_data_size, naxis);
656
657 return true;
658 }
659
readParameterElement()660 bool OriginAnyParser::readParameterElement() {
661 // get parameter name
662 string par_name;
663 char c;
664
665 getline(file, par_name);
666 if (par_name[0] == '\0') {
667 unsigned int eof_parameters_mark = readObjectSize();
668 if (eof_parameters_mark != 0) {
669 LOG_PRINT(logfile, "Wrong end of parameters mark\n")
670 }
671 return false;
672 }
673 LOG_PRINT(logfile, " %s:", par_name.c_str())
674 // get value
675 double value;
676 file >> value;
677 LOG_PRINT(logfile, " %g\n", value)
678 // read the '\n'
679 file >> c;
680 if (c != '\n') {
681 curpos = file.tellg();
682 LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, curpos)
683 parseError = 6;
684 return false;
685 }
686
687 return true;
688 }
689
readNoteElement()690 bool OriginAnyParser::readNoteElement() {
691 /* get info of Note windows, including "Results Log"
692 * return true if a Note window is found, otherwise return false */
693 unsigned int nwe_header_size = 0, nwe_label_size = 0, nwe_contents_size = 0;
694 std::streamoff nwh_start = 0, nwl_start = 0, nwc_start = 0;
695
696 // get note header size
697 nwe_header_size = readObjectSize();
698 if (nwe_header_size == 0) return false;
699
700 curpos = file.tellg();
701 nwh_start = curpos;
702 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)
703 string nwe_header = readObjectAsString(nwe_header_size);
704
705 // TODO: get known info from header
706
707 // go to end of header
708 file.seekg(nwh_start+nwe_header_size+1, ios_base::beg);
709
710 // get label size
711 nwe_label_size = readObjectSize();
712 nwl_start = file.tellg();
713 string nwe_label = readObjectAsString(nwe_label_size);
714 LOG_PRINT(logfile, " label at %" PRId64 " [0x%" PRIx64 "]: %s\n", nwl_start, nwl_start, nwe_label.c_str())
715
716 // go to end of label
717 file.seekg(nwl_start+nwe_label_size, ios_base::beg);
718 if (nwe_label_size > 0) file.seekg(1, ios_base::cur);
719
720 // get contents size
721 nwe_contents_size = readObjectSize();
722 nwc_start = file.tellg();
723 string nwe_contents = readObjectAsString(nwe_contents_size);
724 if (nwc_start > 0) {
725 LOG_PRINT(logfile, " contents at %" PRId64 " [0x%" PRIx64 "]: \n%s\n", nwc_start, nwc_start, nwe_contents.c_str())
726 }
727
728 // get note window info
729 getNoteProperties(nwe_header, nwe_header_size, nwe_label, nwe_label_size, nwe_contents, nwe_contents_size);
730
731 return true;
732 }
733
readProjectTree()734 void OriginAnyParser::readProjectTree() {
735 unsigned int pte_depth = 0;
736
737 // first preamble size and data (usually 4)
738 unsigned int pte_pre1_size = readObjectSize();
739 string pte_pre1 = readObjectAsString(pte_pre1_size);
740
741 // second preamble size and data (usually 16)
742 unsigned int pte_pre2_size = readObjectSize();
743 string pte_pre2 = readObjectAsString(pte_pre2_size);
744
745 // root element and children
746 unsigned int rootfolder = readFolderTree(
747 projectTree.insert(projectTree.begin(), ProjectNode("", ProjectNode::Folder)),
748 pte_depth
749 );
750 if (rootfolder > 0) {
751 LOG_PRINT(logfile, "Number of files at root: %d\n", rootfolder)
752 }
753
754 // epilogue (should be zero)
755 unsigned int pte_post_size = readObjectSize();
756 if (pte_post_size != 0) {
757 LOG_PRINT(logfile, "Wrong end of project tree mark\n")
758 }
759
760 // log info on project tree
761 #ifdef GENERATE_CODE_FOR_LOG
762 outputProjectTree(cout);
763 #endif // GENERATE_CODE_FOR_LOG
764
765 return;
766 }
767
readFolderTree(tree<ProjectNode>::iterator parent,unsigned int depth)768 unsigned int OriginAnyParser::readFolderTree(tree<ProjectNode>::iterator parent, unsigned int depth) {
769 unsigned int fle_header_size = 0, fle_eofh_size = 0, fle_name_size = 0, fle_prop_size = 0;
770
771 // folder header size, data, end mark
772 fle_header_size = readObjectSize();
773 string fle_header = readObjectAsString(fle_header_size);
774 fle_eofh_size = readObjectSize(); // (usually 0)
775 if (fle_eofh_size != 0) {
776 LOG_PRINT(logfile, "Wrong end of folder header mark")
777 }
778
779 // folder name size
780 fle_name_size = readObjectSize();
781 curpos = file.tellg();
782 string fle_name = readObjectAsString(fle_name_size);
783 LOG_PRINT(logfile, "Folder name at %" PRId64 " [0x%" PRIx64 "]: %s\n", curpos, curpos, fle_name.c_str());
784
785 // additional properties
786 fle_prop_size = readObjectSize();
787 for (unsigned int i = 0; i < fle_prop_size; i++) {
788 unsigned int obj_size = readObjectSize();
789 string obj_data = readObjectAsString(obj_size);
790 }
791
792 // get project folder properties
793 tree<ProjectNode>::iterator current_folder = projectTree.append_child(parent, ProjectNode(fle_name, ProjectNode::Folder));
794 getProjectFolderProperties(current_folder, fle_header, fle_header_size);
795
796 // file entries
797 unsigned int number_of_files_size = 0;
798
799 number_of_files_size = readObjectSize(); // should be 4 as number_of_files is an integer
800 curpos = file.tellg();
801 LOG_PRINT(logfile, "Number of files at %" PRId64 " [0x%" PRIx64 "] ", curpos, curpos)
802 string fle_nfiles = readObjectAsString(number_of_files_size);
803
804 istringstream stmp(ios_base::binary);
805 stmp.str(fle_nfiles);
806 unsigned int number_of_files = 0;
807 GET_INT(stmp, number_of_files)
808 LOG_PRINT(logfile, "%d\n", number_of_files)
809
810 for (unsigned int i=0; i < number_of_files; i++) {
811 readProjectLeaf(current_folder);
812 }
813
814 // subfolder entries
815 unsigned int number_of_folders_size = 0;
816
817 number_of_folders_size = readObjectSize(); // should be 4 as number_of_subfolders is an integer
818 curpos = file.tellg();
819 LOG_PRINT(logfile, "Number of subfolders at %" PRId64 " [0x%" PRIx64 "] ", curpos, curpos)
820 string fle_nfolders = readObjectAsString(number_of_folders_size);
821
822 stmp.str(fle_nfolders);
823 unsigned int number_of_folders = 0;
824 GET_INT(stmp, number_of_folders)
825 LOG_PRINT(logfile, "%d\n", number_of_folders)
826
827 for (unsigned int i=0; i < number_of_folders; i++) {
828 depth++;
829 unsigned int files_in_subfolder = readFolderTree(current_folder, depth);
830 if (files_in_subfolder > 0) {
831 LOG_PRINT(logfile, "Number of files in subfolder: %d\n", files_in_subfolder)
832 }
833 depth--;
834 }
835
836 return number_of_files;
837 }
838
readProjectLeaf(tree<ProjectNode>::iterator current_folder)839 void OriginAnyParser::readProjectLeaf(tree<ProjectNode>::iterator current_folder) {
840 // preamble size (usually 0) and data
841 unsigned int ptl_pre_size = readObjectSize();
842 string ptl_pre = readObjectAsString(ptl_pre_size);
843
844 // file data size (usually 8) and data
845 unsigned int ptl_data_size = readObjectSize();
846 curpos = file.tellg();
847 string ptl_data = readObjectAsString(ptl_data_size);
848 LOG_PRINT(logfile, "File at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos)
849
850 // epilogue (should be zero)
851 unsigned int ptl_post_size = readObjectSize();
852 if (ptl_post_size != 0) {
853 LOG_PRINT(logfile, "Wrong end of project leaf mark\n")
854 }
855
856 // get project node properties
857 getProjectLeafProperties(current_folder, ptl_data, ptl_data_size);
858
859 return;
860 }
861
readAttachmentList()862 void OriginAnyParser::readAttachmentList() {
863 /* Attachments are divided in two groups (which can be empty)
864 first group is preceded by two integers: 4096 (0x1000) and number_of_attachments followed as usual by a '\n' mark
865 second group is a series of (header, name, data) triplets without the '\n' mark.
866 */
867
868 // figure out if first group is not empty. In this case we will read integer=8 at current file position
869 unsigned int att_1st_empty = 0;
870 file >> att_1st_empty;
871 file.seekg(-4, ios_base::cur);
872
873 istringstream stmp(ios_base::binary);
874 string att_header;
875 if (att_1st_empty == 8) {
876 // first group
877 unsigned int att_list1_size = 0;
878
879 // get two integers
880 // next line fails if first attachment group is empty: readObjectSize exits as there is no '\n' after 4 bytes for uint
881 att_list1_size = readObjectSize(); // should be 8 as we expect two integer values
882 curpos = file.tellg();
883 string att_list1 = readObjectAsString(att_list1_size);
884 LOG_PRINT(logfile, "First attachment group at %" PRId64 " [0x%" PRIx64 "]", curpos, curpos)
885
886 stmp.str(att_list1);
887
888 unsigned int att_mark = 0, number_of_atts = 0, iattno = 0, att_data_size = 0;
889 GET_INT(stmp, att_mark) // should be 4096
890 GET_INT(stmp, number_of_atts)
891 LOG_PRINT(logfile, " with %d attachments.\n", number_of_atts)
892
893 for (unsigned int i=0; i < number_of_atts; i++) {
894 /* Header is a group of 7 integers followed by \n
895 1st attachment mark (4096: 0x00 0x10 0x00 0x00)
896 2nd attachment number ( <num_of_att)
897 3rd attachment size
898 4th .. 7th ???
899 */
900 // get header
901 att_header = readObjectAsString(7*4);
902 stmp.str(att_header);
903 GET_INT(stmp, att_mark) // should be 4096
904 GET_INT(stmp, iattno)
905 GET_INT(stmp, att_data_size)
906 curpos = file.tellg();
907 LOG_PRINT(logfile, "Attachment no %d (%d) at %" PRId64 " [0x%" PRIx64 "], size %d\n", i, iattno, curpos, curpos, att_data_size)
908
909 // get data
910 string att_data = readObjectAsString(att_data_size);
911 // even if att_data_size is zero, we get a '\n' mark
912 if (att_data_size == 0) file.seekg(1, ios_base::cur);
913 }
914 } else {
915 LOG_PRINT(logfile, "First attachment group is empty\n")
916 }
917
918 /* Second group is a series of (header, name, data) triplets
919 There is no number of attachments. It ends when we reach EOF. */
920 curpos = file.tellg();
921 LOG_PRINT(logfile, "Second attachment group starts at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, curpos, d_file_size)
922 /* Header is a group of 3 integers, with no '\n' at end
923 1st attachment header+name size including itself
924 2nd attachment type (0x59 0x04 0xCA 0x7F for excel workbooks)
925 3rd size of data */
926
927 // get header
928 att_header = string(12,0);
929 while (true) {
930 // check for eof
931 if ((d_file_size == file.tellg()) || (file.eof())) break;
932 // cannot use readObjectAsString: there is no '\n' at end
933 file.read(reinterpret_cast<char*>(&att_header[0]), 12);
934
935 if (file.gcount() != 12) break;
936 // get header size, type and data size
937 unsigned int att_header_size=0, att_type=0, att_size=0;
938 stmp.str(att_header);
939 GET_INT(stmp, att_header_size)
940 GET_INT(stmp, att_type)
941 GET_INT(stmp, att_size)
942
943 // get name and data
944 unsigned int name_size = att_header_size - 3*4;
945 string att_name = string(name_size, 0);
946 file.read(&att_name[0], name_size);
947 curpos = file.tellg();
948 string att_data = string(att_size, 0);
949 file.read(&att_data[0], att_size);
950 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())
951 }
952
953 return;
954 }
955
getColumnInfoAndData(const string & col_header,unsigned int col_header_size,const string & col_data,unsigned int col_data_size)956 bool OriginAnyParser::getColumnInfoAndData(const string& col_header, unsigned int col_header_size, const string& col_data, unsigned int col_data_size) {
957 istringstream stmp(ios_base::binary);
958 short data_type;
959 char data_type_u;
960 unsigned char valuesize;
961 string name(25,0), column_name;
962
963 stmp.str(col_header.substr(0x16));
964 GET_SHORT(stmp, data_type);
965
966 data_type_u = col_header[0x3F];
967 if (fileVersion == 350) {
968 valuesize = col_header[0x36];
969 } else {
970 valuesize = col_header[0x3D];
971 }
972 if(valuesize == 0) {
973 LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize);
974 valuesize = 8;
975 }
976
977 if (fileVersion == 350) {
978 name = col_header.substr(0x57,25).c_str();
979 } else {
980 name = col_header.substr(0x58,25).c_str();
981 }
982 string dataset_name = name;
983 string::size_type colpos = name.find_last_of("_");
984
985 if(colpos != string::npos){
986 column_name = name.substr(colpos + 1);
987 name.resize(colpos);
988 }
989
990 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());
991
992 int total_rows, first_row, last_row;
993 stmp.str(col_header.substr(0x19));
994 GET_INT(stmp, total_rows);
995 GET_INT(stmp, first_row);
996 GET_INT(stmp, last_row);
997 LOG_PRINT(logfile, " total %d, first %d, last %d rows\n", total_rows, first_row, last_row)
998
999 unsigned short signature;
1000 if (col_header_size > 0x72) {
1001 stmp.str(col_header.substr(0x71));
1002 GET_SHORT(stmp, signature);
1003 } else {
1004 LOG_PRINT(logfile, " NOTE: alternative signature determination\n")
1005 signature = col_header[0x18];
1006 }
1007 LOG_PRINT(logfile, " signature %d [0x%X], valuesize %d size %d ", signature, signature, valuesize, col_data_size)
1008
1009
1010 size_t current_col = 1;//, nr = 0, nbytes = 0;
1011 static unsigned int col_index = 0;
1012 unsigned int current_sheet = 0;
1013 vector<Origin::SpreadSheet>::difference_type spread = 0;
1014
1015 if (column_name.empty()) { // Matrix or function
1016 if (data_type == 0x6081) { // Function
1017 functions.push_back(Function(name, objectIndex));
1018 Origin::Function &f = functions.back();
1019 f.formula = toLowerCase(col_data.c_str());
1020
1021 stmp.str(col_header.substr(0x0A));
1022 short t;
1023 GET_SHORT(stmp, t)
1024 if (t == 0x1194)
1025 f.type = Function::Polar;
1026
1027 stmp.str(col_header.substr(0x21));
1028 GET_INT(stmp, f.totalPoints)
1029 GET_DOUBLE(stmp, f.begin)
1030 double d;
1031 GET_DOUBLE(stmp, d)
1032 f.end = f.begin + d*(f.totalPoints - 1);
1033
1034 LOG_PRINT(logfile, "\n NEW FUNCTION: %s = %s", f.name.c_str(), f.formula.c_str());
1035 LOG_PRINT(logfile, ". Range [%g : %g], number of points: %d\n", f.begin, f.end, f.totalPoints);
1036
1037 } else { // Matrix
1038 vector<Origin::Matrix>::difference_type mIndex = -1;
1039 string::size_type pos = name.find_first_of("@");
1040 if (pos != string::npos){
1041 string sheetName = name;
1042 name.resize(pos);
1043 mIndex = findMatrixByName(name);
1044 if (mIndex != -1){
1045 LOG_PRINT(logfile, "\n NEW MATRIX SHEET\n");
1046 matrixes[mIndex].sheets.push_back(MatrixSheet(sheetName, objectIndex));
1047 }
1048 } else {
1049 LOG_PRINT(logfile, "\n NEW MATRIX\n");
1050 matrixes.push_back(Matrix(name));
1051 matrixes.back().sheets.push_back(MatrixSheet(name, objectIndex));
1052 }
1053 // add an empty data set to keep objectIndex synchronized with datasets.size()
1054 datasets.push_back(SpreadColumn(name,objectIndex));
1055 getMatrixValues(col_data, col_data_size, data_type, data_type_u, valuesize, mIndex);
1056 }
1057 } else {
1058 if(spreadSheets.size() == 0 || findSpreadByName(name) == -1) {
1059 LOG_PRINT(logfile, "\n NEW SPREADSHEET\n");
1060 current_col = 1;
1061 spreadSheets.push_back(SpreadSheet(name));
1062 spread = spreadSheets.size() - 1;
1063 spreadSheets.back().maxRows = 0;
1064 current_sheet = 0;
1065 } else {
1066 spread = findSpreadByName(name);
1067 current_col = spreadSheets[spread].columns.size();
1068 if(!current_col)
1069 current_col = 1;
1070 ++current_col;
1071 }
1072 spreadSheets[spread].columns.push_back(SpreadColumn(column_name, objectIndex));
1073 spreadSheets[spread].columns.back().colIndex = ++col_index;
1074 spreadSheets[spread].columns.back().dataset_name = dataset_name;
1075 spreadSheets[spread].columns.back().numRows = total_rows;
1076 spreadSheets[spread].columns.back().beginRow = first_row;
1077 spreadSheets[spread].columns.back().endRow = last_row;
1078
1079 string::size_type sheetpos = spreadSheets[spread].columns.back().name.find_last_of("@");
1080 if(sheetpos != string::npos){
1081 unsigned int sheet = strtol(column_name.substr(sheetpos + 1).c_str(), nullptr, 10);
1082 if( sheet > 1){
1083 spreadSheets[spread].columns.back().name = column_name;
1084
1085 if (current_sheet != (sheet - 1))
1086 current_sheet = sheet - 1;
1087
1088 spreadSheets[spread].columns.back().sheet = current_sheet;
1089 if (spreadSheets[spread].sheets < sheet)
1090 spreadSheets[spread].sheets = sheet;
1091 }
1092 }
1093 LOG_PRINT(logfile, " data index %d, valuesize %d, ", objectIndex, valuesize)
1094
1095 unsigned int nr = col_data_size / valuesize;
1096 LOG_PRINT(logfile, "n. of rows = %d\n\n", nr)
1097
1098 spreadSheets[spread].maxRows<nr ? spreadSheets[spread].maxRows=nr : 0;
1099 stmp.str(col_data);
1100 for(unsigned int i = 0; i < nr; ++i)
1101 {
1102 double value;
1103 if(valuesize <= 8) // Numeric, Time, Date, Month, Day
1104 {
1105 GET_DOUBLE(stmp, value)
1106 if ((i < 5) || (i > (nr-5))) {
1107 LOG_PRINT(logfile, "%g ", value)
1108 } else if (i == 5) {
1109 LOG_PRINT(logfile, "... ")
1110 }
1111 spreadSheets[spread].columns[(current_col-1)].data.push_back(value);
1112 }
1113 else if((data_type & 0x100) == 0x100) // Text&Numeric
1114 {
1115 unsigned char c = col_data[i*valuesize];
1116 stmp.seekg(i*valuesize+2, ios_base::beg);
1117 if(c != 1) //value
1118 {
1119 GET_DOUBLE(stmp, value);
1120 if ((i < 5) || (i > (nr-5))) {
1121 LOG_PRINT(logfile, "%g ", value)
1122 } else if (i == 5) {
1123 LOG_PRINT(logfile, "... ")
1124 }
1125 spreadSheets[spread].columns[(current_col-1)].data.push_back(value);
1126 }
1127 else //text
1128 {
1129 string svaltmp = col_data.substr(i*valuesize+2, valuesize-2);
1130 // TODO: check if this test is still needed
1131 if(svaltmp.find(0x0E) != string::npos) { // try find non-printable symbol - garbage test
1132 svaltmp = string();
1133 LOG_PRINT(logfile, "Non printable symbol found, place 1 for i=%d\n", i)
1134 }
1135 if ((i < 5) || (i > (nr-5))) {
1136 LOG_PRINT(logfile, "\"%s\" ", svaltmp.c_str())
1137 } else if (i == 5) {
1138 LOG_PRINT(logfile, "... ")
1139 }
1140 spreadSheets[spread].columns[(current_col-1)].data.push_back(svaltmp);
1141 }
1142 }
1143 else //text
1144 {
1145 string svaltmp = col_data.substr(i*valuesize, valuesize).c_str();
1146 // TODO: check if this test is still needed
1147 if(svaltmp.find(0x0E) != string::npos) { // try find non-printable symbol - garbage test
1148 svaltmp = string();
1149 LOG_PRINT(logfile, "Non printable symbol found, place 2 for i=%d\n", i)
1150 }
1151 if ((i < 5) || (i > (nr-5))) {
1152 LOG_PRINT(logfile, "\"%s\" ", svaltmp.c_str())
1153 } else if (i == 5) {
1154 LOG_PRINT(logfile, "... ")
1155 }
1156 spreadSheets[spread].columns[(current_col-1)].data.push_back(svaltmp);
1157 }
1158 }
1159 LOG_PRINT(logfile, "\n\n")
1160 datasets.push_back(spreadSheets[spread].columns.back());
1161 }
1162 ++objectIndex;
1163
1164 return true;
1165 }
1166
getMatrixValues(const string & col_data,unsigned int col_data_size,short data_type,char data_type_u,char valuesize,vector<Origin::Matrix>::difference_type mIndex)1167 void OriginAnyParser::getMatrixValues(const string& col_data, unsigned int col_data_size, short data_type, char data_type_u, char valuesize, vector<Origin::Matrix>::difference_type mIndex) {
1168 if (matrixes.empty())
1169 return;
1170
1171 istringstream stmp;
1172 stmp.str(col_data);
1173
1174 if (mIndex < 0)
1175 mIndex = (vector<Origin::Matrix>::difference_type)matrixes.size() - 1;
1176
1177 unsigned int size = col_data_size/valuesize;
1178 bool logValues = true;
1179 switch(data_type){
1180 case 0x6001://double
1181 for(unsigned int i = 0; i < size; ++i){
1182 double value;
1183 GET_DOUBLE(stmp, value)
1184 matrixes[mIndex].sheets.back().data.push_back(value);
1185 }
1186 break;
1187 case 0x6003://float
1188 for(unsigned int i = 0; i < size; ++i){
1189 float value;
1190 GET_FLOAT(stmp, value)
1191 matrixes[mIndex].sheets.back().data.push_back((double)value);
1192 }
1193 break;
1194 case 0x6801://int
1195 if (data_type_u == 8){//unsigned
1196 for(unsigned int i = 0; i < size; ++i){
1197 unsigned int value;
1198 GET_INT(stmp, value)
1199 matrixes[mIndex].sheets.back().data.push_back((double)value);
1200 }
1201 } else {
1202 for(unsigned int i = 0; i < size; ++i){
1203 int value;
1204 GET_INT(stmp, value)
1205 matrixes[mIndex].sheets.back().data.push_back((double)value);
1206 }
1207 }
1208 break;
1209 case 0x6803://short
1210 if (data_type_u == 8){//unsigned
1211 for(unsigned int i = 0; i < size; ++i){
1212 unsigned short value;
1213 GET_SHORT(stmp, value)
1214 matrixes[mIndex].sheets.back().data.push_back((double)value);
1215 }
1216 } else {
1217 for(unsigned int i = 0; i < size; ++i){
1218 short value;
1219 GET_SHORT(stmp, value)
1220 matrixes[mIndex].sheets.back().data.push_back((double)value);
1221 }
1222 }
1223 break;
1224 case 0x6821://char
1225 if (data_type_u == 8){//unsigned
1226 for(unsigned int i = 0; i < size; ++i){
1227 unsigned char value;
1228 value = col_data[i];
1229 matrixes[mIndex].sheets.back().data.push_back((double)value);
1230 }
1231 } else {
1232 for(unsigned int i = 0; i < size; ++i){
1233 char value;
1234 value = col_data[i];
1235 matrixes[mIndex].sheets.back().data.push_back((double)value);
1236 }
1237 }
1238 break;
1239 default:
1240 LOG_PRINT(logfile, " UNKNOWN MATRIX DATATYPE: %02X SKIP DATA\n", data_type);
1241 matrixes.pop_back();
1242 logValues = false;
1243 }
1244
1245 if (logValues){
1246 LOG_PRINT(logfile, " FIRST 10 CELL VALUES: ");
1247 for(unsigned int i = 0; i < 10 && i < matrixes[mIndex].sheets.back().data.size(); ++i)
1248 LOG_PRINT(logfile, "%g\t", matrixes[mIndex].sheets.back().data[i]);
1249 }
1250 }
1251
getWindowProperties(Origin::Window & window,const string & wde_header,unsigned int wde_header_size)1252 void OriginAnyParser::getWindowProperties(Origin::Window& window, const string& wde_header, unsigned int wde_header_size) {
1253 window.objectID = objectIndex;
1254 ++objectIndex;
1255
1256 istringstream stmp;
1257
1258 stmp.str(wde_header.substr(0x1B));
1259 GET_SHORT(stmp, window.frameRect.left)
1260 GET_SHORT(stmp, window.frameRect.top)
1261 GET_SHORT(stmp, window.frameRect.right)
1262 GET_SHORT(stmp, window.frameRect.bottom)
1263
1264 char c = wde_header[0x32];
1265
1266 if(c & 0x01)
1267 window.state = Window::Minimized;
1268 else if(c & 0x02)
1269 window.state = Window::Maximized;
1270
1271 if (wde_header[0x42] != 0) {
1272 window.windowBackgroundColorGradient = (ColorGradientDirection)(wde_header[0x42] >> 2);
1273 window.windowBackgroundColorBase.type = Color::Regular;
1274 window.windowBackgroundColorBase.regular = wde_header[0x43];
1275 window.windowBackgroundColorEnd.type = Color::Regular;
1276 window.windowBackgroundColorEnd.regular = wde_header[0x44];
1277 } else {
1278 window.windowBackgroundColorGradient = ColorGradientDirection::NoGradient;
1279 window.windowBackgroundColorBase.type = Color::Regular;
1280 window.windowBackgroundColorBase.regular = Color::White;
1281 window.windowBackgroundColorEnd.type = Color::Regular;
1282 window.windowBackgroundColorEnd.regular = Color::White;
1283 }
1284 LOG_PRINT(logfile, "ColorGradient %d, base %d, end %d\n",window.windowBackgroundColorGradient,
1285 window.windowBackgroundColorBase.regular, window.windowBackgroundColorEnd.regular);
1286
1287 c = wde_header[0x69];
1288
1289 if(c & 0x01)
1290 window.title = Window::Label;
1291 else if(c & 0x02)
1292 window.title = Window::Name;
1293 else
1294 window.title = Window::Both;
1295
1296 window.hidden = ((c & 0x08) != 0);
1297 if (window.hidden) {
1298 LOG_PRINT(logfile, " WINDOW %d NAME : %s is hidden\n", objectIndex, window.name.c_str());
1299 } else {
1300 LOG_PRINT(logfile, " WINDOW %d NAME : %s is not hidden\n", objectIndex, window.name.c_str());
1301 }
1302
1303 if (wde_header_size > 0x82) {
1304 // only projects of version 6.0 and higher have these
1305 double creationDate, modificationDate;
1306 stmp.str(wde_header.substr(0x73));
1307 GET_DOUBLE(stmp, creationDate);
1308 window.creationDate = doubleToPosixTime(creationDate);
1309 GET_DOUBLE(stmp, modificationDate)
1310 window.modificationDate = doubleToPosixTime(modificationDate);
1311 }
1312
1313 if ((wde_header_size > 0x9E) && (wde_header[0x42] != 0)) {
1314 // get window background colors for version > 5.0
1315 window.windowBackgroundColorBase = getColor(wde_header.substr(0x97,4));
1316 window.windowBackgroundColorEnd = getColor(wde_header.substr(0x9B,4));
1317 }
1318
1319 if(wde_header_size > 0xC3){
1320 window.label = wde_header.substr(0xC3).c_str();
1321 window.label = window.label.substr(0,window.label.find("@${"));
1322 LOG_PRINT(logfile, " WINDOW %d LABEL: %s\n", objectIndex, window.label.c_str());
1323 }
1324
1325 if (imatrix != -1) { // additional properties for matrix windows
1326 unsigned char h = wde_header[0x29];
1327 matrixes[imatrix].activeSheet = h;
1328 if (wde_header_size > 0x86) {
1329 h = wde_header[0x87];
1330 matrixes[imatrix].header = (h == 194) ? Matrix::XY : Matrix::ColumnRow;
1331 }
1332 }
1333 if (igraph != -1) { // additional properties for graph/layout windows
1334 stmp.str(wde_header.substr(0x23));
1335 GET_SHORT(stmp, graphs[igraph].width)
1336 GET_SHORT(stmp, graphs[igraph].height)
1337
1338 unsigned char c = wde_header[0x38];
1339 graphs[igraph].connectMissingData = ((c & 0x40) != 0);
1340
1341 string templateName = wde_header.substr(0x45,20).c_str();
1342 graphs[igraph].templateName = templateName;
1343 if (templateName == "LAYOUT") graphs[igraph].isLayout = true;
1344 }
1345 }
1346
getLayerProperties(const string & lye_header,unsigned int lye_header_size)1347 void OriginAnyParser::getLayerProperties(const string& lye_header, unsigned int lye_header_size) {
1348 istringstream stmp;
1349
1350 if (ispread != -1) { // spreadsheet
1351
1352 spreadSheets[ispread].loose = false;
1353
1354 } else if (imatrix != -1) { // matrix
1355
1356 MatrixSheet& sheet = matrixes[imatrix].sheets[ilayer];
1357
1358 unsigned short width = 8;
1359 stmp.str(lye_header.substr(0x27));
1360 GET_SHORT(stmp, width)
1361 if (width == 0) width = 8;
1362 sheet.width = width;
1363
1364 stmp.str(lye_header.substr(0x2B));
1365 GET_SHORT(stmp, sheet.columnCount)
1366
1367 stmp.str(lye_header.substr(0x52));
1368 GET_SHORT(stmp, sheet.rowCount)
1369
1370 unsigned char view = lye_header[0x71];
1371 if (view != 0x32 && view != 0x28){
1372 sheet.view = MatrixSheet::ImageView;
1373 } else {
1374 sheet.view = MatrixSheet::DataView;
1375 }
1376
1377 if (lye_header_size > 0xD2) {
1378 sheet.name = lye_header.substr(0xD2,32).c_str();
1379 }
1380
1381 } else if (iexcel != -1) { // excel
1382
1383 excels[iexcel].loose = false;
1384 if (lye_header_size > 0xD2) {
1385 excels[iexcel].sheets[ilayer].name = lye_header.substr(0xD2,32).c_str();
1386 }
1387
1388 } else { // graph
1389 graphs[igraph].layers.push_back(GraphLayer());
1390 GraphLayer& glayer = graphs[igraph].layers[ilayer];
1391
1392 stmp.str(lye_header.substr(0x0F));
1393 GET_DOUBLE(stmp, glayer.xAxis.min);
1394 GET_DOUBLE(stmp, glayer.xAxis.max);
1395 GET_DOUBLE(stmp, glayer.xAxis.step);
1396
1397 glayer.xAxis.majorTicks = lye_header[0x2B];
1398
1399 unsigned char g = lye_header[0x2D];
1400 glayer.xAxis.zeroLine = ((g & 0x80) != 0);
1401 glayer.xAxis.oppositeLine = ((g & 0x40) != 0);
1402
1403 glayer.xAxis.minorTicks = lye_header[0x37];
1404 glayer.xAxis.scale = lye_header[0x38];
1405
1406 stmp.str(lye_header.substr(0x3A));
1407 GET_DOUBLE(stmp, glayer.yAxis.min);
1408 GET_DOUBLE(stmp, glayer.yAxis.max);
1409 GET_DOUBLE(stmp, glayer.yAxis.step);
1410
1411 glayer.yAxis.majorTicks = lye_header[0x56];
1412
1413 g = lye_header[0x58];
1414 glayer.yAxis.zeroLine = ((g & 0x80) != 0);
1415 glayer.yAxis.oppositeLine = ((g & 0x40) != 0);
1416
1417 glayer.yAxis.minorTicks = lye_header[0x62];
1418 glayer.yAxis.scale = lye_header[0x63];
1419
1420 g = lye_header[0x68];
1421 glayer.gridOnTop = ((g & 0x04) != 0);
1422 glayer.exchangedAxes = ((g & 0x40) != 0);
1423
1424 stmp.str(lye_header.substr(0x71));
1425 GET_SHORT(stmp, glayer.clientRect.left)
1426 GET_SHORT(stmp, glayer.clientRect.top)
1427 GET_SHORT(stmp, glayer.clientRect.right)
1428 GET_SHORT(stmp, glayer.clientRect.bottom)
1429
1430 unsigned char border = lye_header[0x89];
1431 glayer.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None);
1432
1433 if (lye_header_size > 0x107)
1434 glayer.backgroundColor = getColor(lye_header.substr(0x105,4));
1435
1436 }
1437 }
1438
getColor(const string & strbincolor)1439 Origin::Color OriginAnyParser::getColor(const string& strbincolor) {
1440 /* decode a color value from a 4 byte binary string */
1441 Origin::Color result;
1442 unsigned char sbincolor[4];
1443 for (int i=0; i < 4; i++) {
1444 sbincolor[i] = strbincolor[i];
1445 }
1446 switch(sbincolor[3]) {
1447 case 0:
1448 if(sbincolor[0] < 0x64) {
1449 result.type = Origin::Color::Regular;
1450 result.regular = sbincolor[0];
1451 } else {
1452 switch(sbincolor[2]) {
1453 case 0:
1454 result.type = Origin::Color::Indexing;
1455 break;
1456 case 0x40:
1457 result.type = Origin::Color::Mapping;
1458 break;
1459 case 0x80:
1460 result.type = Origin::Color::RGB;
1461 break;
1462 }
1463 result.column = sbincolor[0] - 0x64;
1464 }
1465 break;
1466 case 1:
1467 result.type = Origin::Color::Custom;
1468 for(int i = 0; i < 3; ++i)
1469 result.custom[i] = sbincolor[i];
1470 break;
1471 case 0x20:
1472 result.type = Origin::Color::Increment;
1473 result.starting = sbincolor[1];
1474 break;
1475 case 0xFF:
1476 if(sbincolor[0] == 0xFC)
1477 result.type = Origin::Color::None;
1478 else if(sbincolor[0] == 0xF7)
1479 result.type = Origin::Color::Automatic;
1480 else {
1481 result.type = Origin::Color::Regular;
1482 result.regular = sbincolor[0];
1483 }
1484 break;
1485 default:
1486 result.type = Origin::Color::Regular;
1487 result.regular = sbincolor[0];
1488 break;
1489 }
1490 return result;
1491 }
1492
getAnnotationProperties(const string & anhd,unsigned int anhdsz,const string & andt1,unsigned int andt1sz,const string & andt2,unsigned int andt2sz,const string & andt3,unsigned int andt3sz)1493 void OriginAnyParser::getAnnotationProperties(const string& anhd, unsigned int anhdsz, const string& andt1, unsigned int andt1sz, const string& andt2, unsigned int andt2sz, const string& andt3, unsigned int andt3sz) {
1494 istringstream stmp;
1495 (void) anhdsz; (void) andt3; (void) andt3sz;
1496
1497 if (ispread != -1) {
1498
1499 string sec_name = anhd.substr(0x46,41).c_str();
1500 int col_index = findColumnByName((int)ispread, sec_name);
1501 if (col_index != -1){ //check if it is a formula
1502 spreadSheets[ispread].columns[col_index].command = andt1.c_str();
1503 LOG_PRINT(logfile, " Column: %s has formula: %s\n", sec_name.c_str(), spreadSheets[ispread].columns[col_index].command.c_str())
1504 }
1505
1506 } else if (imatrix != -1) {
1507
1508 MatrixSheet& sheet = matrixes[imatrix].sheets[ilayer];
1509 string sec_name = anhd.substr(0x46,41).c_str();
1510
1511 stmp.str(andt1.c_str());
1512 if (sec_name == "MV") {
1513 sheet.command = andt1.c_str();
1514 } else if (sec_name == "Y2") {
1515 stmp >> sheet.coordinates[0];
1516 } else if (sec_name == "X2") {
1517 stmp >> sheet.coordinates[1];
1518 } else if (sec_name == "Y1") {
1519 stmp >> sheet.coordinates[2];
1520 } else if (sec_name == "X1") {
1521 stmp >> sheet.coordinates[3];
1522 } else if (sec_name == "COLORMAP") {
1523 // Color maps for matrix annotations are similar to color maps for graph curves (3D).
1524 // They differ only in the start offset to the data string.
1525 getColorMap(sheet.colorMap, andt2, andt2sz);
1526 }
1527
1528 } else if (iexcel != -1) {
1529
1530 string sec_name = anhd.substr(0x46,41).c_str();
1531 vector<Origin::SpreadColumn>::difference_type col_index = findExcelColumnByName(iexcel, ilayer, sec_name);
1532 if (col_index != -1){ //check if it is a formula
1533 excels[iexcel].sheets[ilayer].columns[col_index].command = andt1.c_str();
1534 }
1535
1536 } else {
1537
1538 GraphLayer& glayer = graphs[igraph].layers[ilayer];
1539 string sec_name = anhd.substr(0x46,41).c_str();
1540
1541 Rect r;
1542 stmp.str(anhd.substr(0x03));
1543 GET_SHORT(stmp, r.left)
1544 GET_SHORT(stmp, r.top)
1545 GET_SHORT(stmp, r.right)
1546 GET_SHORT(stmp, r.bottom)
1547
1548 unsigned char attach = anhd[0x28];
1549 if (attach >= (unsigned char)Attach::End_) attach = Attach::Frame;
1550 unsigned char border = anhd[0x29];
1551
1552 Color color = getColor(anhd.substr(0x33,4));
1553
1554 if (sec_name == "PL") glayer.yAxis.formatAxis[0].prefix = andt1.c_str();
1555 if (sec_name == "PR") glayer.yAxis.formatAxis[1].prefix = andt1.c_str();
1556 if (sec_name == "PB") glayer.xAxis.formatAxis[0].prefix = andt1.c_str();
1557 if (sec_name == "PT") glayer.xAxis.formatAxis[1].prefix = andt1.c_str();
1558 if (sec_name == "SL") glayer.yAxis.formatAxis[0].suffix = andt1.c_str();
1559 if (sec_name == "SR") glayer.yAxis.formatAxis[1].suffix = andt1.c_str();
1560 if (sec_name == "SB") glayer.xAxis.formatAxis[0].suffix = andt1.c_str();
1561 if (sec_name == "ST") glayer.xAxis.formatAxis[1].suffix = andt1.c_str();
1562 if (sec_name == "OL") glayer.yAxis.formatAxis[0].factor = andt1.c_str();
1563 if (sec_name == "OR") glayer.yAxis.formatAxis[1].factor = andt1.c_str();
1564 if (sec_name == "OB") glayer.xAxis.formatAxis[0].factor = andt1.c_str();
1565 if (sec_name == "OT") glayer.xAxis.formatAxis[1].factor = andt1.c_str();
1566
1567 unsigned char type = andt1[0x00];
1568 LineVertex begin, end;
1569 /* OriginNNNParser identify line/arrow annotation by checking size of andt1
1570 Origin410: 21||24; Origin 500: 24; Origin 610: 24||96; Origin700 and higher: 120;
1571 An alternative is to look at anhd[0x02]:
1572 (0x21 for Circle/Rect, 0x22 for Line/Arrow, 0x23 for Polygon/Polyline)
1573 */
1574 unsigned char ankind = anhd[0x02];
1575 if (ankind == 0x22) {//Line/Arrow
1576 if ((attach == Origin::Scale) && (andt1sz > 0x5F)) {
1577 if (type == 2) {
1578 stmp.str(andt1.substr(0x20));
1579 GET_DOUBLE(stmp, begin.x)
1580 GET_DOUBLE(stmp, end.x)
1581 stmp.str(andt1.substr(0x40));
1582 GET_DOUBLE(stmp, begin.y)
1583 GET_DOUBLE(stmp, end.y)
1584 } else if (type == 4) {//curved arrow: start point, 2 middle points and end point
1585 stmp.str(andt1.substr(0x20));
1586 GET_DOUBLE(stmp, begin.x)
1587 GET_DOUBLE(stmp, end.x)
1588 GET_DOUBLE(stmp, end.x)
1589 GET_DOUBLE(stmp, end.x)
1590 GET_DOUBLE(stmp, begin.y)
1591 GET_DOUBLE(stmp, end.y)
1592 GET_DOUBLE(stmp, end.y)
1593 GET_DOUBLE(stmp, end.y)
1594 }
1595 } else {
1596 short x1=0, x2=0, y1=0, y2=0;
1597 if (type == 2) {//straight line/arrow
1598 stmp.str(andt1.substr(0x01));
1599 GET_SHORT(stmp, x1)
1600 GET_SHORT(stmp, x2)
1601 stmp.seekg(4, ios_base::cur);
1602 GET_SHORT(stmp, y1)
1603 GET_SHORT(stmp, y2)
1604 } else if (type == 4) {//curved line/arrow has 4 points
1605 stmp.str(andt1.substr(0x01));
1606 GET_SHORT(stmp, x1)
1607 stmp.seekg(4, ios_base::cur);
1608 GET_SHORT(stmp, x2)
1609 GET_SHORT(stmp, y1)
1610 stmp.seekg(4, ios_base::cur);
1611 GET_SHORT(stmp, y2)
1612 }
1613
1614 double dx = fabs(x2 - x1);
1615 double dy = fabs(y2 - y1);
1616 double minx = (x1 <= x2) ? x1 : x2;
1617 double miny = (y1 <= y2) ? y1 : y2;
1618
1619 begin.x = (x1 == x2) ? r.left + 0.5*r.width() : r.left + (x1 - minx)/dx*r.width();
1620 end.x = (x1 == x2) ? r.left + 0.5*r.width() : r.left + (x2 - minx)/dx*r.width();
1621 begin.y = (y1 == y2) ? r.top + 0.5*r.height(): r.top + (y1 - miny)/dy*r.height();
1622 end.y = (y1 == y2) ? r.top + 0.5*r.height(): r.top + (y2 - miny)/dy*r.height();
1623 }
1624 unsigned char arrows = andt1[0x11];
1625 switch (arrows) {
1626 case 0:
1627 begin.shapeType = 0;
1628 end.shapeType = 0;
1629 break;
1630 case 1:
1631 begin.shapeType = 1;
1632 end.shapeType = 0;
1633 break;
1634 case 2:
1635 begin.shapeType = 0;
1636 end.shapeType = 1;
1637 break;
1638 case 3:
1639 begin.shapeType = 1;
1640 end.shapeType = 1;
1641 break;
1642 }
1643 if (andt1sz > 0x77) {
1644 begin.shapeType = andt1[0x60];
1645 unsigned int w = 0;
1646 stmp.str(andt1.substr(0x64));
1647 GET_INT(stmp, w)
1648 begin.shapeWidth = (double)w/500.0;
1649 GET_INT(stmp, w)
1650 begin.shapeLength = (double)w/500.0;
1651
1652 end.shapeType = andt1[0x6C];
1653 stmp.str(andt1.substr(0x70));
1654 GET_INT(stmp, w)
1655 end.shapeWidth = (double)w/500.0;
1656 GET_INT(stmp, w)
1657 end.shapeLength = (double)w/500.0;
1658 }
1659 }
1660 //text properties
1661 short rotation;
1662 stmp.str(andt1.substr(0x02));
1663 GET_SHORT(stmp, rotation)
1664 unsigned char fontSize = andt1[0x4];
1665 unsigned char tab = andt1[0x0A];
1666
1667 //line properties
1668 unsigned char lineStyle = andt1[0x12];
1669 unsigned short w1 = 0;
1670 if (andt1sz > 0x14) {
1671 stmp.str(andt1.substr(0x13));
1672 GET_SHORT(stmp, w1)
1673 }
1674 double width = (double)w1/500.0;
1675
1676 Figure figure;
1677 stmp.str(andt1.substr(0x05));
1678 GET_SHORT(stmp, w1)
1679 figure.width = (double)w1/500.0;
1680 figure.style = andt1[0x08];
1681
1682 if (andt1sz > 0x4D) {
1683 figure.fillAreaColor = getColor(andt1.substr(0x42,4));
1684 stmp.str(andt1.substr(0x46));
1685 GET_SHORT(stmp, w1)
1686 figure.fillAreaPatternWidth = (double)w1/500.0;
1687 figure.fillAreaPatternColor = getColor(andt1.substr(0x4A,4));
1688 figure.fillAreaPattern = andt1[0x4E];
1689 }
1690 if (andt1sz > 0x56) {
1691 unsigned char h = andt1[0x57];
1692 figure.useBorderColor = (h == 0x10);
1693 }
1694
1695 if (sec_name == "XB") {
1696 string text = andt2.c_str();
1697 glayer.xAxis.position = GraphAxis::Bottom;
1698 glayer.xAxis.formatAxis[0].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach);
1699 }
1700 else if (sec_name == "XT") {
1701 string text = andt2.c_str();
1702 glayer.xAxis.position = GraphAxis::Top;
1703 glayer.xAxis.formatAxis[1].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach);
1704 }
1705 else if (sec_name == "YL") {
1706 string text = andt2.c_str();
1707 glayer.yAxis.position = GraphAxis::Left;
1708 glayer.yAxis.formatAxis[0].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach);
1709 }
1710 else if (sec_name == "YR") {
1711 string text = andt2.c_str();
1712 glayer.yAxis.position = GraphAxis::Right;
1713 glayer.yAxis.formatAxis[1].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach);
1714 }
1715 else if (sec_name == "ZF") {
1716 string text = andt2.c_str();
1717 glayer.zAxis.position = GraphAxis::Front;
1718 glayer.zAxis.formatAxis[0].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach);
1719 }
1720 else if (sec_name == "ZB") {
1721 string text = andt2.c_str();
1722 glayer.zAxis.position = GraphAxis::Back;
1723 glayer.zAxis.formatAxis[1].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach);
1724 }
1725 else if (sec_name == "3D") {
1726 stmp.str(andt2);
1727 GET_DOUBLE(stmp, glayer.zAxis.min)
1728 GET_DOUBLE(stmp, glayer.zAxis.max)
1729 GET_DOUBLE(stmp, glayer.zAxis.step)
1730 glayer.zAxis.majorTicks = andt2[0x1C];
1731 glayer.zAxis.minorTicks = andt2[0x28];
1732 glayer.zAxis.scale = andt2[0x29];
1733
1734 stmp.str(andt2.substr(0x5A));
1735 GET_FLOAT(stmp, glayer.xAngle)
1736 GET_FLOAT(stmp, glayer.yAngle)
1737 GET_FLOAT(stmp, glayer.zAngle)
1738
1739 stmp.str(andt2.substr(0x218));
1740 GET_FLOAT(stmp, glayer.xLength)
1741 GET_FLOAT(stmp, glayer.yLength)
1742 GET_FLOAT(stmp, glayer.zLength)
1743 glayer.xLength /= 23.0;
1744 glayer.yLength /= 23.0;
1745 glayer.zLength /= 23.0;
1746
1747 glayer.orthographic3D = (andt2[0x240] != 0);
1748 }
1749 else if (sec_name == "Legend") {
1750 string text = andt2.c_str();
1751 glayer.legend = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach);
1752 }
1753 else if (sec_name == "__BCO2") { // histogram
1754 stmp.str(andt2.substr(0x10));
1755 GET_DOUBLE(stmp, glayer.histogramBin)
1756 stmp.str(andt2.substr(0x20));
1757 GET_DOUBLE(stmp, glayer.histogramEnd)
1758 GET_DOUBLE(stmp, glayer.histogramBegin)
1759
1760 // TODO: check if 0x5E is right (obtained from anhdsz-0x46+93-andt1sz = 111-70+93-40 = 94)
1761 glayer.percentile.p1SymbolType = andt2[0x5E];
1762 glayer.percentile.p99SymbolType = andt2[0x5F];
1763 glayer.percentile.meanSymbolType = andt2[0x60];
1764 glayer.percentile.maxSymbolType = andt2[0x61];
1765 glayer.percentile.minSymbolType = andt2[0x62];
1766
1767 // 0x9F = 0x5E+65
1768 glayer.percentile.labels = andt2[0x9F];
1769 // 0x6B = 0x5E+106-93 = 107
1770 glayer.percentile.whiskersRange = andt2[0x6B];
1771 glayer.percentile.boxRange = andt2[0x6C];
1772 // 0x8e = 0x5E+141-93 = 142
1773 glayer.percentile.whiskersCoeff = andt2[0x8e];
1774 glayer.percentile.boxCoeff = andt2[0x8f];
1775 unsigned char h = andt2[0x90];
1776 glayer.percentile.diamondBox = (h == 0x82) ? true : false;
1777 // 0xCB = 0x5E+109 = 203
1778 stmp.str(andt2.substr(0xCB));
1779 GET_SHORT(stmp, glayer.percentile.symbolSize)
1780 glayer.percentile.symbolSize = glayer.percentile.symbolSize/2 + 1;
1781 // 0x101 = 0x5E+163
1782 glayer.percentile.symbolColor = getColor(andt2.substr(0x101,4));
1783 glayer.percentile.symbolFillColor = getColor(andt2.substr(0x105,4));
1784 }
1785 else if (sec_name == "_206") { // box plot labels
1786 }
1787 else if (sec_name == "VLine") {
1788 stmp.str(andt1.substr(0x0A));
1789 double start;
1790 GET_DOUBLE(stmp, start)
1791 stmp.str(andt1.substr(0x1A));
1792 double width;
1793 GET_DOUBLE(stmp, width)
1794 glayer.vLine = start + 0.5*width;
1795 glayer.imageProfileTool = 2;
1796 }
1797 else if (sec_name == "HLine") {
1798 stmp.str(andt1.substr(0x12));
1799 double start;
1800 GET_DOUBLE(stmp, start)
1801 stmp.str(andt1.substr(0x22));
1802 double width;
1803 GET_DOUBLE(stmp, width)
1804 glayer.hLine = start + 0.5*width;
1805 glayer.imageProfileTool = 2;
1806 }
1807 else if (sec_name == "vline") {
1808 stmp.str(andt1.substr(0x20));
1809 GET_DOUBLE(stmp, glayer.vLine)
1810 glayer.imageProfileTool = 1;
1811 }
1812 else if (sec_name == "hline") {
1813 stmp.str(andt1.substr(0x40));
1814 GET_DOUBLE(stmp, glayer.hLine)
1815 glayer.imageProfileTool = 1;
1816 }
1817 else if (sec_name == "ZCOLORS") {
1818 glayer.isXYY3D = true;
1819 if (fileVersion < 600) {
1820 ColorMap& colorMap = glayer.colorMap;
1821 getZcolorsMap(colorMap, andt2, andt2sz);
1822 }
1823 }
1824 else if (sec_name == "SPECTRUM1") {
1825 glayer.isXYY3D = false;
1826 glayer.colorScale.visible = true;
1827 glayer.colorScale.reverseOrder = (andt2[0x18] != 0);
1828 stmp.str(andt2.substr(0x20));
1829 GET_SHORT(stmp, glayer.colorScale.colorBarThickness)
1830 GET_SHORT(stmp, glayer.colorScale.labelGap)
1831 glayer.colorScale.labelsColor = getColor(andt2.substr(0x5C,4));
1832 }
1833 else if (sec_name == "&0") {
1834 glayer.isWaterfall = true;
1835 string text = andt1.c_str();
1836 string::size_type commaPos = text.find_first_of(",");
1837 stmp.str(text.substr(0,commaPos));
1838 stmp >> glayer.xOffset;
1839 stmp.str(text.substr(commaPos+1));
1840 stmp >> glayer.yOffset;
1841 }
1842 /* OriginNNNParser identify text, circle, rectangle and bitmap annotation by checking size of andt1:
1843 text/pie text rectangle/circle line bitmap
1844 Origin410: 22 0xA(10) 21/24 38
1845 Origin500: 22 0xA(10) 24 40
1846 Origin610: 22 0xA(10) 24/96 40
1847 Origin700: 0x5E(94) 120 0x28(40)
1848 Origin750: 0x3E(62)/78 0x5E(94) 0x78(120) 0x28(40)
1849 Origin850: 0x3E(62)/78 0x5E(94) 0x78(120) 0x28(40)
1850 An alternative is to look at anhd[0x02]:
1851 (0x00 for Text, 0x21 for Circle/Rect, 0x22 for Line/Arrow, 0x23 for Polygon/Polyline)
1852 */
1853 else if ((ankind == 0x0) && (sec_name != "DelData")) { // text
1854 string text = andt2.c_str();
1855 if (sec_name.substr(0,3) == "PIE")
1856 glayer.pieTexts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach));
1857 else
1858 glayer.texts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach));
1859 }
1860 else if (ankind == 0x21) { // rectangle & circle
1861 switch (type) { // type = andt1[0x00]
1862 case 0:
1863 case 1:
1864 figure.type = Figure::Rectangle;
1865 break;
1866 case 2:
1867 case 3:
1868 figure.type = Figure::Circle;
1869 break;
1870 }
1871 figure.clientRect = r;
1872 figure.attach = (Attach)attach;
1873 figure.color = color;
1874
1875 glayer.figures.push_back(figure);
1876 }
1877 else if ((ankind == 0x22) && (sec_name != "sLine") && (sec_name != "sline")) { // line/arrow
1878 glayer.lines.push_back(Line());
1879 Line& line(glayer.lines.back());
1880 line.color = color;
1881 line.clientRect = r;
1882 line.attach = (Attach)attach;
1883 line.width = width;
1884 line.style = lineStyle;
1885 line.begin = begin;
1886 line.end = end;
1887 }
1888 else if (andt1sz == 40) { // bitmap
1889 if (type == 4) { // type = andt1[0x00]
1890 unsigned long filesize = andt2sz + 14;
1891 glayer.bitmaps.push_back(Bitmap());
1892 Bitmap& bitmap(glayer.bitmaps.back());
1893 bitmap.clientRect = r;
1894 bitmap.attach = (Attach)attach;
1895 bitmap.size = filesize;
1896 bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None);
1897 bitmap.data = new unsigned char[filesize];
1898 unsigned char* data = bitmap.data;
1899 //add Bitmap header
1900 memcpy(data, "BM", 2);
1901 data += 2;
1902 memcpy(data, &filesize, 4);
1903 data += 4;
1904 unsigned int d = 0;
1905 memcpy(data, &d, 4);
1906 data += 4;
1907 d = 0x36;
1908 memcpy(data, &d, 4);
1909 data += 4;
1910 memcpy(data, andt2.c_str(), andt2sz);
1911 } else if (type == 6) {
1912 // TODO check if 0x5E is right (obtained from anhdsz-0x46+93-andt1sz = 111-70+93-40 = 94)
1913 string gname = andt2.substr(0x5E).c_str();
1914 glayer.bitmaps.push_back(Bitmap(gname));
1915 Bitmap& bitmap(glayer.bitmaps.back());
1916 bitmap.clientRect = r;
1917 bitmap.attach = (Attach)attach;
1918 bitmap.size = 0;
1919 bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None);
1920 }
1921 }
1922
1923 }
1924 return;
1925 }
1926
getCurveProperties(const string & cvehd,unsigned int cvehdsz,const string & cvedt,unsigned int cvedtsz)1927 void OriginAnyParser::getCurveProperties(const string& cvehd, unsigned int cvehdsz, const string& cvedt, unsigned int cvedtsz) {
1928 istringstream stmp;
1929
1930 if (ispread != -1) { // spreadsheet: curves are columns
1931
1932 // TODO: check that spreadsheet columns are stored in proper order
1933 // vector<SpreadColumn> header;
1934 unsigned char c = cvehd[0x11];
1935 string name = cvehd.substr(0x12).c_str();
1936 unsigned short width = 0;
1937 if (cvehdsz > 0x4B) {
1938 stmp.str(cvehd.substr(0x4A));
1939 GET_SHORT(stmp, width)
1940 }
1941 int col_index = findColumnByName((int)ispread, name);
1942 if (col_index != -1) {
1943 if (spreadSheets[ispread].columns[col_index].name != name)
1944 spreadSheets[ispread].columns[col_index].name = name;
1945
1946 SpreadColumn::ColumnType type;
1947 switch(c){
1948 case 3:
1949 type = SpreadColumn::X;
1950 break;
1951 case 0:
1952 type = SpreadColumn::Y;
1953 break;
1954 case 5:
1955 type = SpreadColumn::Z;
1956 break;
1957 case 6:
1958 type = SpreadColumn::XErr;
1959 break;
1960 case 2:
1961 type = SpreadColumn::YErr;
1962 break;
1963 case 4:
1964 type = SpreadColumn::Label;
1965 break;
1966 default:
1967 type = SpreadColumn::NONE;
1968 break;
1969 }
1970 spreadSheets[ispread].columns[col_index].type = type;
1971
1972 width /= 0xA;
1973 if(width == 0) width = 8;
1974 spreadSheets[ispread].columns[col_index].width = width;
1975 unsigned char c1 = cvehd[0x1E];
1976 unsigned char c2 = cvehd[0x1F];
1977 switch (c1) {
1978 case 0x00: // Numeric - Dec1000
1979 case 0x09: // Text&Numeric - Dec1000
1980 case 0x10: // Numeric - Scientific
1981 case 0x19: // Text&Numeric - Scientific
1982 case 0x20: // Numeric - Engineering
1983 case 0x29: // Text&Numeric - Engineering
1984 case 0x30: // Numeric - Dec1,000
1985 case 0x39: // Text&Numeric - Dec1,000
1986 spreadSheets[ispread].columns[col_index].valueType = (c1%0x10 == 0x9) ? TextNumeric : Numeric;
1987 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c1 / 0x10;
1988 if (c2 >= 0x80) {
1989 spreadSheets[ispread].columns[col_index].significantDigits = c2 - 0x80;
1990 spreadSheets[ispread].columns[col_index].numericDisplayType = SignificantDigits;
1991 } else if (c2 > 0) {
1992 spreadSheets[ispread].columns[col_index].decimalPlaces = c2 - 0x03;
1993 spreadSheets[ispread].columns[col_index].numericDisplayType = DecimalPlaces;
1994 }
1995 break;
1996 case 0x02: // Time
1997 spreadSheets[ispread].columns[col_index].valueType = Time;
1998 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2 - 0x80;
1999 break;
2000 case 0x03: // Date
2001 case 0x33:
2002 spreadSheets[ispread].columns[col_index].valueType = Date;
2003 spreadSheets[ispread].columns[col_index].valueTypeSpecification= c2 - 0x80;
2004 break;
2005 case 0x31: // Text
2006 spreadSheets[ispread].columns[col_index].valueType = Text;
2007 break;
2008 case 0x4: // Month
2009 case 0x34:
2010 spreadSheets[ispread].columns[col_index].valueType = Month;
2011 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2;
2012 break;
2013 case 0x5: // Day
2014 case 0x35:
2015 spreadSheets[ispread].columns[col_index].valueType = Day;
2016 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2;
2017 break;
2018 default: // Text
2019 spreadSheets[ispread].columns[col_index].valueType = Text;
2020 break;
2021 }
2022 if (cvedtsz > 0) {
2023 spreadSheets[ispread].columns[col_index].comment = cvedt.c_str();
2024 }
2025 // TODO: check that spreadsheet columns are stored in proper order
2026 // header.push_back(spreadSheets[ispread].columns[col_index]);
2027 }
2028 // TODO: check that spreadsheet columns are stored in proper order
2029 // for (unsigned int i = 0; i < header.size(); i++)
2030 // spreadSheets[spread].columns[i] = header[i];
2031
2032 } else if (imatrix != -1) {
2033
2034 MatrixSheet sheet = matrixes[imatrix].sheets[ilayer];
2035 unsigned char c1 = cvehd[0x1E];
2036 unsigned char c2 = cvehd[0x1F];
2037
2038 sheet.valueTypeSpecification = c1/0x10;
2039 if (c2 >= 0x80) {
2040 sheet.significantDigits = c2-0x80;
2041 sheet.numericDisplayType = SignificantDigits;
2042 } else if (c2 > 0) {
2043 sheet.decimalPlaces = c2-0x03;
2044 sheet.numericDisplayType = DecimalPlaces;
2045 }
2046
2047 matrixes[imatrix].sheets[ilayer] = sheet;
2048
2049 } else if (iexcel != -1) {
2050
2051 unsigned char c = cvehd[0x11];
2052 string name = cvehd.substr(0x12).c_str();
2053 unsigned short width = 0;
2054 stmp.str(cvehd.substr(0x4A));
2055 GET_SHORT(stmp, width)
2056 unsigned short dataID = 0;
2057 stmp.str(cvehd.substr(0x04));
2058 GET_SHORT(stmp, dataID)
2059
2060 unsigned int isheet = datasets[dataID-1].sheet;
2061 vector<Origin::SpreadColumn>::difference_type col_index = findExcelColumnByName(iexcel, isheet, name);
2062 if (col_index != -1) {
2063 SpreadColumn::ColumnType type;
2064 switch(c){
2065 case 3:
2066 type = SpreadColumn::X;
2067 break;
2068 case 0:
2069 type = SpreadColumn::Y;
2070 break;
2071 case 5:
2072 type = SpreadColumn::Z;
2073 break;
2074 case 6:
2075 type = SpreadColumn::XErr;
2076 break;
2077 case 2:
2078 type = SpreadColumn::YErr;
2079 break;
2080 case 4:
2081 type = SpreadColumn::Label;
2082 break;
2083 default:
2084 type = SpreadColumn::NONE;
2085 break;
2086 }
2087 excels[iexcel].sheets[isheet].columns[col_index].type = type;
2088 width /= 0xA;
2089 if (width == 0) width = 8;
2090 excels[iexcel].sheets[isheet].columns[col_index].width = width;
2091
2092 unsigned char c1 = cvehd[0x1E];
2093 unsigned char c2 = cvehd[0x1F];
2094 switch (c1) {
2095 case 0x00: // Numeric - Dec1000
2096 case 0x09: // Text&Numeric - Dec1000
2097 case 0x10: // Numeric - Scientific
2098 case 0x19: // Text&Numeric - Scientific
2099 case 0x20: // Numeric - Engineering
2100 case 0x29: // Text&Numeric - Engineering
2101 case 0x30: // Numeric - Dec1,000
2102 case 0x39: // Text&Numeric - Dec1,000
2103 excels[iexcel].sheets[isheet].columns[col_index].valueType = (c1%0x10 == 0x9) ? TextNumeric : Numeric;
2104 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c1 / 0x10;
2105 if (c2 >= 0x80) {
2106 excels[iexcel].sheets[isheet].columns[col_index].significantDigits = c2 - 0x80;
2107 excels[iexcel].sheets[isheet].columns[col_index].numericDisplayType = SignificantDigits;
2108 } else if (c2 > 0) {
2109 excels[iexcel].sheets[isheet].columns[col_index].decimalPlaces = c2 - 0x03;
2110 excels[iexcel].sheets[isheet].columns[col_index].numericDisplayType = DecimalPlaces;
2111 }
2112 break;
2113 case 0x02: // Time
2114 excels[iexcel].sheets[isheet].columns[col_index].valueType = Time;
2115 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2 - 0x80;
2116 break;
2117 case 0x03: // Date
2118 excels[iexcel].sheets[isheet].columns[col_index].valueType = Date;
2119 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2 - 0x80;
2120 break;
2121 case 0x31: // Text
2122 excels[iexcel].sheets[isheet].columns[col_index].valueType = Text;
2123 break;
2124 case 0x04: // Month
2125 case 0x34:
2126 excels[iexcel].sheets[isheet].columns[col_index].valueType = Month;
2127 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2;
2128 break;
2129 case 0x05: // Day
2130 case 0x35:
2131 excels[iexcel].sheets[isheet].columns[col_index].valueType = Day;
2132 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2;
2133 break;
2134 default: // Text
2135 excels[iexcel].sheets[isheet].columns[col_index].valueType = Text;
2136 break;
2137 }
2138 if (cvedtsz > 0) {
2139 excels[iexcel].sheets[isheet].columns[col_index].comment = cvedt.c_str();
2140 }
2141 }
2142
2143 } else {
2144
2145 GraphLayer& glayer = graphs[igraph].layers[ilayer];
2146 glayer.curves.push_back(GraphCurve());
2147 GraphCurve& curve(glayer.curves.back());
2148
2149 unsigned char h = cvehd[0x26];
2150 curve.hidden = (h == 33);
2151 curve.type = cvehd[0x4C];
2152 if (curve.type == GraphCurve::XYZContour || curve.type == GraphCurve::Contour)
2153 glayer.isXYY3D = false;
2154
2155 unsigned short w;
2156 stmp.str(cvehd.substr(0x04));
2157 GET_SHORT(stmp, w)
2158 pair<string, string> column = findDataByIndex(w-1);
2159 short nColY = w;
2160 if (column.first.size() > 0) {
2161 curve.dataName = column.first;
2162 if (glayer.is3D() || (curve.type == GraphCurve::XYZContour)) {
2163 curve.zColumnName = column.second;
2164 } else {
2165 curve.yColumnName = column.second;
2166 }
2167 }
2168
2169 stmp.str(cvehd.substr(0x23));
2170 GET_SHORT(stmp, w)
2171 column = findDataByIndex(w-1);
2172 if (column.first.size() > 0) {
2173 curve.xDataName = (curve.dataName != column.first) ? column.first : string();
2174 if (glayer.is3D() || (curve.type == GraphCurve::XYZContour)) {
2175 curve.yColumnName = column.second;
2176 } else if (glayer.isXYY3D){
2177 curve.xColumnName = column.second;
2178 } else {
2179 curve.xColumnName = column.second;
2180 }
2181 }
2182
2183 if (cvehdsz > 0x4E) {
2184 stmp.str(cvehd.substr(0x4D));
2185 GET_SHORT(stmp, w)
2186 column = findDataByIndex(w-1);
2187 if (column.first.size() > 0 && (glayer.is3D() || (curve.type == GraphCurve::XYZContour))) {
2188 curve.xColumnName = column.second;
2189 if (curve.dataName != column.first) {
2190 // graph X and Y from different tables
2191 }
2192 }
2193 }
2194
2195 if (glayer.is3D() || glayer.isXYY3D) graphs[igraph].is3D = true;
2196
2197 curve.lineConnect = cvehd[0x11];
2198 curve.lineStyle = cvehd[0x12];
2199 curve.boxWidth = cvehd[0x14];
2200
2201 stmp.str(cvehd.substr(0x15));
2202 GET_SHORT(stmp, w)
2203 curve.lineWidth = (double)w/500.0;
2204
2205 curve.symbolShape = cvehd[0x17];
2206 curve.symbolInterior = cvehd[0x18];
2207
2208 stmp.str(cvehd.substr(0x19));
2209 GET_SHORT(stmp, w)
2210 curve.symbolSize = (double)w/500.0;
2211
2212 h = cvehd[0x1C];
2213 curve.fillArea = (h==2);
2214 curve.fillAreaType = cvehd[0x1E];
2215
2216 //text
2217 if (curve.type == GraphCurve::TextPlot) {
2218 stmp.str(cvehd.substr(0x13));
2219 GET_SHORT(stmp, curve.text.rotation)
2220 curve.text.rotation /= 10;
2221 GET_SHORT(stmp, curve.text.fontSize)
2222
2223 h = cvehd[0x19];
2224 switch (h) {
2225 case 26:
2226 curve.text.justify = TextProperties::Center;
2227 break;
2228 case 2:
2229 curve.text.justify = TextProperties::Right;
2230 break;
2231 default:
2232 curve.text.justify = TextProperties::Left;
2233 break;
2234 }
2235
2236 h = cvehd[0x20];
2237 curve.text.fontUnderline = ((h & 0x1) != 0);
2238 curve.text.fontItalic = ((h & 0x2) != 0);
2239 curve.text.fontBold = ((h & 0x8) != 0);
2240 curve.text.whiteOut = ((h & 0x20) != 0);
2241
2242 char offset = cvehd[0x37];
2243 curve.text.xOffset = offset * 5;
2244 offset = cvehd[0x38];
2245 curve.text.yOffset = offset * 5;
2246 }
2247
2248 //vector
2249 if (curve.type == GraphCurve::FlowVector || curve.type == GraphCurve::Vector) {
2250 stmp.str(cvehd.substr(0x56));
2251 GET_FLOAT(stmp, curve.vector.multiplier)
2252
2253 h = cvehd[0x5E];
2254 column = findDataByIndex(nColY - 1 + h - 0x64);
2255 if (column.first.size() > 0)
2256 curve.vector.endXColumnName = column.second;
2257
2258 h = cvehd[0x62];
2259 column = findDataByIndex(nColY - 1 + h - 0x64);
2260 if (column.first.size() > 0)
2261 curve.vector.endYColumnName = column.second;
2262
2263 h = cvehd[0x18];
2264 if (h >= 0x64) {
2265 column = findDataByIndex(nColY - 1 + h - 0x64);
2266 if (column.first.size() > 0)
2267 curve.vector.angleColumnName = column.second;
2268 } else if (h <= 0x08)
2269 curve.vector.constAngle = 45*h;
2270
2271 h = cvehd[0x19];
2272 if (h >= 0x64){
2273 column = findDataByIndex(nColY - 1 + h - 0x64);
2274 if (column.first.size() > 0)
2275 curve.vector.magnitudeColumnName = column.second;
2276 } else
2277 curve.vector.constMagnitude = (int)curve.symbolSize;
2278
2279 stmp.str(cvehd.substr(0x66));
2280 GET_SHORT(stmp, curve.vector.arrowLength)
2281 curve.vector.arrowAngle = cvehd[0x68];
2282
2283 h = cvehd[0x69];
2284 curve.vector.arrowClosed = !(h & 0x1);
2285
2286 stmp.str(cvehd.substr(0x70));
2287 GET_SHORT(stmp, w)
2288 curve.vector.width = (double)w/500.0;
2289
2290 h = cvehd[0x142];
2291 switch (h) {
2292 case 2:
2293 curve.vector.position = VectorProperties::Midpoint;
2294 break;
2295 case 4:
2296 curve.vector.position = VectorProperties::Head;
2297 break;
2298 default:
2299 curve.vector.position = VectorProperties::Tail;
2300 break;
2301 }
2302 }
2303 //pie
2304 if (curve.type == GraphCurve::Pie) {
2305 // code from Origin410/500Parser
2306 h = cvehd[0x14];
2307 curve.pie.formatPercentages = ((h & 0x08) != 0);
2308 curve.pie.formatValues = !curve.pie.formatPercentages;
2309 curve.pie.positionAssociate = ((h & 0x80) != 0);
2310 curve.pie.formatCategories = ((h & 0x20) != 0);
2311
2312 h = cvehd[0x19];
2313 curve.pie.radius = 100 - h;
2314
2315 h = cvehd[0x1A];
2316 curve.pie.distance = h;
2317 curve.pie.formatAutomatic = true;
2318 curve.pie.viewAngle = 90;
2319 curve.pie.thickness = 33;
2320 curve.pie.rotation = 0;
2321 curve.pie.horizontalOffset = 0;
2322
2323 if (cvehdsz > 0xA9) { // code from Origin750Parser.cpp
2324
2325 h = cvehd[0x92];
2326 curve.pie.formatPercentages = ((h & 0x01) != 0);
2327 curve.pie.formatValues = ((h & 0x02) != 0);
2328 curve.pie.positionAssociate = ((h & 0x08) != 0);
2329 curve.pie.clockwiseRotation = ((h & 0x20) != 0);
2330 curve.pie.formatCategories = ((h & 0x80) != 0);
2331
2332 curve.pie.formatAutomatic = (cvehd[0x93] != 0);
2333 stmp.str(cvehd.substr(0x94));
2334 GET_SHORT(stmp, curve.pie.distance)
2335 curve.pie.viewAngle = cvehd[0x96];
2336 curve.pie.thickness = cvehd[0x98];
2337
2338 stmp.str(cvehd.substr(0x9A));
2339 GET_SHORT(stmp, curve.pie.rotation)
2340
2341 stmp.str(cvehd.substr(0x9E));
2342 GET_SHORT(stmp, curve.pie.displacement)
2343
2344 stmp.str(cvehd.substr(0xA0));
2345 GET_SHORT(stmp, curve.pie.radius)
2346 GET_SHORT(stmp, curve.pie.horizontalOffset)
2347
2348 stmp.str(cvehd.substr(0xA6));
2349 GET_INT(stmp, curve.pie.displacedSectionCount)
2350 }
2351 }
2352 //surface
2353 if (glayer.isXYY3D || curve.type == GraphCurve::Mesh3D) {
2354 curve.surface.type = cvehd[0x17];
2355 h = cvehd[0x1C];
2356 if ((h & 0x60) == 0x60)
2357 curve.surface.grids = SurfaceProperties::X;
2358 else if (h & 0x20)
2359 curve.surface.grids = SurfaceProperties::Y;
2360 else if (h & 0x40)
2361 curve.surface.grids = SurfaceProperties::None;
2362 else
2363 curve.surface.grids = SurfaceProperties::XY;
2364
2365 curve.surface.sideWallEnabled = ((h & 0x10) != 0);
2366 curve.surface.frontColor = getColor(cvehd.substr(0x1D,4));
2367
2368 h = cvehd[0x13];
2369 curve.surface.backColorEnabled = ((h & 0x08) != 0);
2370 curve.surface.surface.fill = ((h & 0x10) != 0);
2371 curve.surface.surface.contour = ((h & 0x40) != 0);
2372 curve.surface.topContour.fill = ((h & 0x02) != 0);
2373 curve.surface.topContour.contour = ((h & 0x04) != 0);
2374 curve.surface.bottomContour.fill = ((h & 0x80) != 0);
2375 curve.surface.bottomContour.contour = ((h & 0x01) != 0);
2376
2377 if (cvehdsz > 0x165) {
2378 stmp.str(cvehd.substr(0x14C));
2379 GET_SHORT(stmp, w)
2380 curve.surface.gridLineWidth = (double)w/500.0;
2381 curve.surface.gridColor = getColor(cvehd.substr(0x14E,4));
2382 curve.surface.backColor = getColor(cvehd.substr(0x15A,4));
2383 curve.surface.xSideWallColor = getColor(cvehd.substr(0x15E,4));
2384 curve.surface.ySideWallColor = getColor(cvehd.substr(0x162,4));
2385 }
2386 if (cvehdsz > 0xA9) {
2387 stmp.str(cvehd.substr(0x94));
2388 GET_SHORT(stmp, w)
2389 curve.surface.surface.lineWidth = (double)w/500.0;
2390 curve.surface.surface.lineColor = getColor(cvehd.substr(0x96,4));
2391
2392 stmp.str(cvehd.substr(0xB4));
2393 GET_SHORT(stmp, w)
2394 curve.surface.topContour.lineWidth = (double)w/500.0;
2395 curve.surface.topContour.lineColor = getColor(cvehd.substr(0xB6,4));
2396
2397 stmp.str(cvehd.substr(0xA4));
2398 GET_SHORT(stmp, w)
2399 curve.surface.bottomContour.lineWidth = (double)w/500.0;
2400 curve.surface.bottomContour.lineColor = getColor(cvehd.substr(0xA6,4));
2401 }
2402
2403 }
2404 if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) {
2405 if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) glayer.isXYY3D = false;
2406 ColorMap& colorMap = (curve.type == GraphCurve::Mesh3D ? curve.surface.colorMap : curve.colorMap);
2407 h = cvehd[0x13];
2408 colorMap.fillEnabled = ((h & 0x82) != 0);
2409
2410 if ((curve.type == GraphCurve::Contour) && (cvehdsz > 0x89)) {
2411 stmp.str(cvehd.substr(0x7A));
2412 GET_SHORT(stmp, curve.text.fontSize)
2413
2414 h = cvehd[0x83];
2415 curve.text.fontUnderline = ((h & 0x1) != 0);
2416 curve.text.fontItalic = ((h & 0x2) != 0);
2417 curve.text.fontBold = ((h & 0x8) != 0);
2418 curve.text.whiteOut = ((h & 0x20) != 0);
2419
2420 curve.text.color = getColor(cvehd.substr(0x86,4));
2421 }
2422 if (cvedtsz > 0x6C) {
2423 getColorMap(colorMap, cvedt, cvedtsz);
2424 } else {
2425 colorMap = glayer.colorMap;
2426 }
2427 }
2428
2429 if (fileVersion >= 850) {
2430 curve.lineTransparency = cvehd[0x9C];
2431 h = cvehd[0x9D];
2432 curve.fillAreaWithLineTransparency = !h;
2433 curve.fillAreaTransparency = cvehd[0x11E];
2434 } else {
2435 // use sensible default values
2436 curve.fillAreaWithLineTransparency = false;
2437 curve.fillAreaTransparency = 255;
2438 }
2439
2440 if (cvehdsz > 0x143) {
2441 curve.fillAreaColor = getColor(cvehd.substr(0xC2,4));
2442 stmp.str(cvehd.substr(0xC6));
2443 GET_SHORT(stmp, w)
2444 curve.fillAreaPatternWidth = (double)w/500.0;
2445
2446 curve.fillAreaPatternColor = getColor(cvehd.substr(0xCA,4));
2447 curve.fillAreaPattern = cvehd[0xCE];
2448 curve.fillAreaPatternBorderStyle = cvehd[0xCF];
2449 stmp.str(cvehd.substr(0xD0));
2450 GET_SHORT(stmp, w)
2451 curve.fillAreaPatternBorderWidth = (double)w/500.0;
2452 curve.fillAreaPatternBorderColor = getColor(cvehd.substr(0xD2,4));
2453
2454 curve.fillAreaTransparency = cvehd[0x11E];
2455
2456 curve.lineColor = getColor(cvehd.substr(0x16A,4));
2457
2458 if (curve.type != GraphCurve::Contour) curve.text.color = curve.lineColor;
2459
2460 curve.symbolFillColor = getColor(cvehd.substr(0x12E,4));
2461 curve.symbolColor = getColor(cvehd.substr(0x132,4));
2462 curve.vector.color = curve.symbolColor;
2463
2464 h = cvehd[0x136];
2465 curve.symbolThickness = (h == 255 ? 1 : h);
2466 curve.pointOffset = cvehd[0x137];
2467 h = cvehd[0x138];
2468 curve.symbolFillTransparency = cvehd[0x139];
2469
2470 h = cvehd[0x143];
2471 curve.connectSymbols = ((h & 0x8) != 0);
2472 }
2473 }
2474 }
2475
getAxisBreakProperties(const string & abdata,unsigned int abdatasz)2476 void OriginAnyParser::getAxisBreakProperties(const string& abdata, unsigned int abdatasz) {
2477 istringstream stmp;
2478 (void) abdatasz;
2479
2480 if (ispread != -1) { // spreadsheet
2481
2482 } else if (imatrix != -1) { // matrix
2483
2484
2485 } else if (iexcel != -1) { // excel
2486
2487
2488 } else { // graph
2489
2490 GraphLayer& glayer = graphs[igraph].layers[ilayer];
2491 unsigned char h = abdata[0x02];
2492 if (h == 2) {
2493 glayer.xAxisBreak.minorTicksBefore = glayer.xAxis.minorTicks;
2494 glayer.xAxisBreak.scaleIncrementBefore = glayer.xAxis.step;
2495 glayer.xAxisBreak.show = true;
2496 stmp.str(abdata.substr(0x0B));
2497 GET_DOUBLE(stmp, glayer.xAxisBreak.from)
2498 GET_DOUBLE(stmp, glayer.xAxisBreak.to)
2499 GET_DOUBLE(stmp, glayer.xAxisBreak.scaleIncrementAfter)
2500 GET_DOUBLE(stmp, glayer.xAxisBreak.position)
2501 h = abdata[0x2B];
2502 glayer.xAxisBreak.log10 = (h == 1);
2503 glayer.xAxisBreak.minorTicksAfter = abdata[0x2C];
2504 } else if (h == 4) {
2505 glayer.yAxisBreak.minorTicksBefore = glayer.yAxis.minorTicks;
2506 glayer.yAxisBreak.scaleIncrementBefore = glayer.yAxis.step;
2507 glayer.yAxisBreak.show = true;
2508 stmp.str(abdata.substr(0x0B));
2509 GET_DOUBLE(stmp, glayer.yAxisBreak.from)
2510 GET_DOUBLE(stmp, glayer.yAxisBreak.to)
2511 GET_DOUBLE(stmp, glayer.yAxisBreak.scaleIncrementAfter)
2512 GET_DOUBLE(stmp, glayer.yAxisBreak.position)
2513 h = abdata[0x2B];
2514 glayer.yAxisBreak.log10 = (h == 1);
2515 glayer.yAxisBreak.minorTicksAfter = abdata[0x2C];
2516 }
2517
2518 }
2519 }
2520
getAxisParameterProperties(const string & apdata,unsigned int apdatasz,int naxis)2521 void OriginAnyParser::getAxisParameterProperties(const string& apdata, unsigned int apdatasz, int naxis) {
2522 istringstream stmp;
2523 static int iaxispar = 0;
2524
2525 if (igraph != -1) {
2526 unsigned char h = 0;
2527 unsigned short w = 0;
2528
2529 GraphLayer& glayer = graphs[igraph].layers[ilayer];
2530 GraphAxis axis = glayer.xAxis;
2531 if (naxis == 1) {
2532 axis = glayer.xAxis;
2533 } else if (naxis == 2) {
2534 axis = glayer.yAxis;
2535 } else if (naxis == 3) {
2536 axis = glayer.zAxis;
2537 }
2538 if (iaxispar == 0) { // minor Grid
2539 h = apdata[0x26];
2540 axis.minorGrid.hidden = (h==0);
2541 axis.minorGrid.color = apdata[0x0F];
2542 axis.minorGrid.style = apdata[0x12];
2543 stmp.str(apdata.substr(0x15));
2544 GET_SHORT(stmp, w)
2545 axis.minorGrid.width = (double)w/500.0;
2546 } else if (iaxispar == 1) { // major Grid
2547 h = apdata[0x26];
2548 axis.majorGrid.hidden = (h==0);
2549 axis.majorGrid.color = apdata[0x0F];
2550 axis.majorGrid.style = apdata[0x12];
2551 stmp.str(apdata.substr(0x15));
2552 GET_SHORT(stmp, w)
2553 axis.majorGrid.width = (double)w/500.0;
2554 } else if (iaxispar == 2) { // tickaxis 0
2555 h = apdata[0x26];
2556 axis.tickAxis[0].showMajorLabels = ((h & 0x40) != 0);
2557 axis.tickAxis[0].color = apdata[0x0F];
2558 stmp.str(apdata.substr(0x13));
2559 GET_SHORT(stmp, w)
2560 axis.tickAxis[0].rotation = w/10;
2561 GET_SHORT(stmp, w)
2562 axis.tickAxis[0].fontSize = w;
2563 h = apdata[0x1A];
2564 axis.tickAxis[0].fontBold = ((h & 0x08) != 0);
2565 stmp.str(apdata.substr(0x23));
2566 GET_SHORT(stmp, w)
2567 h = apdata[0x25];
2568 unsigned char h1 = apdata[0x26];
2569 axis.tickAxis[0].valueType = (ValueType)(h & 0x0F);
2570 pair<string, string> column;
2571 switch (axis.tickAxis[0].valueType) {
2572 case Numeric:
2573 /*switch ((h>>4)) {
2574 case 0x9:
2575 axis.tickAxis[0].valueTypeSpecification=1;
2576 break;
2577 case 0xA:
2578 axis.tickAxis[0].valueTypeSpecification=2;
2579 break;
2580 case 0xB:
2581 axis.tickAxis[0].valueTypeSpecification=3;
2582 break;
2583 default:
2584 axis.tickAxis[0].valueTypeSpecification=0;
2585 }*/
2586 if ((h>>4) > 7) {
2587 axis.tickAxis[0].valueTypeSpecification = (h>>4) - 8;
2588 axis.tickAxis[0].decimalPlaces = h1 - 0x40;
2589 } else {
2590 axis.tickAxis[0].valueTypeSpecification = (h>>4);
2591 axis.tickAxis[0].decimalPlaces = -1;
2592 }
2593 break;
2594 case Time:
2595 case Date:
2596 case Month:
2597 case Day:
2598 case ColumnHeading:
2599 axis.tickAxis[0].valueTypeSpecification = h1 - 0x40;
2600 break;
2601 case Text:
2602 case TickIndexedDataset:
2603 case Categorical:
2604 column = findDataByIndex(w-1);
2605 if (column.first.size() > 0) {
2606 axis.tickAxis[0].dataName = column.first;
2607 axis.tickAxis[0].columnName = column.second;
2608 }
2609 break;
2610 case TextNumeric: // Numeric Decimal 1.000
2611 axis.tickAxis[0].valueType = Numeric;
2612 axis.tickAxis[0].valueTypeSpecification = 0;
2613 break;
2614 }
2615 } else if (iaxispar == 3) { // formataxis 0
2616 h = apdata[0x26];
2617 axis.formatAxis[0].hidden = (h == 0);
2618 axis.formatAxis[0].color = apdata[0x0F];
2619 if (apdatasz > 0x4B) {
2620 stmp.str(apdata.substr(0x4A));
2621 GET_SHORT(stmp, w)
2622 axis.formatAxis[0].majorTickLength = (double)w/10.0;
2623 }
2624 stmp.str(apdata.substr(0x15));
2625 GET_SHORT(stmp, w)
2626 axis.formatAxis[0].thickness = (double)w/500.0;
2627 h = apdata[0x25];
2628 axis.formatAxis[0].minorTicksType = (h>>6);
2629 axis.formatAxis[0].majorTicksType = ((h>>4) & 3);
2630 axis.formatAxis[0].axisPosition = (h & 0x0F);
2631 short w1 = 0;
2632 switch (axis.formatAxis[0].axisPosition) { // TODO: check if correct
2633 case 1:
2634 stmp.str(apdata.substr(0x37));
2635 GET_SHORT(stmp, w1)
2636 axis.formatAxis[0].axisPositionValue = (double)w1;
2637 break;
2638 case 2:
2639 stmp.str(apdata.substr(0x2F));
2640 GET_DOUBLE(stmp, axis.formatAxis[0].axisPositionValue)
2641 break;
2642 }
2643 } else if (iaxispar == 4) { // tickaxis 1
2644 h = apdata[0x26];
2645 axis.tickAxis[1].showMajorLabels = ((h & 0x40) != 0);
2646 axis.tickAxis[1].color = apdata[0x0F];
2647 stmp.str(apdata.substr(0x13));
2648 GET_SHORT(stmp, w)
2649 axis.tickAxis[1].rotation = w/10;
2650 GET_SHORT(stmp, w)
2651 axis.tickAxis[1].fontSize = w;
2652 h = apdata[0x1A];
2653 axis.tickAxis[1].fontBold = ((h & 0x08) != 0);
2654 stmp.str(apdata.substr(0x23));
2655 GET_SHORT(stmp, w)
2656 h = apdata[0x25];
2657 unsigned char h1 = apdata[0x26];
2658 axis.tickAxis[1].valueType = (ValueType)(h & 0x0F);
2659 pair<string, string> column;
2660 switch (axis.tickAxis[1].valueType) {
2661 case Numeric:
2662 /*switch ((h>>4)) {
2663 case 0x9:
2664 axis.tickAxis[1].valueTypeSpecification=1;
2665 break;
2666 case 0xA:
2667 axis.tickAxis[1].valueTypeSpecification=2;
2668 break;
2669 case 0xB:
2670 axis.tickAxis[1].valueTypeSpecification=3;
2671 break;
2672 default:
2673 axis.tickAxis[1].valueTypeSpecification=0;
2674 }*/
2675 if ((h>>4) > 7) {
2676 axis.tickAxis[1].valueTypeSpecification = (h>>4) - 8;
2677 axis.tickAxis[1].decimalPlaces = h1 - 0x40;
2678 } else {
2679 axis.tickAxis[1].valueTypeSpecification = (h>>4);
2680 axis.tickAxis[1].decimalPlaces = -1;
2681 }
2682 break;
2683 case Time:
2684 case Date:
2685 case Month:
2686 case Day:
2687 case ColumnHeading:
2688 axis.tickAxis[1].valueTypeSpecification = h1 - 0x40;
2689 break;
2690 case Text:
2691 case TickIndexedDataset:
2692 case Categorical:
2693 column = findDataByIndex(w-1);
2694 if (column.first.size() > 0) {
2695 axis.tickAxis[1].dataName = column.first;
2696 axis.tickAxis[1].columnName = column.second;
2697 }
2698 break;
2699 case TextNumeric: // Numeric Decimal 1.000
2700 axis.tickAxis[1].valueType = Numeric;
2701 axis.tickAxis[1].valueTypeSpecification = 0;
2702 break;
2703 }
2704 } else if (iaxispar == 5) { // formataxis 1
2705 h = apdata[0x26];
2706 axis.formatAxis[1].hidden = (h == 0);
2707 axis.formatAxis[1].color = apdata[0x0F];
2708 if (apdatasz > 0x4B) {
2709 stmp.str(apdata.substr(0x4A));
2710 GET_SHORT(stmp, w)
2711 axis.formatAxis[1].majorTickLength = (double)w/10.0;
2712 }
2713 stmp.str(apdata.substr(0x15));
2714 GET_SHORT(stmp, w)
2715 axis.formatAxis[1].thickness = (double)w/500.0;
2716 h = apdata[0x25];
2717 axis.formatAxis[1].minorTicksType = (h>>6);
2718 axis.formatAxis[1].majorTicksType = ((h>>4) & 3);
2719 axis.formatAxis[1].axisPosition = (h & 0x0F);
2720 short w1 = 0;
2721 switch (axis.formatAxis[1].axisPosition) { // TODO: check if correct
2722 case 1:
2723 stmp.str(apdata.substr(0x37));
2724 GET_SHORT(stmp, w1)
2725 axis.formatAxis[1].axisPositionValue = (double)w1;
2726 break;
2727 case 2:
2728 stmp.str(apdata.substr(0x2F));
2729 GET_DOUBLE(stmp, axis.formatAxis[1].axisPositionValue)
2730 break;
2731 }
2732 }
2733
2734 if (naxis == 1) {
2735 glayer.xAxis = axis;
2736 } else if (naxis == 2) {
2737 glayer.yAxis = axis;
2738 } else if (naxis == 3) {
2739 glayer.zAxis = axis;
2740 }
2741
2742 iaxispar++;
2743 iaxispar %= 6;
2744
2745 }
2746 }
2747
getNoteProperties(const string & nwehd,unsigned int nwehdsz,const string & nwelb,unsigned int nwelbsz,const string & nwect,unsigned int nwectsz)2748 void OriginAnyParser::getNoteProperties(const string& nwehd, unsigned int nwehdsz, const string& nwelb, unsigned int nwelbsz, const string& nwect, unsigned int nwectsz) {
2749 LOG_PRINT(logfile, "OriginAnyParser::getNoteProperties()");
2750 istringstream stmp;
2751 (void) nwehdsz; (void) nwelbsz; (void) nwectsz;
2752
2753 // note window position and size
2754 Rect rect;
2755 unsigned int coord;
2756 stmp.str(nwehd);
2757 GET_INT(stmp, coord)
2758 rect.left = static_cast<short>(coord);
2759 GET_INT(stmp, coord)
2760 rect.top = static_cast<short>(coord);
2761 GET_INT(stmp, coord)
2762 rect.right = static_cast<short>(coord);
2763 GET_INT(stmp, coord)
2764 rect.bottom = static_cast<short>(coord);
2765
2766 string name = nwelb.c_str();
2767
2768 // ResultsLog note window has left, top, right, bottom all zero.
2769 // All other parameters are also zero, except "name" and "text".
2770 if (!rect.bottom || !rect.right) {
2771 resultsLog = nwect;
2772 return;
2773 }
2774 unsigned char state = nwehd[0x18];
2775
2776 // files from version < 6.0 have nwehdsz < 1D
2777 if (nwehdsz < 0x2F) return;
2778
2779 double creationDate, modificationDate;
2780 stmp.str(nwehd.substr(0x20));
2781 GET_DOUBLE(stmp, creationDate)
2782 GET_DOUBLE(stmp, modificationDate)
2783
2784 if (nwehdsz < 0x38) return;
2785 unsigned char c = nwehd[0x38];
2786
2787 if (nwehdsz < 0x3F) return;
2788 unsigned int labellen = 0;
2789 stmp.str(nwehd.substr(0x3C));
2790 GET_INT(stmp, labellen)
2791
2792 notes.push_back(Note(name));
2793 LOG_PRINT(logfile,"notes: %d\n", (int)notes.size());
2794 notes.back().objectID = objectIndex;
2795 ++objectIndex;
2796
2797 notes.back().frameRect = rect;
2798 notes.back().creationDate = doubleToPosixTime(creationDate);
2799 notes.back().modificationDate = doubleToPosixTime(modificationDate);
2800
2801 if (c == 0x01)
2802 notes.back().title = Window::Label;
2803 else if (c == 0x02)
2804 notes.back().title = Window::Name;
2805 else
2806 notes.back().title = Window::Both;
2807
2808 if (state == 0x07)
2809 notes.back().state = Window::Minimized;
2810 else if (state == 0x0b)
2811 notes.back().state = Window::Maximized;
2812
2813 notes.back().hidden = ((state & 0x40) != 0);
2814
2815 if (labellen > 1) {
2816 notes.back().label = nwect.substr(0,labellen);
2817 notes.back().text = nwect.substr(labellen).c_str();
2818 } else {
2819 notes.back().text = nwect.c_str();
2820 }
2821 }
2822
getColorMap(ColorMap & cmap,const string & cmapdata,unsigned int cmapdatasz)2823 void OriginAnyParser::getColorMap(ColorMap& cmap, const string& cmapdata, unsigned int cmapdatasz) {
2824 istringstream stmp;
2825 unsigned int cmoffset = 0;
2826 // color maps for matrix annotations have a different offset than graph curve's colormaps
2827 if (imatrix != -1) {
2828 cmoffset = 0x14;
2829 } else if (igraph != -1) {
2830 cmoffset = 0x6C;
2831 } else {
2832 return;
2833 }
2834
2835 stmp.str(cmapdata.substr(cmoffset));
2836 unsigned int colorMapSize = 0;
2837 GET_INT(stmp, colorMapSize)
2838
2839 // check we have enough data to fill the map
2840 unsigned int minDataSize = cmoffset + 0x114 + (colorMapSize+2)*0x38;
2841 if (minDataSize > cmapdatasz) {
2842 LOG_PRINT(logfile, "WARNING: Too few data while getting ColorMap. Needed: at least %d bytes. Have: %d bytes.\n", minDataSize, cmapdatasz)
2843 return;
2844 }
2845
2846 unsigned int lvl_offset = 0;
2847 for (unsigned int i = 0; i < colorMapSize + 3; ++i) {
2848 lvl_offset = cmoffset + 0x114 + i*0x38;
2849 ColorMapLevel level;
2850
2851 level.fillPattern = cmapdata[lvl_offset];
2852 level.fillPatternColor = getColor(cmapdata.substr(lvl_offset+0x04, 4));
2853
2854 stmp.str(cmapdata.substr(lvl_offset+0x08));
2855 unsigned short w;
2856 GET_SHORT(stmp, w)
2857 level.fillPatternLineWidth = (double)w/500.0;
2858
2859 level.lineStyle = cmapdata[lvl_offset+0x10];
2860
2861 stmp.str(cmapdata.substr(lvl_offset+0x12));
2862 GET_SHORT(stmp, w)
2863 level.lineWidth = (double)w/500.0;
2864
2865 level.lineColor = getColor(cmapdata.substr(lvl_offset+0x14, 4));
2866
2867 unsigned char h = cmapdata[lvl_offset+0x1A];
2868 level.labelVisible = (h & 0x1);
2869 level.lineVisible = !(h & 0x2);
2870
2871 level.fillColor = getColor(cmapdata.substr(lvl_offset+0x28, 4));
2872
2873 double value = 0.0;
2874 stmp.str(cmapdata.substr(lvl_offset+0x30));
2875 GET_DOUBLE(stmp, value)
2876
2877 cmap.levels.push_back(make_pair(value, level));
2878 }
2879
2880 }
2881
getZcolorsMap(ColorMap & colorMap,const string & cmapdata,unsigned int cmapdatasz)2882 void OriginAnyParser::getZcolorsMap(ColorMap& colorMap, const string& cmapdata, unsigned int cmapdatasz) {
2883 istringstream stmp;
2884 (void) cmapdatasz;
2885
2886 Color lowColor;//color below
2887 lowColor.type = Origin::Color::Custom;
2888 lowColor.custom[0] = cmapdata[0x0E];
2889 lowColor.custom[1] = cmapdata[0x0F];
2890 lowColor.custom[2] = cmapdata[0x10];
2891 // skip an unsigned char at 0x11
2892
2893 Color highColor;//color above
2894 highColor.type = Origin::Color::Custom;
2895 highColor.custom[0] = cmapdata[0x12];
2896 highColor.custom[1] = cmapdata[0x13];
2897 highColor.custom[2] = cmapdata[0x14];
2898 // skip an unsigned char at 0x15
2899
2900 unsigned short colorMapSize;
2901 stmp.str(cmapdata.substr(0x16));
2902 GET_SHORT(stmp, colorMapSize)
2903 // skip a short at 0x18-0x19
2904
2905 for (int i = 0; i < 4; ++i) {//low, high, middle and missing data colors
2906 Color color; (void) color;
2907 color.type = Origin::Color::Custom;
2908 color.custom[0] = cmapdata[0x1A+4*i];
2909 color.custom[1] = cmapdata[0x1B+4*i];
2910 color.custom[2] = cmapdata[0x1C+4*i];
2911 }
2912
2913 double zmin, zmax, zmissing;
2914 stmp.str(cmapdata.substr(0x2A));
2915 GET_DOUBLE(stmp, zmin);
2916 GET_DOUBLE(stmp, zmax);
2917 GET_DOUBLE(stmp, zmissing);
2918
2919 short val;
2920 for (int i = 0; i < 2; ++i) {
2921 Color color; (void) color;
2922 color.type = Origin::Color::Custom;
2923 color.custom[0] = cmapdata[0x66+10*i];
2924 color.custom[1] = cmapdata[0x67+10*i];
2925 color.custom[2] = cmapdata[0x68+10*i];
2926 // skip an unsigned char at 0x69+10*i
2927 stmp.str(cmapdata.substr(0x6A+10*i));
2928 GET_SHORT(stmp, val)
2929 }
2930
2931 ColorMapLevel level;
2932 level.fillColor = lowColor;
2933 colorMap.levels.push_back(make_pair(zmin, level));
2934
2935 for (int i = 0; i < (colorMapSize + 1); ++i) {
2936 Color color; (void) color;
2937 color.type = Origin::Color::Custom;
2938 color.custom[0] = cmapdata[0x7A+10*i];
2939 color.custom[1] = cmapdata[0x7B+10*i];
2940 color.custom[2] = cmapdata[0x7C+10*i];
2941 // skip an unsigned char at 0x7D+10*i
2942 stmp.str(cmapdata.substr((0x7E)+10*i));
2943 GET_SHORT(stmp, val)
2944
2945 level.fillColor = color;
2946 colorMap.levels.push_back(make_pair(val, level));
2947 }
2948
2949 level.fillColor = highColor;
2950 colorMap.levels.push_back(make_pair(zmax, level));
2951 }
2952
getProjectLeafProperties(tree<ProjectNode>::iterator current_folder,const string & ptldt,unsigned int ptldtsz)2953 void OriginAnyParser::getProjectLeafProperties(tree<ProjectNode>::iterator current_folder, const string& ptldt, unsigned int ptldtsz) {
2954 LOG_PRINT(logfile,"OriginAnyParser::getProjectLeafProperties()\n");
2955 istringstream stmp;
2956 (void) ptldtsz;
2957
2958 stmp.str(ptldt);
2959 unsigned int file_type = 0, file_object_id = 0;
2960 GET_INT(stmp, file_type);
2961 GET_INT(stmp, file_object_id);
2962
2963 LOG_PRINT(logfile,"file_type=%d file_object_id=%d\n",file_type,file_object_id);
2964 if (file_type == 0x100000) { // Note window
2965 LOG_PRINT(logfile,"notes.size()=%d\n",(int)notes.size());
2966 if ((file_object_id <= notes.size()) && (notes.size()>0)) {
2967 projectTree.append_child(current_folder, ProjectNode(notes[file_object_id].name, ProjectNode::Note));
2968 }
2969 } else { // other windows
2970 tree<Origin::ProjectNode>::iterator childnode;
2971 pair<ProjectNode::NodeType, Origin::Window> object = findWindowObjectByIndex(file_object_id);
2972 childnode=projectTree.append_child(current_folder, ProjectNode(object.second.name, object.first));
2973 (*childnode).creationDate = object.second.creationDate;
2974 (*childnode).modificationDate = object.second.modificationDate;
2975 }
2976 }
2977
getProjectFolderProperties(tree<ProjectNode>::iterator current_folder,const string & flehd,unsigned int flehdsz)2978 void OriginAnyParser::getProjectFolderProperties(tree<ProjectNode>::iterator current_folder, const string& flehd, unsigned int flehdsz) {
2979 istringstream stmp;
2980 (void) flehdsz;
2981
2982 unsigned char a = flehd[0x02];
2983 (*current_folder).active = (a == 1);
2984
2985 double creationDate, modificationDate;
2986 stmp.str(flehd.substr(0x10));
2987 GET_DOUBLE(stmp, creationDate);
2988 GET_DOUBLE(stmp, modificationDate);
2989
2990 (*current_folder).creationDate = doubleToPosixTime(creationDate);
2991 (*current_folder).modificationDate = doubleToPosixTime(modificationDate);
2992 }
2993
outputProjectTree(std::ostream & out)2994 void OriginAnyParser::outputProjectTree(std::ostream & out) {
2995 size_t windowsCount = spreadSheets.size()+matrixes.size()+excels.size()+graphs.size()+notes.size();
2996
2997 out << "Project has " << windowsCount << " windows." << endl;
2998 out << "Origin project Tree" << endl;
2999
3000 char cdsz[21];
3001 for (tree<ProjectNode>::iterator it = projectTree.begin(projectTree.begin()); it != projectTree.end(projectTree.begin()); ++it) {
3002 strftime(cdsz, sizeof(cdsz), "%F %T", gmtime(&(*it).creationDate));
3003 out << string(projectTree.depth(it) - 1, ' ') << (*it).name.c_str() << "\t" << cdsz << endl;
3004 }
3005 }
3006