File indexing completed on 2025-02-16 09:49:50
0001 0002 /* 0003 OriginAnyParser.cpp 0004 0005 SPDX-FileCopyrightText: 2017 Miquel Garriga <gbmiquel@gmail.com> 0006 SPDX-FileCopyrightText: 2021 Stefan Gerlach <stefan.gerlach@uni.kn> 0007 0008 SPDX-License-Identifier: GPL-3.0-or-later 0009 0010 Parser for all versions. Based mainly on Origin750Parser.cpp 0011 */ 0012 0013 #include "OriginAnyParser.h" 0014 0015 #include <sstream> 0016 #include <cinttypes> 0017 0018 using namespace std; 0019 0020 /* define a macro to get an int (or uint) from a istringstream in binary mode */ 0021 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 0022 # define GET_SHORT(iss, ovalue) \ 0023 { \ 0024 iss.read(reinterpret_cast<char *>(&ovalue), 2); \ 0025 }; 0026 # define GET_INT(iss, ovalue) \ 0027 { \ 0028 iss.read(reinterpret_cast<char *>(&ovalue), 4); \ 0029 }; 0030 # define GET_FLOAT(iss, ovalue) \ 0031 { \ 0032 iss.read(reinterpret_cast<char *>(&ovalue), 4); \ 0033 }; 0034 # define GET_DOUBLE(iss, ovalue) \ 0035 { \ 0036 iss.read(reinterpret_cast<char *>(&ovalue), 8); \ 0037 }; 0038 #else 0039 void inline swap_bytes(unsigned char *data, int size) 0040 { 0041 int i = 0, j = size - 1; 0042 while (i < j) { 0043 std::swap(data[i], data[j]); 0044 ++i, --j; 0045 } 0046 } 0047 # define GET_SHORT(iss, ovalue) \ 0048 { \ 0049 iss.read(reinterpret_cast<char *>(&ovalue), 2); \ 0050 swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 2); \ 0051 }; 0052 # define GET_INT(iss, ovalue) \ 0053 { \ 0054 iss.read(reinterpret_cast<char *>(&ovalue), 4); \ 0055 swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 4); \ 0056 }; 0057 # define GET_FLOAT(iss, ovalue) \ 0058 { \ 0059 iss.read(reinterpret_cast<char *>(&ovalue), 4); \ 0060 swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 4); \ 0061 }; 0062 # define GET_DOUBLE(iss, ovalue) \ 0063 { \ 0064 iss.read(reinterpret_cast<char *>(&ovalue), 8); \ 0065 swap_bytes(reinterpret_cast<unsigned char *>(&ovalue), 8); \ 0066 }; 0067 #endif 0068 0069 OriginAnyParser::OriginAnyParser(const string &fileName) 0070 : file(fileName.c_str(), ios::binary), 0071 logfile(nullptr), 0072 d_file_size(0), 0073 curpos(0), 0074 objectIndex(0), 0075 parseError(0), 0076 ispread(-1), 0077 imatrix(-1), 0078 iexcel(-1), 0079 igraph(-1), 0080 ilayer(-1) 0081 { 0082 } 0083 0084 bool OriginAnyParser::parse() 0085 { 0086 #ifdef GENERATE_CODE_FOR_LOG 0087 // append progress in log file 0088 logfile = fopen("opjfile.log", "a"); 0089 #endif // GENERATE_CODE_FOR_LOG 0090 0091 // get length of file: 0092 file.seekg(0, ios_base::end); 0093 d_file_size = file.tellg(); 0094 file.seekg(0, ios_base::beg); 0095 0096 LOG_PRINT(logfile, "File size: %" PRId64 "\n", d_file_size) 0097 0098 // get file and program version, check it is a valid file 0099 readFileVersion(); 0100 if (parseError > 1) 0101 return false; 0102 curpos = file.tellg(); 0103 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos) 0104 0105 // get global header 0106 readGlobalHeader(); 0107 if (parseError > 1) 0108 return false; 0109 curpos = file.tellg(); 0110 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos) 0111 0112 // get dataset list 0113 unsigned int dataset_list_size = 0; 0114 objectIndex = 0; // use it to count DataSets 0115 0116 LOG_PRINT(logfile, "Reading Data sets ...\n") 0117 while (true) { 0118 if (!readDataSetElement()) 0119 break; 0120 dataset_list_size++; 0121 } 0122 if (parseError > 1) 0123 return false; 0124 LOG_PRINT(logfile, " ... done. Data sets: %d\n", dataset_list_size) 0125 curpos = file.tellg(); 0126 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, 0127 curpos, d_file_size) 0128 0129 for (unsigned int i = 0; i < spreadSheets.size(); ++i) { 0130 if (spreadSheets[i].sheets > 1) { 0131 LOG_PRINT(logfile, " CONVERT SPREADSHEET \"%s\" to EXCEL\n", 0132 spreadSheets[i].name.c_str()); 0133 convertSpreadToExcel(i); 0134 --i; 0135 } 0136 } 0137 0138 // get window list 0139 unsigned int window_list_size = 0; 0140 objectIndex = 0; // reset it to count Windows (except Notes) 0141 0142 LOG_PRINT(logfile, "Reading Windows ...\n") 0143 while (true) { 0144 if (!readWindowElement()) 0145 break; 0146 window_list_size++; 0147 } 0148 LOG_PRINT(logfile, " ... done. Windows: %d\n", window_list_size) 0149 curpos = file.tellg(); 0150 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, 0151 curpos, d_file_size) 0152 0153 // get parameter list 0154 unsigned int parameter_list_size = 0; 0155 0156 LOG_PRINT(logfile, "Reading Parameters ...\n") 0157 while (true) { 0158 if (!readParameterElement()) 0159 break; 0160 parameter_list_size++; 0161 } 0162 LOG_PRINT(logfile, " ... done. Parameters: %d\n", parameter_list_size) 0163 curpos = file.tellg(); 0164 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, 0165 curpos, d_file_size) 0166 0167 // Note windows were added between version >4.141 and 4.210, 0168 // i.e., with Release 5.0 0169 if (curpos < d_file_size) { 0170 // get note windows list 0171 unsigned int note_list_size = 0; 0172 0173 LOG_PRINT(logfile, "Reading Note windows ...\n") 0174 objectIndex = 0; // reset it to count Notes 0175 while (true) { 0176 if (!readNoteElement()) 0177 break; 0178 note_list_size++; 0179 } 0180 LOG_PRINT(logfile, " ... done. Note windows: %d\n", note_list_size) 0181 curpos = file.tellg(); 0182 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, 0183 curpos, d_file_size) 0184 } 0185 0186 // Project Tree was added between version >4.210 and 4.2616, 0187 // i.e., with Release 6.0 0188 if (curpos < d_file_size) { 0189 // get project tree 0190 readProjectTree(); 0191 curpos = file.tellg(); 0192 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, 0193 curpos, d_file_size) 0194 } 0195 0196 // Attachments were added between version >4.2673_558 and 4.2764_623, 0197 // i.e., with Release 7.0 0198 if (curpos < d_file_size) { 0199 readAttachmentList(); 0200 curpos = file.tellg(); 0201 LOG_PRINT(logfile, "Now at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 "\n", curpos, 0202 curpos, d_file_size) 0203 } 0204 0205 if (curpos >= d_file_size) 0206 LOG_PRINT(logfile, "Now at end of file\n") 0207 0208 #ifdef GENERATE_CODE_FOR_LOG 0209 fclose(logfile); 0210 #endif // GENERATE_CODE_FOR_LOG 0211 0212 return true; 0213 } 0214 0215 string toLowerCase(string str) 0216 { 0217 for (unsigned int i = 0; i < str.length(); i++) 0218 if (str[i] >= 0x41 && str[i] <= 0x5A) 0219 str[i] = str[i] + 0x20; 0220 return str; 0221 } 0222 0223 OriginParser *createOriginAnyParser(const string &fileName) 0224 { 0225 return new OriginAnyParser(fileName); 0226 } 0227 0228 unsigned int OriginAnyParser::readObjectSize() 0229 { 0230 unsigned int obj_size = 0; 0231 0232 char c = 0; 0233 file >> obj_size; 0234 file >> c; 0235 if (c != '\n') { 0236 curpos = file.tellg(); 0237 LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, curpos) 0238 parseError = 3; 0239 return 0; 0240 } 0241 return obj_size; 0242 } 0243 0244 string OriginAnyParser::readObjectAsString(unsigned int size) 0245 { 0246 char c; 0247 // read a size-byte blob of data followed by '\n' 0248 if (size > 0) { 0249 // get a string large enough to hold the result, initialize it to all 0's 0250 string blob = string(size, '\0'); 0251 // read data into that string 0252 // cannot use '>>' operator because iendianfstream truncates it at first '\0' 0253 file.read(&blob[0], size); 0254 // read the '\n' 0255 file >> c; 0256 if (c != '\n') { 0257 curpos = file.tellg(); 0258 LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, 0259 curpos) 0260 parseError = 4; 0261 return string(); 0262 } 0263 return blob; 0264 } 0265 return string(); 0266 } 0267 0268 void OriginAnyParser::readFileVersion() 0269 { 0270 // get file and program version, check it is a valid file 0271 string sFileVersion; 0272 getline(file, sFileVersion); 0273 0274 if ((sFileVersion.substr(0, 4) != "CPYA")) { 0275 LOG_PRINT(logfile, "File, is not a valid OPJ file\n") 0276 if ((sFileVersion.substr(0, 5) != "CPYUA")) { 0277 LOG_PRINT(logfile, "File, is not a valid OPJU file\n") 0278 parseError = 2; 0279 return; 0280 } 0281 } 0282 0283 if (*sFileVersion.rbegin() != '#') 0284 parseError = 1; 0285 LOG_PRINT(logfile, "File version string: %s\n", sFileVersion.c_str()) 0286 } 0287 0288 void OriginAnyParser::readGlobalHeader() 0289 { 0290 LOG_PRINT(logfile, "readGlobalHeader()\n") 0291 // get global header size 0292 unsigned int gh_size = 0, gh_endmark = 0; 0293 gh_size = readObjectSize(); 0294 curpos = file.tellg(); 0295 LOG_PRINT(logfile, "Global header size: %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "],", 0296 gh_size, gh_size, curpos, curpos) 0297 0298 // get global header data 0299 string gh_data; 0300 gh_data = readObjectAsString(gh_size); 0301 0302 curpos = file.tellg(); 0303 LOG_PRINT(logfile, " ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos) 0304 0305 // when gh_size > 0x1B, a double with fileVersion/100 can be read at gh_data[0x1B:0x23] 0306 if (gh_size > 0x1B) { 0307 istringstream stmp; 0308 stmp.str(gh_data.substr(0x1B)); 0309 double dFileVersion; 0310 GET_DOUBLE(stmp, dFileVersion) 0311 if (dFileVersion > 8.5) { 0312 fileVersion = (unsigned int)trunc(dFileVersion * 100.); 0313 } else { 0314 fileVersion = 10 * (unsigned int)trunc(dFileVersion * 10.); 0315 } 0316 LOG_PRINT(logfile, "Project version as read from header: %.2f (%.6f)\n", 0317 fileVersion / 100.0, dFileVersion) 0318 } 0319 0320 // now read a zero size end mark 0321 gh_endmark = readObjectSize(); 0322 if (gh_endmark != 0) { 0323 curpos = file.tellg(); 0324 LOG_PRINT(logfile, "Wrong end of list mark %d at %" PRId64 " [0x%" PRIx64 "]\n", gh_endmark, 0325 curpos, curpos) 0326 parseError = 5; 0327 return; 0328 } 0329 } 0330 0331 bool OriginAnyParser::readDataSetElement() 0332 { 0333 LOG_PRINT(logfile, "readDataSetElement()\n") 0334 /* get info and values of a DataSet (worksheet column, matrix sheet, ...) 0335 * return true if a DataSet is found, otherwise return false */ 0336 unsigned int dse_header_size = 0, dse_data_size = 0, dse_mask_size = 0; 0337 std::streamoff dsh_start = 0, dsd_start = 0, dsm_start = 0; 0338 string dse_header; 0339 0340 // get dataset header size 0341 dse_header_size = readObjectSize(); 0342 if (dse_header_size == 0) 0343 return false; 0344 0345 curpos = file.tellg(); 0346 dsh_start = curpos; 0347 LOG_PRINT(logfile, "Column: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "], ", 0348 dse_header_size, dse_header_size, curpos, curpos) 0349 dse_header = readObjectAsString(dse_header_size); 0350 0351 // get known info 0352 string name(25, 0); 0353 name = dse_header.substr(0x58, 25); 0354 0355 // go to end of dataset header, get data size 0356 file.seekg(dsh_start + dse_header_size + 1, ios_base::beg); 0357 dse_data_size = readObjectSize(); 0358 dsd_start = file.tellg(); 0359 string dse_data = readObjectAsString(dse_data_size); 0360 curpos = file.tellg(); 0361 LOG_PRINT(logfile, 0362 "data size %d [0x%X], from %" PRId64 " [0x%" PRIx64 "] to %" PRId64 " [0x%" PRIx64 0363 "],", 0364 dse_data_size, dse_data_size, dsd_start, dsd_start, curpos, curpos) 0365 0366 // get data values 0367 getColumnInfoAndData(dse_header, dse_header_size, dse_data, dse_data_size); 0368 0369 // go to end of data values, get mask size (often zero) 0370 file.seekg(dsd_start + dse_data_size, ios_base::beg); // dse_data_size can be zero 0371 if (dse_data_size > 0) 0372 file.seekg(1, ios_base::cur); 0373 dse_mask_size = readObjectSize(); 0374 dsm_start = file.tellg(); 0375 if (dse_mask_size > 0) 0376 LOG_PRINT(logfile, "\nmask size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]", 0377 dse_mask_size, dse_mask_size, dsm_start, dsm_start) 0378 string dse_mask = readObjectAsString(dse_mask_size); 0379 0380 // get mask values 0381 if (dse_mask_size > 0) { 0382 curpos = file.tellg(); 0383 LOG_PRINT(logfile, ", ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos) 0384 // TODO: extract mask values from dse_mask 0385 // go to end of dataset mask 0386 file.seekg(dsm_start + dse_mask_size + 1, ios_base::beg); 0387 } 0388 curpos = file.tellg(); 0389 LOG_PRINT(logfile, " ends at %" PRId64 " [0x%" PRIx64 "]: ", curpos, curpos) 0390 LOG_PRINT(logfile, "%s\n", name.c_str()) 0391 0392 return true; 0393 } 0394 0395 bool OriginAnyParser::readWindowElement() 0396 { 0397 LOG_PRINT(logfile, "readWindowElement()\n") 0398 /* get general info and details of a window 0399 * return true if a Window is found, otherwise return false */ 0400 unsigned int wde_header_size = 0; 0401 std::streamoff wdh_start = 0; 0402 0403 // get window header size 0404 wde_header_size = readObjectSize(); 0405 if (wde_header_size == 0) 0406 return false; 0407 0408 curpos = file.tellg(); 0409 wdh_start = curpos; 0410 LOG_PRINT(logfile, 0411 "Window found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]: ", 0412 wde_header_size, wde_header_size, curpos, curpos) 0413 string wde_header = readObjectAsString(wde_header_size); 0414 0415 // get known info 0416 string name(25, 0); 0417 name = wde_header.substr(0x02, 25).c_str(); 0418 LOG_PRINT(logfile, "%s\n", name.c_str()) 0419 0420 // classify type of window 0421 ispread = findSpreadByName(name); 0422 imatrix = findMatrixByName(name); 0423 iexcel = findExcelByName(name); 0424 igraph = -1; 0425 0426 if (ispread != -1) { 0427 LOG_PRINT(logfile, "\n Window is a Worksheet book\n") 0428 getWindowProperties(spreadSheets[ispread], wde_header, wde_header_size); 0429 } else if (imatrix != -1) { 0430 LOG_PRINT(logfile, "\n Window is a Matrix book\n") 0431 getWindowProperties(matrixes[imatrix], wde_header, wde_header_size); 0432 } else if (iexcel != -1) { 0433 LOG_PRINT(logfile, "\n Window is an Excel book\n") 0434 getWindowProperties(excels[iexcel], wde_header, wde_header_size); 0435 } else { 0436 LOG_PRINT(logfile, "\n Window is a Graph\n") 0437 graphs.push_back(Graph(name)); 0438 igraph = (int)graphs.size() - 1; 0439 getWindowProperties(graphs[igraph], wde_header, wde_header_size); 0440 } 0441 0442 // go to end of window header 0443 file.seekg(wdh_start + wde_header_size + 1, ios_base::beg); 0444 0445 // get layer list 0446 unsigned int layer_list_size = 0; 0447 0448 LOG_PRINT(logfile, " Reading Layers ...\n") 0449 while (true) { 0450 ilayer = layer_list_size; 0451 if (!readLayerElement()) 0452 break; 0453 layer_list_size++; 0454 } 0455 LOG_PRINT(logfile, " ... done. Layers: %d\n", layer_list_size) 0456 curpos = file.tellg(); 0457 LOG_PRINT(logfile, "window ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos) 0458 0459 return true; 0460 } 0461 0462 bool OriginAnyParser::readLayerElement() 0463 { 0464 LOG_PRINT(logfile, "readLayerElement()\n") 0465 /* get general info and details of a layer 0466 * return true if a Layer is found, otherwise return false */ 0467 unsigned int lye_header_size = 0; 0468 std::streamoff lyh_start = 0; 0469 0470 // get layer header size 0471 lye_header_size = readObjectSize(); 0472 if (lye_header_size == 0) 0473 return false; 0474 0475 curpos = file.tellg(); 0476 lyh_start = curpos; 0477 LOG_PRINT(logfile, 0478 " Layer found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]\n", 0479 lye_header_size, lye_header_size, curpos, curpos) 0480 string lye_header = readObjectAsString(lye_header_size); 0481 0482 // get known info 0483 LOG_PRINT(logfile, " Reading Layer properties ...\n") 0484 getLayerProperties(lye_header, lye_header_size); 0485 0486 // go to end of layer header 0487 file.seekg(lyh_start + lye_header_size + 1, ios_base::beg); 0488 0489 // get annotation list 0490 unsigned int annotation_list_size = 0; 0491 0492 LOG_PRINT(logfile, " Reading Annotations ...\n") 0493 /* Some annotations can be groups of annotations. We need a recursive function for those cases 0494 */ 0495 annotation_list_size = readAnnotationList(); 0496 if (annotation_list_size > 0) { 0497 LOG_PRINT(logfile, " ... done. Annotations: %d\n", annotation_list_size) 0498 } 0499 0500 // get curve list 0501 unsigned int curve_list_size = 0; 0502 0503 LOG_PRINT(logfile, " Reading Curves ...\n") 0504 while (true) { 0505 if (!readCurveElement()) 0506 break; 0507 curve_list_size++; 0508 } 0509 LOG_PRINT(logfile, " ... done. Curves: %d\n", curve_list_size) 0510 0511 // get axisbreak list 0512 unsigned int axisbreak_list_size = 0; 0513 0514 LOG_PRINT(logfile, " Reading Axis breaks ...\n") 0515 while (true) { 0516 if (!readAxisBreakElement()) 0517 break; 0518 axisbreak_list_size++; 0519 } 0520 LOG_PRINT(logfile, " ... done. Axis breaks: %d\n", axisbreak_list_size) 0521 0522 // get x axisparameter list 0523 unsigned int axispar_x_list_size = 0; 0524 0525 LOG_PRINT(logfile, " Reading x-Axis parameters ...\n") 0526 while (true) { 0527 if (!readAxisParameterElement(1)) 0528 break; 0529 axispar_x_list_size++; 0530 } 0531 LOG_PRINT(logfile, " ... done. x-Axis parameters: %d\n", axispar_x_list_size) 0532 0533 // get y axisparameter list 0534 unsigned int axispar_y_list_size = 0; 0535 0536 LOG_PRINT(logfile, " Reading y-Axis parameters ...\n") 0537 while (true) { 0538 if (!readAxisParameterElement(2)) 0539 break; 0540 axispar_y_list_size++; 0541 } 0542 LOG_PRINT(logfile, " ... done. y-Axis parameters: %d\n", axispar_y_list_size) 0543 0544 // get z axisparameter list 0545 unsigned int axispar_z_list_size = 0; 0546 0547 LOG_PRINT(logfile, " Reading z-Axis parameters ...\n") 0548 while (true) { 0549 if (!readAxisParameterElement(3)) 0550 break; 0551 axispar_z_list_size++; 0552 } 0553 LOG_PRINT(logfile, " ... done. z-Axis parameters: %d\n", axispar_z_list_size) 0554 0555 curpos = file.tellg(); 0556 LOG_PRINT(logfile, " layer ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos) 0557 0558 return true; 0559 } 0560 0561 unsigned int OriginAnyParser::readAnnotationList() 0562 { 0563 LOG_PRINT(logfile, "readAnnotationList()\n") 0564 /* Purpose of this function is to allow recursive call for groups of annotation elements. */ 0565 unsigned int annotation_list_size = 0; 0566 0567 while (true) { 0568 if (!readAnnotationElement()) 0569 break; 0570 annotation_list_size++; 0571 } 0572 return annotation_list_size; 0573 } 0574 0575 bool OriginAnyParser::readAnnotationElement() 0576 { 0577 LOG_PRINT(logfile, "readAnnotationElement()\n") 0578 /* get general info and details of an Annotation 0579 * return true if an Annotation is found, otherwise return false */ 0580 unsigned int ane_header_size = 0; 0581 std::streamoff anh_start = 0; 0582 0583 // get annotation header size 0584 ane_header_size = readObjectSize(); 0585 if (ane_header_size == 0) 0586 return false; 0587 0588 curpos = file.tellg(); 0589 anh_start = curpos; 0590 LOG_PRINT(logfile, 0591 " Annotation found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 0592 "]: ", 0593 ane_header_size, ane_header_size, curpos, curpos) 0594 string ane_header = readObjectAsString(ane_header_size); 0595 0596 // get known info 0597 string name(41, 0); 0598 name = ane_header.substr(0x46, 41); 0599 LOG_PRINT(logfile, "%s\n", name.c_str()) 0600 0601 // go to end of annotation header 0602 file.seekg(anh_start + ane_header_size + 1, ios_base::beg); 0603 0604 // data of an annotation element is divided in three blocks 0605 // first block 0606 unsigned int ane_data_1_size = 0; 0607 std::streamoff andt1_start = 0; 0608 ane_data_1_size = readObjectSize(); 0609 0610 andt1_start = file.tellg(); 0611 LOG_PRINT(logfile, " block 1 size %d [0x%X] at %" PRId64 " [0x%" PRIx64 "]\n", 0612 ane_data_1_size, ane_data_1_size, andt1_start, andt1_start) 0613 string andt1_data = readObjectAsString(ane_data_1_size); 0614 0615 // TODO: get known info 0616 0617 // go to end of first data block 0618 file.seekg(andt1_start + ane_data_1_size + 1, ios_base::beg); 0619 0620 // second block 0621 unsigned int ane_data_2_size = 0; 0622 std::streamoff andt2_start = 0; 0623 ane_data_2_size = readObjectSize(); 0624 andt2_start = file.tellg(); 0625 LOG_PRINT(logfile, " block 2 size %d [0x%X] at %" PRId64 " [0x%" PRIx64 "]\n", 0626 ane_data_2_size, ane_data_2_size, andt2_start, andt2_start) 0627 string andt2_data; 0628 0629 // check for group of annotations 0630 if (((ane_data_1_size == 0x5e) || (ane_data_1_size == 0x0A)) && (ane_data_2_size == 0x04)) { 0631 curpos = file.tellg(); 0632 LOG_PRINT(logfile, " Annotation group found at %" PRId64 " [0x%" PRIx64 "] ...\n", curpos, 0633 curpos) 0634 unsigned int angroup_size = readAnnotationList(); 0635 curpos = file.tellg(); 0636 if (angroup_size > 0) { 0637 LOG_PRINT(logfile, " ... group end at %" PRId64 " [0x%" PRIx64 "]. Annotations: %d\n", 0638 curpos, curpos, angroup_size) 0639 } 0640 andt2_data = string(); 0641 } else { 0642 andt2_data = readObjectAsString(ane_data_2_size); 0643 // TODO: get known info 0644 // go to end of second data block 0645 file.seekg(andt2_start + ane_data_2_size, ios_base::beg); 0646 if (ane_data_2_size > 0) 0647 file.seekg(1, ios_base::cur); 0648 } 0649 0650 // third block 0651 unsigned int ane_data_3_size = 0; 0652 ane_data_3_size = readObjectSize(); 0653 0654 std::streamoff andt3_start = file.tellg(); 0655 if (andt3_start > 0) { 0656 LOG_PRINT(logfile, " block 3 size %d [0x%X] at %" PRId64 " [0x%" PRIx64 "]\n", 0657 ane_data_3_size, ane_data_3_size, andt3_start, andt3_start) 0658 } 0659 string andt3_data = readObjectAsString(ane_data_3_size); 0660 0661 curpos = file.tellg(); 0662 LOG_PRINT(logfile, " annotation ends at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos) 0663 0664 // get annotation info 0665 getAnnotationProperties(ane_header, ane_header_size, andt1_data, ane_data_1_size, andt2_data, 0666 ane_data_2_size, andt3_data, ane_data_3_size); 0667 0668 return true; 0669 } 0670 0671 bool OriginAnyParser::readCurveElement() 0672 { 0673 LOG_PRINT(logfile, "readCurveElement()\n") 0674 /* get general info and details of a Curve 0675 * return true if a Curve is found, otherwise return false */ 0676 unsigned int cve_header_size = 0, cve_data_size = 0; 0677 std::streamoff cvh_start = 0, cvd_start = 0; 0678 0679 // get curve header size 0680 cve_header_size = readObjectSize(); 0681 if (cve_header_size == 0) 0682 return false; 0683 0684 curpos = file.tellg(); 0685 cvh_start = curpos; 0686 LOG_PRINT(logfile, " Curve: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "], ", 0687 cve_header_size, cve_header_size, curpos, curpos) 0688 string cve_header = readObjectAsString(cve_header_size); 0689 0690 // TODO: get known info from curve header 0691 string name = cve_header.substr(0x12, 12); 0692 0693 // go to end of header, get curve data size 0694 file.seekg(cvh_start + cve_header_size + 1, ios_base::beg); 0695 cve_data_size = readObjectSize(); 0696 cvd_start = file.tellg(); 0697 LOG_PRINT(logfile, "data size %d [0x%X], from %" PRId64 " [0x%" PRIx64 "]", cve_data_size, 0698 cve_data_size, cvd_start, cvd_start) 0699 string cve_data = readObjectAsString(cve_data_size); 0700 0701 // TODO: get known info from curve data 0702 0703 // go to end of data 0704 file.seekg(cvd_start + cve_data_size, ios_base::beg); 0705 if (cve_data_size > 0) 0706 file.seekg(1, ios_base::cur); 0707 0708 curpos = file.tellg(); 0709 LOG_PRINT(logfile, "to %" PRId64 " [0x%" PRIx64 "]: %s\n", curpos, curpos, name.c_str()) 0710 0711 // get curve (or column) info 0712 getCurveProperties(cve_header, cve_header_size, cve_data, cve_data_size); 0713 0714 return true; 0715 } 0716 0717 bool OriginAnyParser::readAxisBreakElement() 0718 { 0719 LOG_PRINT(logfile, "readAxisBreakElement()\n") 0720 /* get info of Axis breaks 0721 * return true if an Axis break, otherwise return false */ 0722 unsigned int abe_data_size = 0; 0723 std::streamoff abd_start = 0; 0724 0725 // get axis break data size 0726 abe_data_size = readObjectSize(); 0727 if (abe_data_size == 0) 0728 return false; 0729 0730 curpos = file.tellg(); 0731 abd_start = curpos; 0732 string abd_data = readObjectAsString(abe_data_size); 0733 0734 // get known info 0735 0736 // go to end of axis break data 0737 file.seekg(abd_start + abe_data_size + 1, ios_base::beg); 0738 0739 // get axis break info 0740 getAxisBreakProperties(abd_data, abe_data_size); 0741 0742 return true; 0743 } 0744 0745 bool OriginAnyParser::readAxisParameterElement(unsigned int naxis) 0746 { 0747 LOG_PRINT(logfile, "readAxisParameterElement()\n") 0748 /* get info of Axis parameters for naxis-axis (x,y,z) = (1,2,3) 0749 * return true if an Axis break is found, otherwise return false */ 0750 unsigned int ape_data_size = 0; 0751 std::streamoff apd_start = 0; 0752 0753 // get axis break data size 0754 ape_data_size = readObjectSize(); 0755 if (ape_data_size == 0) 0756 return false; 0757 0758 curpos = file.tellg(); 0759 apd_start = curpos; 0760 string apd_data = readObjectAsString(ape_data_size); 0761 0762 // get known info 0763 0764 // go to end of axis break data 0765 file.seekg(apd_start + ape_data_size + 1, ios_base::beg); 0766 0767 // get axis parameter info 0768 getAxisParameterProperties(apd_data, ape_data_size, naxis); 0769 0770 return true; 0771 } 0772 0773 bool OriginAnyParser::readParameterElement() 0774 { 0775 LOG_PRINT(logfile, "readParameterElement()\n") 0776 // get parameter name 0777 string par_name; 0778 char c; 0779 0780 getline(file, par_name); 0781 if (par_name[0] == '\0') { 0782 unsigned int eof_parameters_mark = readObjectSize(); 0783 if (eof_parameters_mark != 0) { 0784 LOG_PRINT(logfile, "Wrong end of parameters mark\n") 0785 } 0786 return false; 0787 } 0788 LOG_PRINT(logfile, " %s:", par_name.c_str()) 0789 // get value 0790 double value; 0791 file >> value; 0792 LOG_PRINT(logfile, " %g\n", value) 0793 // read the '\n' 0794 file >> c; 0795 if (c != '\n') { 0796 curpos = file.tellg(); 0797 LOG_PRINT(logfile, "Wrong delimiter %c at %" PRId64 " [0x%" PRIx64 "]\n", c, curpos, curpos) 0798 parseError = 6; 0799 return false; 0800 } 0801 0802 return true; 0803 } 0804 0805 bool OriginAnyParser::readNoteElement() 0806 { 0807 LOG_PRINT(logfile, "readNoteElement()\n") 0808 /* get info of Note windows, including "Results Log" 0809 * return true if a Note window is found, otherwise return false */ 0810 unsigned int nwe_header_size = 0, nwe_label_size = 0, nwe_contents_size = 0; 0811 std::streamoff nwh_start = 0, nwl_start = 0, nwc_start = 0; 0812 0813 // get note header size 0814 nwe_header_size = readObjectSize(); 0815 if (nwe_header_size == 0) 0816 return false; 0817 0818 curpos = file.tellg(); 0819 nwh_start = curpos; 0820 LOG_PRINT(logfile, 0821 " Note window found: header size %d [0x%X], starts at %" PRId64 " [0x%" PRIx64 "]\n", 0822 nwe_header_size, nwe_header_size, curpos, curpos) 0823 string nwe_header = readObjectAsString(nwe_header_size); 0824 0825 // TODO: get known info from header 0826 0827 // go to end of header 0828 file.seekg(nwh_start + nwe_header_size + 1, ios_base::beg); 0829 0830 // get label size 0831 nwe_label_size = readObjectSize(); 0832 nwl_start = file.tellg(); 0833 string nwe_label = readObjectAsString(nwe_label_size); 0834 LOG_PRINT(logfile, " label at %" PRId64 " [0x%" PRIx64 "]: %s\n", nwl_start, nwl_start, 0835 nwe_label.c_str()) 0836 0837 // go to end of label 0838 file.seekg(nwl_start + nwe_label_size, ios_base::beg); 0839 if (nwe_label_size > 0) 0840 file.seekg(1, ios_base::cur); 0841 0842 // get contents size 0843 nwe_contents_size = readObjectSize(); 0844 nwc_start = file.tellg(); 0845 string nwe_contents = readObjectAsString(nwe_contents_size); 0846 if (nwc_start > 0) { 0847 LOG_PRINT(logfile, " contents at %" PRId64 " [0x%" PRIx64 "]: \n%s\n", nwc_start, 0848 nwc_start, nwe_contents.c_str()) 0849 } 0850 0851 // get note window info 0852 getNoteProperties(nwe_header, nwe_header_size, nwe_label, nwe_label_size, nwe_contents, 0853 nwe_contents_size); 0854 0855 return true; 0856 } 0857 0858 void OriginAnyParser::readProjectTree() 0859 { 0860 LOG_PRINT(logfile, "readProjectTree()\n") 0861 unsigned int pte_depth = 0; 0862 0863 // first preamble size and data (usually 4) 0864 unsigned int pte_pre1_size = readObjectSize(); 0865 string pte_pre1 = readObjectAsString(pte_pre1_size); 0866 0867 // second preamble size and data (usually 16) 0868 unsigned int pte_pre2_size = readObjectSize(); 0869 string pte_pre2 = readObjectAsString(pte_pre2_size); 0870 0871 // root element and children 0872 unsigned int rootfolder = readFolderTree( 0873 projectTree.insert(projectTree.begin(), ProjectNode("", ProjectNode::Folder)), 0874 pte_depth); 0875 if (rootfolder > 0) { 0876 LOG_PRINT(logfile, "Number of files at root: %d\n", rootfolder) 0877 } 0878 0879 // epilogue (should be zero) 0880 unsigned int pte_post_size = readObjectSize(); 0881 if (pte_post_size != 0) { 0882 LOG_PRINT(logfile, "Wrong end of project tree mark\n") 0883 } 0884 0885 // log info on project tree 0886 #ifdef GENERATE_CODE_FOR_LOG 0887 outputProjectTree(cout); 0888 #endif // GENERATE_CODE_FOR_LOG 0889 0890 return; 0891 } 0892 0893 unsigned int OriginAnyParser::readFolderTree(tree<ProjectNode>::iterator parent, unsigned int depth) 0894 { 0895 LOG_PRINT(logfile, "readFolderTree()\n") 0896 unsigned int fle_header_size = 0, fle_eofh_size = 0, fle_name_size = 0, fle_prop_size = 0; 0897 0898 // folder header size, data, end mark 0899 fle_header_size = readObjectSize(); 0900 string fle_header = readObjectAsString(fle_header_size); 0901 fle_eofh_size = readObjectSize(); // (usually 0) 0902 if (fle_eofh_size != 0) { 0903 LOG_PRINT(logfile, "Wrong end of folder header mark") 0904 } 0905 0906 // folder name size 0907 fle_name_size = readObjectSize(); 0908 curpos = file.tellg(); 0909 string fle_name = readObjectAsString(fle_name_size); 0910 LOG_PRINT(logfile, "Folder name at %" PRId64 " [0x%" PRIx64 "]: %s\n", curpos, curpos, 0911 fle_name.c_str()); 0912 0913 // additional properties 0914 fle_prop_size = readObjectSize(); 0915 for (unsigned int i = 0; i < fle_prop_size; i++) { 0916 unsigned int obj_size = readObjectSize(); 0917 string obj_data = readObjectAsString(obj_size); 0918 } 0919 0920 // get project folder properties 0921 tree<ProjectNode>::iterator current_folder = 0922 projectTree.append_child(parent, ProjectNode(fle_name, ProjectNode::Folder)); 0923 getProjectFolderProperties(current_folder, fle_header, fle_header_size); 0924 0925 // file entries 0926 unsigned int number_of_files_size = 0; 0927 0928 number_of_files_size = readObjectSize(); // should be 4 as number_of_files is an integer 0929 curpos = file.tellg(); 0930 LOG_PRINT(logfile, "Number of files at %" PRId64 " [0x%" PRIx64 "] ", curpos, curpos) 0931 string fle_nfiles = readObjectAsString(number_of_files_size); 0932 0933 istringstream stmp(ios_base::binary); 0934 stmp.str(fle_nfiles); 0935 unsigned int number_of_files = 0; 0936 GET_INT(stmp, number_of_files) 0937 LOG_PRINT(logfile, "%d\n", number_of_files) 0938 0939 for (unsigned int i = 0; i < number_of_files; i++) { 0940 readProjectLeaf(current_folder); 0941 } 0942 0943 // subfolder entries 0944 unsigned int number_of_folders_size = 0; 0945 0946 number_of_folders_size = readObjectSize(); // should be 4 as number_of_subfolders is an integer 0947 curpos = file.tellg(); 0948 LOG_PRINT(logfile, "Number of subfolders at %" PRId64 " [0x%" PRIx64 "] ", curpos, curpos) 0949 string fle_nfolders = readObjectAsString(number_of_folders_size); 0950 0951 stmp.str(fle_nfolders); 0952 unsigned int number_of_folders = 0; 0953 GET_INT(stmp, number_of_folders) 0954 LOG_PRINT(logfile, "%d\n", number_of_folders) 0955 0956 for (unsigned int i = 0; i < number_of_folders; i++) { 0957 depth++; 0958 unsigned int files_in_subfolder = readFolderTree(current_folder, depth); 0959 if (files_in_subfolder > 0) { 0960 LOG_PRINT(logfile, "Number of files in subfolder: %d\n", files_in_subfolder) 0961 } 0962 depth--; 0963 } 0964 0965 return number_of_files; 0966 } 0967 0968 void OriginAnyParser::readProjectLeaf(tree<ProjectNode>::iterator current_folder) 0969 { 0970 // preamble size (usually 0) and data 0971 unsigned int ptl_pre_size = readObjectSize(); 0972 string ptl_pre = readObjectAsString(ptl_pre_size); 0973 0974 // file data size (usually 8) and data 0975 unsigned int ptl_data_size = readObjectSize(); 0976 curpos = file.tellg(); 0977 string ptl_data = readObjectAsString(ptl_data_size); 0978 LOG_PRINT(logfile, "File at %" PRId64 " [0x%" PRIx64 "]\n", curpos, curpos) 0979 0980 // epilogue (should be zero) 0981 unsigned int ptl_post_size = readObjectSize(); 0982 if (ptl_post_size != 0) { 0983 LOG_PRINT(logfile, "Wrong end of project leaf mark\n") 0984 } 0985 0986 // get project node properties 0987 getProjectLeafProperties(current_folder, ptl_data, ptl_data_size); 0988 0989 return; 0990 } 0991 0992 void OriginAnyParser::readAttachmentList() 0993 { 0994 LOG_PRINT(logfile, "readAttachmentList()\n") 0995 /* Attachments are divided in two groups (which can be empty) 0996 first group is preceded by two integers: 4096 (0x1000) and number_of_attachments followed as 0997 usual by a '\n' mark second group is a series of (header, name, data) triplets without the '\n' 0998 mark. 0999 */ 1000 1001 // figure out if first group is not empty. In this case we will read integer=8 at current file 1002 // position 1003 unsigned int att_1st_empty = 0; 1004 file >> att_1st_empty; 1005 file.seekg(-4, ios_base::cur); 1006 1007 istringstream stmp(ios_base::binary); 1008 string att_header; 1009 if (att_1st_empty == 8) { 1010 // first group 1011 unsigned int att_list1_size = 0; 1012 1013 // get two integers 1014 // next line fails if first attachment group is empty: readObjectSize exits as there is no 1015 // '\n' after 4 bytes for uint 1016 att_list1_size = readObjectSize(); // should be 8 as we expect two integer values 1017 curpos = file.tellg(); 1018 string att_list1 = readObjectAsString(att_list1_size); 1019 LOG_PRINT(logfile, "First attachment group at %" PRId64 " [0x%" PRIx64 "]", curpos, curpos) 1020 1021 stmp.str(att_list1); 1022 1023 unsigned int att_mark = 0, number_of_atts = 0, iattno = 0, att_data_size = 0; 1024 GET_INT(stmp, att_mark) // should be 4096 1025 GET_INT(stmp, number_of_atts) 1026 LOG_PRINT(logfile, " with %d attachments.\n", number_of_atts) 1027 1028 for (unsigned int i = 0; i < number_of_atts; i++) { 1029 /* Header is a group of 7 integers followed by \n 1030 1st attachment mark (4096: 0x00 0x10 0x00 0x00) 1031 2nd attachment number ( <num_of_att) 1032 3rd attachment size 1033 4th .. 7th ??? 1034 */ 1035 // get header 1036 att_header = readObjectAsString(7 * 4); 1037 stmp.str(att_header); 1038 GET_INT(stmp, att_mark) // should be 4096 1039 GET_INT(stmp, iattno) 1040 GET_INT(stmp, att_data_size) 1041 curpos = file.tellg(); 1042 LOG_PRINT(logfile, "Attachment no %d (%d) at %" PRId64 " [0x%" PRIx64 "], size %d\n", i, 1043 iattno, curpos, curpos, att_data_size) 1044 1045 // get data 1046 string att_data = readObjectAsString(att_data_size); 1047 // even if att_data_size is zero, we get a '\n' mark 1048 if (att_data_size == 0) 1049 file.seekg(1, ios_base::cur); 1050 } 1051 } else { 1052 LOG_PRINT(logfile, "First attachment group is empty\n") 1053 } 1054 1055 /* Second group is a series of (header, name, data) triplets 1056 There is no number of attachments. It ends when we reach EOF. */ 1057 curpos = file.tellg(); 1058 LOG_PRINT(logfile, 1059 "Second attachment group starts at %" PRId64 " [0x%" PRIx64 "], file size %" PRId64 1060 "\n", 1061 curpos, curpos, d_file_size) 1062 /* Header is a group of 3 integers, with no '\n' at end 1063 1st attachment header+name size including itself 1064 2nd attachment type (0x59 0x04 0xCA 0x7F for excel workbooks) 1065 3rd size of data */ 1066 1067 // get header 1068 att_header = string(12, 0); 1069 while (true) { 1070 // check for eof 1071 if ((d_file_size == file.tellg()) || (file.eof())) 1072 break; 1073 // cannot use readObjectAsString: there is no '\n' at end 1074 file.read(reinterpret_cast<char *>(&att_header[0]), 12); 1075 1076 if (file.gcount() != 12) 1077 break; 1078 // get header size, type and data size 1079 unsigned int att_header_size = 0, att_type = 0, att_size = 0; 1080 stmp.str(att_header); 1081 GET_INT(stmp, att_header_size) 1082 GET_INT(stmp, att_type) 1083 GET_INT(stmp, att_size) 1084 1085 // get name and data 1086 unsigned int name_size = att_header_size - 3 * 4; 1087 string att_name = string(name_size, 0); 1088 file.read(&att_name[0], name_size); 1089 curpos = file.tellg(); 1090 string att_data = string(att_size, 0); 1091 file.read(&att_data[0], att_size); 1092 LOG_PRINT(logfile, 1093 "attachment at %" PRId64 " [0x%" PRIx64 "], type 0x%X, size %d [0x%X]: %s\n", 1094 curpos, curpos, att_type, att_size, att_size, att_name.c_str()) 1095 } 1096 1097 return; 1098 } 1099 1100 bool OriginAnyParser::getColumnInfoAndData(const string &col_header, unsigned int col_header_size, 1101 const string &col_data, unsigned int col_data_size) 1102 { 1103 istringstream stmp(ios_base::binary); 1104 short data_type; 1105 char data_type_u; 1106 unsigned char valuesize; 1107 string name(25, 0), column_name; 1108 1109 stmp.str(col_header.substr(0x16)); 1110 GET_SHORT(stmp, data_type); 1111 1112 data_type_u = col_header[0x3F]; 1113 if (fileVersion == 350) { 1114 valuesize = col_header[0x36]; 1115 } else { 1116 valuesize = col_header[0x3D]; 1117 } 1118 if (valuesize == 0) { 1119 LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize); 1120 valuesize = 8; 1121 } 1122 1123 if (fileVersion == 350) { 1124 name = col_header.substr(0x57, 25).c_str(); 1125 } else { 1126 name = col_header.substr(0x58, 25).c_str(); 1127 } 1128 string dataset_name = name; 1129 string::size_type colpos = name.find_last_of("_"); 1130 1131 if (colpos != string::npos) { 1132 column_name = name.substr(colpos + 1); 1133 name.resize(colpos); 1134 } 1135 1136 LOG_PRINT(logfile, "\n data_type 0x%.4X, data_type_u 0x%.2X, valuesize %d [0x%X], %s [%s]\n", 1137 data_type, data_type_u, valuesize, valuesize, name.c_str(), column_name.c_str()); 1138 1139 int total_rows, first_row, last_row; 1140 stmp.str(col_header.substr(0x19)); 1141 GET_INT(stmp, total_rows); 1142 GET_INT(stmp, first_row); 1143 GET_INT(stmp, last_row); 1144 LOG_PRINT(logfile, " total %d, first %d, last %d rows\n", total_rows, first_row, last_row) 1145 1146 unsigned short signature; 1147 if (col_header_size > 0x72) { 1148 stmp.str(col_header.substr(0x71)); 1149 GET_SHORT(stmp, signature); 1150 } else { 1151 LOG_PRINT(logfile, " NOTE: alternative signature determination\n") 1152 signature = col_header[0x18]; 1153 } 1154 LOG_PRINT(logfile, " signature %d [0x%X], valuesize %d size %d ", signature, signature, 1155 valuesize, col_data_size) 1156 1157 size_t current_col = 1; //, nr = 0, nbytes = 0; 1158 static unsigned int col_index = 0; 1159 unsigned int current_sheet = 0; 1160 vector<Origin::SpreadSheet>::difference_type spread = 0; 1161 1162 if (column_name.empty()) { // Matrix or function 1163 if (data_type == 0x6081) { // Function 1164 functions.push_back(Function(name, objectIndex)); 1165 Origin::Function &f = functions.back(); 1166 f.formula = toLowerCase(col_data.c_str()); 1167 1168 stmp.str(col_header.substr(0x0A)); 1169 short t; 1170 GET_SHORT(stmp, t) 1171 if (t == 0x1194) 1172 f.type = Function::Polar; 1173 1174 stmp.str(col_header.substr(0x21)); 1175 GET_INT(stmp, f.totalPoints) 1176 GET_DOUBLE(stmp, f.begin) 1177 double d; 1178 GET_DOUBLE(stmp, d) 1179 f.end = f.begin + d * (f.totalPoints - 1); 1180 1181 LOG_PRINT(logfile, "\n NEW FUNCTION: %s = %s", f.name.c_str(), f.formula.c_str()); 1182 LOG_PRINT(logfile, ". Range [%g : %g], number of points: %d\n", f.begin, f.end, 1183 f.totalPoints); 1184 1185 } else { // Matrix 1186 vector<Origin::Matrix>::difference_type mIndex = -1; 1187 string::size_type pos = name.find_first_of("@"); 1188 if (pos != string::npos) { 1189 string sheetName = name; 1190 name.resize(pos); 1191 mIndex = findMatrixByName(name); 1192 if (mIndex != -1) { 1193 LOG_PRINT(logfile, "\n NEW MATRIX SHEET\n"); 1194 matrixes[mIndex].sheets.push_back(MatrixSheet(sheetName, objectIndex)); 1195 } 1196 } else { 1197 LOG_PRINT(logfile, "\n NEW MATRIX\n"); 1198 matrixes.push_back(Matrix(name)); 1199 matrixes.back().sheets.push_back(MatrixSheet(name, objectIndex)); 1200 } 1201 // add an empty data set to keep objectIndex synchronized with datasets.size() 1202 datasets.push_back(SpreadColumn(name, objectIndex)); 1203 getMatrixValues(col_data, col_data_size, data_type, data_type_u, valuesize, mIndex); 1204 } 1205 } else { 1206 if (spreadSheets.size() == 0 || findSpreadByName(name) == -1) { 1207 LOG_PRINT(logfile, "\n NEW SPREADSHEET\n"); 1208 current_col = 1; 1209 spreadSheets.push_back(SpreadSheet(name)); 1210 spread = spreadSheets.size() - 1; 1211 spreadSheets.back().maxRows = 0; 1212 current_sheet = 0; 1213 } else { 1214 spread = findSpreadByName(name); 1215 current_col = spreadSheets[spread].columns.size(); 1216 if (!current_col) 1217 current_col = 1; 1218 ++current_col; 1219 } 1220 spreadSheets[spread].columns.push_back(SpreadColumn(column_name, objectIndex)); 1221 spreadSheets[spread].columns.back().colIndex = ++col_index; 1222 spreadSheets[spread].columns.back().dataset_name = dataset_name; 1223 spreadSheets[spread].columns.back().numRows = total_rows; 1224 spreadSheets[spread].columns.back().beginRow = first_row; 1225 spreadSheets[spread].columns.back().endRow = last_row; 1226 1227 string::size_type sheetpos = spreadSheets[spread].columns.back().name.find_last_of("@"); 1228 if (sheetpos != string::npos) { 1229 unsigned int sheet = strtol(column_name.substr(sheetpos + 1).c_str(), nullptr, 10); 1230 if (sheet > 1) { 1231 spreadSheets[spread].columns.back().name = column_name; 1232 1233 if (current_sheet != (sheet - 1)) 1234 current_sheet = sheet - 1; 1235 1236 spreadSheets[spread].columns.back().sheet = current_sheet; 1237 if (spreadSheets[spread].sheets < sheet) 1238 spreadSheets[spread].sheets = sheet; 1239 } 1240 } 1241 LOG_PRINT(logfile, " data index %d, valuesize %d, ", objectIndex, valuesize) 1242 1243 unsigned int nr = col_data_size / valuesize; 1244 LOG_PRINT(logfile, "n. of rows = %d\n\n", nr) 1245 1246 spreadSheets[spread].maxRows < nr ? spreadSheets[spread].maxRows = nr : 0; 1247 stmp.str(col_data); 1248 for (unsigned int i = 0; i < nr; ++i) { 1249 double value; 1250 if (valuesize <= 8) // Numeric, Time, Date, Month, Day 1251 { 1252 GET_DOUBLE(stmp, value) 1253 if ((i < 5) || (i > (nr - 5))) { 1254 LOG_PRINT(logfile, "%g ", value) 1255 } else if (i == 5) { 1256 LOG_PRINT(logfile, "... ") 1257 } 1258 spreadSheets[spread].columns[(current_col - 1)].data.push_back(value); 1259 } else if ((data_type & 0x100) == 0x100) // Text&Numeric 1260 { 1261 unsigned char c = col_data[i * valuesize]; 1262 stmp.seekg(i * valuesize + 2, ios_base::beg); 1263 if (c != 1) // value 1264 { 1265 GET_DOUBLE(stmp, value); 1266 if ((i < 5) || (i > (nr - 5))) { 1267 LOG_PRINT(logfile, "%g ", value) 1268 } else if (i == 5) { 1269 LOG_PRINT(logfile, "... ") 1270 } 1271 spreadSheets[spread].columns[(current_col - 1)].data.push_back(value); 1272 } else // text 1273 { 1274 string svaltmp = col_data.substr(i * valuesize + 2, valuesize - 2); 1275 // TODO: check if this test is still needed 1276 if (svaltmp.find(0x0E) 1277 != string::npos) { // try find non-printable symbol - garbage test 1278 svaltmp = string(); 1279 LOG_PRINT(logfile, "Non printable symbol found, place 1 for i=%d\n", i) 1280 } 1281 if ((i < 5) || (i > (nr - 5))) { 1282 LOG_PRINT(logfile, "\"%s\" ", svaltmp.c_str()) 1283 } else if (i == 5) { 1284 LOG_PRINT(logfile, "... ") 1285 } 1286 spreadSheets[spread].columns[(current_col - 1)].data.push_back(svaltmp); 1287 } 1288 } else // text 1289 { 1290 string svaltmp = col_data.substr(i * valuesize, valuesize).c_str(); 1291 // TODO: check if this test is still needed 1292 if (svaltmp.find(0x0E) 1293 != string::npos) { // try find non-printable symbol - garbage test 1294 svaltmp = string(); 1295 LOG_PRINT(logfile, "Non printable symbol found, place 2 for i=%d\n", i) 1296 } 1297 if ((i < 5) || (i > (nr - 5))) { 1298 LOG_PRINT(logfile, "\"%s\" ", svaltmp.c_str()) 1299 } else if (i == 5) { 1300 LOG_PRINT(logfile, "... ") 1301 } 1302 spreadSheets[spread].columns[(current_col - 1)].data.push_back(svaltmp); 1303 } 1304 } 1305 LOG_PRINT(logfile, "\n\n") 1306 datasets.push_back(spreadSheets[spread].columns.back()); 1307 } 1308 ++objectIndex; 1309 1310 return true; 1311 } 1312 1313 void OriginAnyParser::getMatrixValues(const string &col_data, unsigned int col_data_size, 1314 short data_type, char data_type_u, char valuesize, 1315 vector<Origin::Matrix>::difference_type mIndex) 1316 { 1317 if (matrixes.empty()) 1318 return; 1319 1320 istringstream stmp; 1321 stmp.str(col_data); 1322 1323 if (mIndex < 0) 1324 mIndex = (vector<Origin::Matrix>::difference_type)matrixes.size() - 1; 1325 1326 unsigned int size = col_data_size / valuesize; 1327 bool logValues = true; 1328 switch (data_type) { 1329 case 0x6001: // double 1330 for (unsigned int i = 0; i < size; ++i) { 1331 double value; 1332 GET_DOUBLE(stmp, value) 1333 matrixes[mIndex].sheets.back().data.push_back(value); 1334 } 1335 break; 1336 case 0x6003: // float 1337 for (unsigned int i = 0; i < size; ++i) { 1338 float value; 1339 GET_FLOAT(stmp, value) 1340 matrixes[mIndex].sheets.back().data.push_back((double)value); 1341 } 1342 break; 1343 case 0x6801: // int 1344 if (data_type_u == 8) { // unsigned 1345 for (unsigned int i = 0; i < size; ++i) { 1346 unsigned int value; 1347 GET_INT(stmp, value) 1348 matrixes[mIndex].sheets.back().data.push_back((double)value); 1349 } 1350 } else { 1351 for (unsigned int i = 0; i < size; ++i) { 1352 int value; 1353 GET_INT(stmp, value) 1354 matrixes[mIndex].sheets.back().data.push_back((double)value); 1355 } 1356 } 1357 break; 1358 case 0x6803: // short 1359 if (data_type_u == 8) { // unsigned 1360 for (unsigned int i = 0; i < size; ++i) { 1361 unsigned short value; 1362 GET_SHORT(stmp, value) 1363 matrixes[mIndex].sheets.back().data.push_back((double)value); 1364 } 1365 } else { 1366 for (unsigned int i = 0; i < size; ++i) { 1367 short value; 1368 GET_SHORT(stmp, value) 1369 matrixes[mIndex].sheets.back().data.push_back((double)value); 1370 } 1371 } 1372 break; 1373 case 0x6821: // char 1374 if (data_type_u == 8) { // unsigned 1375 for (unsigned int i = 0; i < size; ++i) { 1376 unsigned char value; 1377 value = col_data[i]; 1378 matrixes[mIndex].sheets.back().data.push_back((double)value); 1379 } 1380 } else { 1381 for (unsigned int i = 0; i < size; ++i) { 1382 char value; 1383 value = col_data[i]; 1384 matrixes[mIndex].sheets.back().data.push_back((double)value); 1385 } 1386 } 1387 break; 1388 default: 1389 LOG_PRINT(logfile, " UNKNOWN MATRIX DATATYPE: %02X SKIP DATA\n", data_type); 1390 matrixes.pop_back(); 1391 logValues = false; 1392 } 1393 1394 if (logValues) { 1395 LOG_PRINT(logfile, " FIRST 10 CELL VALUES: "); 1396 for (unsigned int i = 0; i < 10 && i < matrixes[mIndex].sheets.back().data.size(); ++i) 1397 LOG_PRINT(logfile, "%g\t", matrixes[mIndex].sheets.back().data[i]); 1398 } 1399 } 1400 1401 void OriginAnyParser::getWindowProperties(Origin::Window &window, const string &wde_header, 1402 unsigned int wde_header_size) 1403 { 1404 LOG_PRINT(logfile, "getWindowProperties()\n") 1405 window.objectID = objectIndex; 1406 ++objectIndex; 1407 1408 istringstream stmp; 1409 1410 stmp.str(wde_header.substr(0x1B)); 1411 GET_SHORT(stmp, window.frameRect.left) 1412 GET_SHORT(stmp, window.frameRect.top) 1413 GET_SHORT(stmp, window.frameRect.right) 1414 GET_SHORT(stmp, window.frameRect.bottom) 1415 1416 char c = wde_header[0x32]; 1417 1418 if (c & 0x01) 1419 window.state = Window::Minimized; 1420 else if (c & 0x02) 1421 window.state = Window::Maximized; 1422 1423 if (wde_header[0x42] != 0) { 1424 window.windowBackgroundColorGradient = (ColorGradientDirection)(wde_header[0x42] >> 2); 1425 window.windowBackgroundColorBase.type = Color::Regular; 1426 window.windowBackgroundColorBase.regular = wde_header[0x43]; 1427 window.windowBackgroundColorEnd.type = Color::Regular; 1428 window.windowBackgroundColorEnd.regular = wde_header[0x44]; 1429 } else { 1430 window.windowBackgroundColorGradient = ColorGradientDirection::NoGradient; 1431 window.windowBackgroundColorBase.type = Color::Regular; 1432 window.windowBackgroundColorBase.regular = Color::White; 1433 window.windowBackgroundColorEnd.type = Color::Regular; 1434 window.windowBackgroundColorEnd.regular = Color::White; 1435 } 1436 LOG_PRINT(logfile, "ColorGradient %d, base %d, end %d\n", window.windowBackgroundColorGradient, 1437 window.windowBackgroundColorBase.regular, window.windowBackgroundColorEnd.regular); 1438 1439 c = wde_header[0x69]; 1440 1441 if (c & 0x01) 1442 window.title = Window::Label; 1443 else if (c & 0x02) 1444 window.title = Window::Name; 1445 else 1446 window.title = Window::Both; 1447 1448 window.hidden = ((c & 0x08) != 0); 1449 if (window.hidden) { 1450 LOG_PRINT(logfile, " WINDOW %d NAME : %s is hidden\n", objectIndex, 1451 window.name.c_str()); 1452 } else { 1453 LOG_PRINT(logfile, " WINDOW %d NAME : %s is not hidden\n", 1454 objectIndex, window.name.c_str()); 1455 } 1456 1457 if (wde_header_size > 0x82) { 1458 // only projects of version 6.0 and higher have these 1459 double creationDate, modificationDate; 1460 stmp.str(wde_header.substr(0x73)); 1461 GET_DOUBLE(stmp, creationDate); 1462 window.creationDate = doubleToPosixTime(creationDate); 1463 GET_DOUBLE(stmp, modificationDate) 1464 window.modificationDate = doubleToPosixTime(modificationDate); 1465 } 1466 1467 if ((wde_header_size > 0x9E) && (wde_header[0x42] != 0)) { 1468 // get window background colors for version > 5.0 1469 window.windowBackgroundColorBase = getColor(wde_header.substr(0x97, 4)); 1470 window.windowBackgroundColorEnd = getColor(wde_header.substr(0x9B, 4)); 1471 } 1472 1473 if (wde_header_size > 0xC3) { 1474 window.label = wde_header.substr(0xC3).c_str(); 1475 window.label = window.label.substr(0, window.label.find("@${")); 1476 LOG_PRINT(logfile, " WINDOW %d LABEL: %s\n", objectIndex, 1477 window.label.c_str()); 1478 } 1479 1480 if (imatrix != -1) { // additional properties for matrix windows 1481 unsigned char h = wde_header[0x29]; 1482 matrixes[imatrix].activeSheet = h; 1483 if (wde_header_size > 0x86) { 1484 h = wde_header[0x87]; 1485 matrixes[imatrix].header = (h == 194) ? Matrix::XY : Matrix::ColumnRow; 1486 } 1487 } 1488 if (igraph != -1) { // additional properties for graph/layout windows 1489 stmp.str(wde_header.substr(0x23)); 1490 GET_SHORT(stmp, graphs[igraph].width) 1491 GET_SHORT(stmp, graphs[igraph].height) 1492 1493 unsigned char c = wde_header[0x38]; 1494 graphs[igraph].connectMissingData = ((c & 0x40) != 0); 1495 1496 string templateName = wde_header.substr(0x45, 20).c_str(); 1497 graphs[igraph].templateName = templateName; 1498 if (templateName == "LAYOUT") 1499 graphs[igraph].isLayout = true; 1500 } 1501 } 1502 1503 void OriginAnyParser::getLayerProperties(const string &lye_header, unsigned int lye_header_size) 1504 { 1505 LOG_PRINT(logfile, "getLayerProperties()\n") 1506 istringstream stmp; 1507 1508 if (ispread != -1) { // spreadsheet 1509 1510 spreadSheets[ispread].loose = false; 1511 1512 } else if (imatrix != -1) { // matrix 1513 1514 MatrixSheet &sheet = matrixes[imatrix].sheets[ilayer]; 1515 1516 unsigned short width = 8; 1517 stmp.str(lye_header.substr(0x27)); 1518 GET_SHORT(stmp, width) 1519 if (width == 0) 1520 width = 8; 1521 sheet.width = width; 1522 1523 stmp.str(lye_header.substr(0x2B)); 1524 GET_SHORT(stmp, sheet.columnCount) 1525 1526 stmp.str(lye_header.substr(0x52)); 1527 GET_SHORT(stmp, sheet.rowCount) 1528 1529 unsigned char view = lye_header[0x71]; 1530 if (view != 0x32 && view != 0x28) { 1531 sheet.view = MatrixSheet::ImageView; 1532 } else { 1533 sheet.view = MatrixSheet::DataView; 1534 } 1535 1536 if (lye_header_size > 0xD2) { 1537 sheet.name = lye_header.substr(0xD2, 32).c_str(); 1538 } 1539 1540 } else if (iexcel != -1) { // excel 1541 1542 excels[iexcel].loose = false; 1543 if (lye_header_size > 0xD2) { 1544 excels[iexcel].sheets[ilayer].name = lye_header.substr(0xD2, 32).c_str(); 1545 } 1546 1547 } else { // graph 1548 graphs[igraph].layers.push_back(GraphLayer()); 1549 GraphLayer &glayer = graphs[igraph].layers[ilayer]; 1550 1551 stmp.str(lye_header.substr(0x0F)); 1552 GET_DOUBLE(stmp, glayer.xAxis.min); 1553 GET_DOUBLE(stmp, glayer.xAxis.max); 1554 GET_DOUBLE(stmp, glayer.xAxis.step); 1555 1556 glayer.xAxis.majorTicks = lye_header[0x2B]; 1557 1558 unsigned char g = lye_header[0x2D]; 1559 glayer.xAxis.zeroLine = ((g & 0x80) != 0); 1560 glayer.xAxis.oppositeLine = ((g & 0x40) != 0); 1561 1562 glayer.xAxis.minorTicks = lye_header[0x37]; 1563 glayer.xAxis.scale = lye_header[0x38]; 1564 1565 stmp.str(lye_header.substr(0x3A)); 1566 GET_DOUBLE(stmp, glayer.yAxis.min); 1567 GET_DOUBLE(stmp, glayer.yAxis.max); 1568 GET_DOUBLE(stmp, glayer.yAxis.step); 1569 1570 glayer.yAxis.majorTicks = lye_header[0x56]; 1571 1572 g = lye_header[0x58]; 1573 glayer.yAxis.zeroLine = ((g & 0x80) != 0); 1574 glayer.yAxis.oppositeLine = ((g & 0x40) != 0); 1575 1576 glayer.yAxis.minorTicks = lye_header[0x62]; 1577 glayer.yAxis.scale = lye_header[0x63]; 1578 1579 g = lye_header[0x68]; 1580 glayer.gridOnTop = ((g & 0x04) != 0); 1581 glayer.exchangedAxes = ((g & 0x40) != 0); 1582 1583 stmp.str(lye_header.substr(0x71)); 1584 GET_SHORT(stmp, glayer.clientRect.left) 1585 GET_SHORT(stmp, glayer.clientRect.top) 1586 GET_SHORT(stmp, glayer.clientRect.right) 1587 GET_SHORT(stmp, glayer.clientRect.bottom) 1588 1589 unsigned char border = lye_header[0x89]; 1590 glayer.borderType = (BorderType)(border >= 0x80 ? border - 0x80 : None); 1591 1592 if (lye_header_size > 0x107) 1593 glayer.backgroundColor = getColor(lye_header.substr(0x105, 4)); 1594 } 1595 } 1596 1597 Origin::Color OriginAnyParser::getColor(const string &strbincolor) 1598 { 1599 /* decode a color value from a 4 byte binary string */ 1600 Origin::Color result{ Origin::Color::Regular, { Origin::Color::Black } }; 1601 unsigned char sbincolor[4]; 1602 for (int i = 0; i < 4; i++) { 1603 sbincolor[i] = strbincolor[i]; 1604 } 1605 switch (sbincolor[3]) { 1606 case 0: 1607 if (sbincolor[0] < 0x64) { 1608 result.regular = sbincolor[0]; 1609 } else { 1610 switch (sbincolor[2]) { 1611 case 0: 1612 result.type = Origin::Color::Indexing; 1613 break; 1614 case 0x40: 1615 result.type = Origin::Color::Mapping; 1616 break; 1617 case 0x80: 1618 result.type = Origin::Color::RGB; 1619 break; 1620 } 1621 result.column = sbincolor[0] - 0x64; 1622 } 1623 break; 1624 case 1: 1625 result.type = Origin::Color::Custom; 1626 for (int i = 0; i < 3; ++i) 1627 result.custom[i] = sbincolor[i]; 1628 break; 1629 case 0x20: 1630 result.type = Origin::Color::Increment; 1631 result.starting = sbincolor[1]; 1632 break; 1633 case 0xFF: 1634 if (sbincolor[0] == 0xFC) 1635 result.type = Origin::Color::None; 1636 else if (sbincolor[0] == 0xF7) 1637 result.type = Origin::Color::Automatic; 1638 else 1639 result.regular = sbincolor[0]; 1640 break; 1641 default: 1642 result.regular = sbincolor[0]; 1643 break; 1644 } 1645 return result; 1646 } 1647 1648 void OriginAnyParser::getAnnotationProperties(const string &anhd, unsigned int anhdsz, 1649 const string &andt1, unsigned int andt1sz, 1650 const string &andt2, unsigned int andt2sz, 1651 const string &andt3, unsigned int andt3sz) 1652 { 1653 LOG_PRINT(logfile, "getAnnotationProperties()\n") 1654 1655 /* LOG_PRINT(logfile, "anhd =") 1656 for (unsigned int i = 0; i < anhdsz; i++) 1657 LOG_PRINT(logfile, " %02x", anhd[i] & 0xFF); 1658 LOG_PRINT(logfile, "\n") 1659 LOG_PRINT(logfile, "andt1 =") 1660 for (unsigned int i = 0; i < andt1sz; i++) 1661 LOG_PRINT(logfile, " %02x", andt1[i] & 0xFF); 1662 LOG_PRINT(logfile, "\n") 1663 LOG_PRINT(logfile, "andt2 =") 1664 for (unsigned int i = 0; i < andt2sz; i++) 1665 LOG_PRINT(logfile, " %02x", andt2[i] & 0xFF); 1666 LOG_PRINT(logfile, "\n") 1667 LOG_PRINT(logfile, "andt3 =") 1668 for (unsigned int i = 0; i < andt3sz; i++) 1669 LOG_PRINT(logfile, " %02x", andt3[i] & 0xFF); 1670 LOG_PRINT(logfile, "\n") 1671 */ 1672 istringstream stmp; 1673 (void)anhdsz; 1674 (void)andt3; 1675 (void)andt3sz; 1676 1677 string sec_name = anhd.substr(0x46, 41).c_str(); 1678 1679 if (ispread != -1) { 1680 1681 int col_index = findColumnByName((int)ispread, sec_name); 1682 if (col_index != -1) { // check if it is a formula 1683 spreadSheets[ispread].columns[col_index].command = andt1.c_str(); 1684 LOG_PRINT(logfile, " Column: %s has formula: %s\n", 1685 sec_name.c_str(), spreadSheets[ispread].columns[col_index].command.c_str()) 1686 } 1687 1688 } else if (imatrix != -1) { 1689 1690 MatrixSheet &sheet = matrixes[imatrix].sheets[ilayer]; 1691 1692 stmp.str(andt1.c_str()); 1693 if (sec_name == "MV") { 1694 sheet.command = andt1.c_str(); 1695 } else if (sec_name == "Y2") { 1696 stmp >> sheet.coordinates[0]; 1697 } else if (sec_name == "X2") { 1698 stmp >> sheet.coordinates[1]; 1699 } else if (sec_name == "Y1") { 1700 stmp >> sheet.coordinates[2]; 1701 } else if (sec_name == "X1") { 1702 stmp >> sheet.coordinates[3]; 1703 } else if (sec_name == "COLORMAP") { 1704 // Color maps for matrix annotations are similar to color maps for graph curves (3D). 1705 // They differ only in the start offset to the data string. 1706 getColorMap(sheet.colorMap, andt2, andt2sz); 1707 } 1708 1709 } else if (iexcel != -1) { 1710 1711 vector<Origin::SpreadColumn>::difference_type col_index = 1712 findExcelColumnByName(iexcel, ilayer, sec_name); 1713 if (col_index != -1) { // check if it is a formula 1714 excels[iexcel].sheets[ilayer].columns[col_index].command = andt1.c_str(); 1715 } 1716 1717 } else { 1718 1719 GraphLayer &glayer = graphs[igraph].layers[ilayer]; 1720 1721 Rect r; 1722 stmp.str(anhd.substr(0x03)); 1723 GET_SHORT(stmp, r.left) 1724 GET_SHORT(stmp, r.top) 1725 GET_SHORT(stmp, r.right) 1726 GET_SHORT(stmp, r.bottom) 1727 1728 unsigned char attach = anhd[0x28]; 1729 LOG_PRINT(logfile, "attach = %02x\n", attach) 1730 bool shown = true; // axis title shown: attach = 0x22 1731 if (attach == 0x32) 1732 shown = false; 1733 1734 if (attach >= (unsigned char)Attach::End_) 1735 attach = Attach::Frame; 1736 unsigned char border = anhd[0x29]; 1737 1738 Color color = getColor(anhd.substr(0x33, 4)); 1739 1740 if (sec_name == "PL") 1741 glayer.yAxis.formatAxis[0].prefix = andt1.c_str(); 1742 if (sec_name == "PR") 1743 glayer.yAxis.formatAxis[1].prefix = andt1.c_str(); 1744 if (sec_name == "PB") 1745 glayer.xAxis.formatAxis[0].prefix = andt1.c_str(); 1746 if (sec_name == "PT") 1747 glayer.xAxis.formatAxis[1].prefix = andt1.c_str(); 1748 if (sec_name == "SL") 1749 glayer.yAxis.formatAxis[0].suffix = andt1.c_str(); 1750 if (sec_name == "SR") 1751 glayer.yAxis.formatAxis[1].suffix = andt1.c_str(); 1752 if (sec_name == "SB") 1753 glayer.xAxis.formatAxis[0].suffix = andt1.c_str(); 1754 if (sec_name == "ST") 1755 glayer.xAxis.formatAxis[1].suffix = andt1.c_str(); 1756 if (sec_name == "OL") 1757 glayer.yAxis.formatAxis[0].factor = andt1.c_str(); 1758 if (sec_name == "OR") 1759 glayer.yAxis.formatAxis[1].factor = andt1.c_str(); 1760 if (sec_name == "OB") 1761 glayer.xAxis.formatAxis[0].factor = andt1.c_str(); 1762 if (sec_name == "OT") 1763 glayer.xAxis.formatAxis[1].factor = andt1.c_str(); 1764 if (sec_name == "X1T") { 1765 glayer.xAxis.anchor = stod(andt1); 1766 LOG_PRINT(logfile, " x axis anchor = %g\n", glayer.xAxis.anchor) 1767 } 1768 if (sec_name == "Y1T") { 1769 glayer.yAxis.anchor = stod(andt1); 1770 LOG_PRINT(logfile, " y axis anchor = %g\n", glayer.yAxis.anchor) 1771 } 1772 if (sec_name == "Z1T") { 1773 glayer.zAxis.anchor = stod(andt1); 1774 LOG_PRINT(logfile, " z axis anchor = %g\n", glayer.zAxis.anchor) 1775 } 1776 1777 unsigned char type = andt1[0x00]; 1778 LineVertex begin, end; 1779 /* OriginNNNParser identify line/arrow annotation by checking size of andt1 1780 Origin410: 21||24; Origin 500: 24; Origin 610: 24||96; Origin700 and higher: 120; 1781 An alternative is to look at anhd[0x02]: 1782 (0x21 for Circle/Rect, 0x22 for Line/Arrow, 0x23 for Polygon/Polyline) 1783 */ 1784 unsigned char ankind = anhd[0x02]; 1785 if (ankind == 0x22) { // Line/Arrow 1786 if ((attach == Origin::Scale) && (andt1sz > 0x5F)) { 1787 if (type == 2) { 1788 stmp.str(andt1.substr(0x20)); 1789 GET_DOUBLE(stmp, begin.x) 1790 GET_DOUBLE(stmp, end.x) 1791 stmp.str(andt1.substr(0x40)); 1792 GET_DOUBLE(stmp, begin.y) 1793 GET_DOUBLE(stmp, end.y) 1794 } else if (type == 4) { // curved arrow: start point, 2 middle points and end point 1795 stmp.str(andt1.substr(0x20)); 1796 GET_DOUBLE(stmp, begin.x) 1797 GET_DOUBLE(stmp, end.x) 1798 GET_DOUBLE(stmp, end.x) 1799 GET_DOUBLE(stmp, end.x) 1800 GET_DOUBLE(stmp, begin.y) 1801 GET_DOUBLE(stmp, end.y) 1802 GET_DOUBLE(stmp, end.y) 1803 GET_DOUBLE(stmp, end.y) 1804 } 1805 } else { 1806 short x1 = 0, x2 = 0, y1 = 0, y2 = 0; 1807 if (type == 2) { // straight line/arrow 1808 stmp.str(andt1.substr(0x01)); 1809 GET_SHORT(stmp, x1) 1810 GET_SHORT(stmp, x2) 1811 stmp.seekg(4, ios_base::cur); 1812 GET_SHORT(stmp, y1) 1813 GET_SHORT(stmp, y2) 1814 } else if (type == 4) { // curved line/arrow has 4 points 1815 stmp.str(andt1.substr(0x01)); 1816 GET_SHORT(stmp, x1) 1817 stmp.seekg(4, ios_base::cur); 1818 GET_SHORT(stmp, x2) 1819 GET_SHORT(stmp, y1) 1820 stmp.seekg(4, ios_base::cur); 1821 GET_SHORT(stmp, y2) 1822 } 1823 1824 double dx = fabs(x2 - x1); 1825 double dy = fabs(y2 - y1); 1826 double minx = (x1 <= x2) ? x1 : x2; 1827 double miny = (y1 <= y2) ? y1 : y2; 1828 1829 begin.x = (x1 == x2) ? r.left + 0.5 * r.width() 1830 : r.left + (x1 - minx) / dx * r.width(); 1831 end.x = (x1 == x2) ? r.left + 0.5 * r.width() 1832 : r.left + (x2 - minx) / dx * r.width(); 1833 begin.y = (y1 == y2) ? r.top + 0.5 * r.height() 1834 : r.top + (y1 - miny) / dy * r.height(); 1835 end.y = (y1 == y2) ? r.top + 0.5 * r.height() 1836 : r.top + (y2 - miny) / dy * r.height(); 1837 } 1838 unsigned char arrows = 0; 1839 if (andt1sz > 0x11) { 1840 arrows = andt1[0x11]; 1841 switch (arrows) { 1842 case 0: 1843 begin.shapeType = 0; 1844 end.shapeType = 0; 1845 break; 1846 case 1: 1847 begin.shapeType = 1; 1848 end.shapeType = 0; 1849 break; 1850 case 2: 1851 begin.shapeType = 0; 1852 end.shapeType = 1; 1853 break; 1854 case 3: 1855 begin.shapeType = 1; 1856 end.shapeType = 1; 1857 break; 1858 } 1859 } 1860 if (andt1sz > 0x77) { 1861 begin.shapeType = andt1[0x60]; 1862 unsigned int w = 0; 1863 stmp.str(andt1.substr(0x64)); 1864 GET_INT(stmp, w) 1865 begin.shapeWidth = (double)w / 500.0; 1866 GET_INT(stmp, w) 1867 begin.shapeLength = (double)w / 500.0; 1868 1869 end.shapeType = andt1[0x6C]; 1870 stmp.str(andt1.substr(0x70)); 1871 GET_INT(stmp, w) 1872 end.shapeWidth = (double)w / 500.0; 1873 GET_INT(stmp, w) 1874 end.shapeLength = (double)w / 500.0; 1875 } 1876 } 1877 // text properties 1878 short rotation = 0; 1879 unsigned char fontSize = 12; 1880 if (andt1sz > 0x04) { 1881 stmp.str(andt1.substr(0x02)); 1882 GET_SHORT(stmp, rotation) 1883 fontSize = andt1[0x4]; 1884 } 1885 unsigned char tab = 8; 1886 if (andt1sz > 0x0A) 1887 tab = andt1[0x0A]; 1888 1889 // line properties 1890 unsigned char lineStyle = 0; 1891 if (andt1sz > 0x12) 1892 lineStyle = andt1[0x12]; 1893 unsigned short w1 = 0; 1894 if (andt1sz > 0x14) { 1895 stmp.str(andt1.substr(0x13)); 1896 GET_SHORT(stmp, w1) 1897 } 1898 double width = (double)w1 / 500.0; 1899 1900 Figure figure; 1901 if (andt1sz > 0x06) { 1902 stmp.str(andt1.substr(0x05)); 1903 GET_SHORT(stmp, w1) 1904 figure.width = (double)w1 / 500.0; 1905 } 1906 if (andt1sz > 0x08) 1907 figure.style = andt1[0x08]; 1908 1909 if (andt1sz > 0x4E) { 1910 figure.fillAreaColor = getColor(andt1.substr(0x42, 4)); 1911 stmp.str(andt1.substr(0x46)); 1912 GET_SHORT(stmp, w1) 1913 figure.fillAreaPatternWidth = (double)w1 / 500.0; 1914 figure.fillAreaPatternColor = getColor(andt1.substr(0x4A, 4)); 1915 figure.fillAreaPattern = andt1[0x4E]; 1916 } 1917 if (andt1sz > 0x57) { 1918 unsigned char h = andt1[0x57]; 1919 figure.useBorderColor = (h == 0x10); 1920 } 1921 1922 if (sec_name == "XB") { 1923 string text = andt2.c_str(); 1924 glayer.xAxis.position = GraphAxis::Bottom; 1925 glayer.xAxis.formatAxis[0].label = 1926 TextBox(text, r, color, fontSize, rotation / 10, tab, 1927 (BorderType)(border >= 0x80 ? border - 0x80 : None), (Attach)attach, shown); 1928 } else if (sec_name == "XT") { 1929 string text = andt2.c_str(); 1930 glayer.xAxis.position = GraphAxis::Top; 1931 glayer.xAxis.formatAxis[1].label = 1932 TextBox(text, r, color, fontSize, rotation / 10, tab, 1933 (BorderType)(border >= 0x80 ? border - 0x80 : None), (Attach)attach, shown); 1934 } else if (sec_name == "YL") { 1935 string text = andt2.c_str(); 1936 glayer.yAxis.position = GraphAxis::Left; 1937 glayer.yAxis.formatAxis[0].label = 1938 TextBox(text, r, color, fontSize, rotation / 10, tab, 1939 (BorderType)(border >= 0x80 ? border - 0x80 : None), (Attach)attach, shown); 1940 } else if (sec_name == "YR") { 1941 string text = andt2.c_str(); 1942 glayer.yAxis.position = GraphAxis::Right; 1943 glayer.yAxis.formatAxis[1].label = 1944 TextBox(text, r, color, fontSize, rotation / 10, tab, 1945 (BorderType)(border >= 0x80 ? border - 0x80 : None), (Attach)attach, shown); 1946 } else if (sec_name == "ZF") { 1947 string text = andt2.c_str(); 1948 glayer.zAxis.position = GraphAxis::Front; 1949 glayer.zAxis.formatAxis[0].label = 1950 TextBox(text, r, color, fontSize, rotation / 10, tab, 1951 (BorderType)(border >= 0x80 ? border - 0x80 : None), (Attach)attach, shown); 1952 } else if (sec_name == "ZB") { 1953 string text = andt2.c_str(); 1954 glayer.zAxis.position = GraphAxis::Back; 1955 glayer.zAxis.formatAxis[1].label = 1956 TextBox(text, r, color, fontSize, rotation / 10, tab, 1957 (BorderType)(border >= 0x80 ? border - 0x80 : None), (Attach)attach, shown); 1958 } else if (sec_name == "3D") { 1959 stmp.str(andt2); 1960 GET_DOUBLE(stmp, glayer.zAxis.min) 1961 GET_DOUBLE(stmp, glayer.zAxis.max) 1962 GET_DOUBLE(stmp, glayer.zAxis.step) 1963 glayer.zAxis.majorTicks = andt2[0x1C]; 1964 glayer.zAxis.minorTicks = andt2[0x28]; 1965 glayer.zAxis.scale = andt2[0x29]; 1966 1967 stmp.str(andt2.substr(0x5A)); 1968 GET_FLOAT(stmp, glayer.xAngle) 1969 GET_FLOAT(stmp, glayer.yAngle) 1970 GET_FLOAT(stmp, glayer.zAngle) 1971 1972 stmp.str(andt2.substr(0x218)); 1973 GET_FLOAT(stmp, glayer.xLength) 1974 GET_FLOAT(stmp, glayer.yLength) 1975 GET_FLOAT(stmp, glayer.zLength) 1976 glayer.xLength /= 23.0; 1977 glayer.yLength /= 23.0; 1978 glayer.zLength /= 23.0; 1979 1980 glayer.orthographic3D = (andt2[0x240] != 0); 1981 } else if ((sec_name == "Legend") || (sec_name == "legend")) { 1982 string text = andt2.c_str(); 1983 glayer.legend = 1984 TextBox(text, r, color, fontSize, rotation / 10, tab, 1985 (BorderType)(border >= 0x80 ? border - 0x80 : None), (Attach)attach); 1986 } else if (sec_name == "__BCO2") { // histogram 1987 stmp.str(andt2.substr(0x10)); 1988 GET_DOUBLE(stmp, glayer.histogramBin) 1989 stmp.str(andt2.substr(0x20)); 1990 GET_DOUBLE(stmp, glayer.histogramEnd) 1991 GET_DOUBLE(stmp, glayer.histogramBegin) 1992 1993 // TODO: check if 0x5E is right (obtained from anhdsz-0x46+93-andt1sz = 111-70+93-40 = 1994 // 94) 1995 glayer.percentile.p1SymbolType = andt2[0x5E]; 1996 glayer.percentile.p99SymbolType = andt2[0x5F]; 1997 glayer.percentile.meanSymbolType = andt2[0x60]; 1998 glayer.percentile.maxSymbolType = andt2[0x61]; 1999 glayer.percentile.minSymbolType = andt2[0x62]; 2000 2001 // 0x9F = 0x5E+65 2002 glayer.percentile.labels = andt2[0x9F]; 2003 // 0x6B = 0x5E+106-93 = 107 2004 glayer.percentile.whiskersRange = andt2[0x6B]; 2005 glayer.percentile.boxRange = andt2[0x6C]; 2006 // 0x8e = 0x5E+141-93 = 142 2007 glayer.percentile.whiskersCoeff = andt2[0x8e]; 2008 glayer.percentile.boxCoeff = andt2[0x8f]; 2009 unsigned char h = andt2[0x90]; 2010 glayer.percentile.diamondBox = (h == 0x82) ? true : false; 2011 // 0xCB = 0x5E+109 = 203 2012 stmp.str(andt2.substr(0xCB)); 2013 GET_SHORT(stmp, glayer.percentile.symbolSize) 2014 glayer.percentile.symbolSize = glayer.percentile.symbolSize / 2 + 1; 2015 // 0x101 = 0x5E+163 2016 glayer.percentile.symbolColor = getColor(andt2.substr(0x101, 4)); 2017 glayer.percentile.symbolFillColor = getColor(andt2.substr(0x105, 4)); 2018 } else if (sec_name == "_206") { // box plot labels 2019 } else if (sec_name == "VLine") { 2020 stmp.str(andt1.substr(0x0A)); 2021 double start; 2022 GET_DOUBLE(stmp, start) 2023 stmp.str(andt1.substr(0x1A)); 2024 double width; 2025 GET_DOUBLE(stmp, width) 2026 glayer.vLine = start + 0.5 * width; 2027 glayer.imageProfileTool = 2; 2028 } else if (sec_name == "HLine") { 2029 stmp.str(andt1.substr(0x12)); 2030 double start; 2031 GET_DOUBLE(stmp, start) 2032 stmp.str(andt1.substr(0x22)); 2033 double width; 2034 GET_DOUBLE(stmp, width) 2035 glayer.hLine = start + 0.5 * width; 2036 glayer.imageProfileTool = 2; 2037 } else if (sec_name == "vline") { 2038 stmp.str(andt1.substr(0x20)); 2039 GET_DOUBLE(stmp, glayer.vLine) 2040 glayer.imageProfileTool = 1; 2041 } else if (sec_name == "hline") { 2042 stmp.str(andt1.substr(0x40)); 2043 GET_DOUBLE(stmp, glayer.hLine) 2044 glayer.imageProfileTool = 1; 2045 } else if (sec_name == "ZCOLORS") { 2046 glayer.isXYY3D = true; 2047 if (fileVersion < 600) { 2048 ColorMap &colorMap = glayer.colorMap; 2049 getZcolorsMap(colorMap, andt2, andt2sz); 2050 } 2051 } else if (sec_name == "SPECTRUM1") { 2052 glayer.isXYY3D = false; 2053 glayer.colorScale.visible = true; 2054 glayer.colorScale.reverseOrder = (andt2[0x18] != 0); 2055 stmp.str(andt2.substr(0x20)); 2056 GET_SHORT(stmp, glayer.colorScale.colorBarThickness) 2057 GET_SHORT(stmp, glayer.colorScale.labelGap) 2058 glayer.colorScale.labelsColor = getColor(andt2.substr(0x5C, 4)); 2059 } else if (sec_name == "&0") { 2060 glayer.isWaterfall = true; 2061 string text = andt1.c_str(); 2062 string::size_type commaPos = text.find_first_of(","); 2063 stmp.str(text.substr(0, commaPos)); 2064 stmp >> glayer.xOffset; 2065 stmp.str(text.substr(commaPos + 1)); 2066 stmp >> glayer.yOffset; 2067 } 2068 /* OriginNNNParser identify text, circle, rectangle and bitmap annotation by checking size 2069 of andt1: text/pie text rectangle/circle line bitmap Origin410: 2070 22 0xA(10) 21/24 38 Origin500: 22 0xA(10) 24 2071 40 Origin610: 22 0xA(10) 24/96 40 Origin700: 2072 0x5E(94) 120 0x28(40) Origin750: 0x3E(62)/78 0x5E(94) 2073 0x78(120) 0x28(40) Origin850: 0x3E(62)/78 0x5E(94) 0x78(120) 0x28(40) An 2074 alternative is to look at anhd[0x02]: (0x00 for Text, 0x21 for Circle/Rect, 0x22 for 2075 Line/Arrow, 0x23 for Polygon/Polyline) 2076 */ 2077 else if ((ankind == 0x0) && (sec_name != "DelData")) { // text 2078 string text = andt2.c_str(); 2079 if (sec_name.substr(0, 3) == "PIE") 2080 glayer.pieTexts.push_back(TextBox( 2081 text, r, color, fontSize, rotation / 10, tab, 2082 (BorderType)(border >= 0x80 ? border - 0x80 : None), (Attach)attach)); 2083 else 2084 glayer.texts.push_back(TextBox(text, r, color, fontSize, rotation / 10, tab, 2085 (BorderType)(border >= 0x80 ? border - 0x80 : None), 2086 (Attach)attach)); 2087 } else if (ankind == 0x21) { // rectangle & circle 2088 switch (type) { // type = andt1[0x00] 2089 case 0: 2090 case 1: 2091 figure.type = Figure::Rectangle; 2092 break; 2093 case 2: 2094 case 3: 2095 figure.type = Figure::Circle; 2096 break; 2097 } 2098 figure.clientRect = r; 2099 figure.attach = (Attach)attach; 2100 figure.color = color; 2101 2102 glayer.figures.push_back(figure); 2103 } else if ((ankind == 0x22) && (sec_name != "sLine") 2104 && (sec_name != "sline")) { // line/arrow 2105 glayer.lines.push_back(Line()); 2106 Line &line(glayer.lines.back()); 2107 line.color = color; 2108 line.clientRect = r; 2109 line.attach = (Attach)attach; 2110 line.width = width; 2111 line.style = lineStyle; 2112 line.begin = begin; 2113 line.end = end; 2114 } else if (andt1sz == 40) { // bitmap 2115 if (type == 4) { // type = andt1[0x00] 2116 unsigned long filesize = andt2sz + 14; 2117 glayer.bitmaps.push_back(Bitmap()); 2118 Bitmap &bitmap(glayer.bitmaps.back()); 2119 bitmap.clientRect = r; 2120 bitmap.attach = (Attach)attach; 2121 bitmap.size = filesize; 2122 bitmap.borderType = (BorderType)(border >= 0x80 ? border - 0x80 : None); 2123 bitmap.data = new unsigned char[filesize]; 2124 unsigned char *data = bitmap.data; 2125 // add Bitmap header 2126 memcpy(data, "BM", 2); 2127 data += 2; 2128 memcpy(data, &filesize, 4); 2129 data += 4; 2130 unsigned int d = 0; 2131 memcpy(data, &d, 4); 2132 data += 4; 2133 d = 0x36; 2134 memcpy(data, &d, 4); 2135 data += 4; 2136 memcpy(data, andt2.c_str(), andt2sz); 2137 } else if (type == 6) { 2138 // TODO check if 0x5E is right (obtained from anhdsz-0x46+93-andt1sz = 111-70+93-40 2139 // = 94) 2140 string gname = andt2.substr(0x5E).c_str(); 2141 glayer.bitmaps.push_back(Bitmap(gname)); 2142 Bitmap &bitmap(glayer.bitmaps.back()); 2143 bitmap.clientRect = r; 2144 bitmap.attach = (Attach)attach; 2145 bitmap.size = 0; 2146 bitmap.borderType = (BorderType)(border >= 0x80 ? border - 0x80 : None); 2147 } 2148 } 2149 } 2150 return; 2151 } 2152 2153 void OriginAnyParser::getCurveProperties(const string &cvehd, unsigned int cvehdsz, 2154 const string &cvedt, unsigned int cvedtsz) 2155 { 2156 LOG_PRINT(logfile, "getCurveProperties()\n") 2157 istringstream stmp; 2158 2159 if (ispread != -1) { // spreadsheet: curves are columns 2160 2161 // TODO: check that spreadsheet columns are stored in proper order 2162 // vector<SpreadColumn> header; 2163 unsigned char c = cvehd[0x11]; 2164 string name = cvehd.substr(0x12).c_str(); 2165 unsigned short width = 0; 2166 if (cvehdsz > 0x4B) { 2167 stmp.str(cvehd.substr(0x4A)); 2168 GET_SHORT(stmp, width) 2169 } 2170 int col_index = findColumnByName((int)ispread, name); 2171 if (col_index != -1) { 2172 if (spreadSheets[ispread].columns[col_index].name != name) 2173 spreadSheets[ispread].columns[col_index].name = name; 2174 2175 SpreadColumn::ColumnType type; 2176 switch (c) { 2177 case 3: 2178 type = SpreadColumn::X; 2179 break; 2180 case 0: 2181 type = SpreadColumn::Y; 2182 break; 2183 case 5: 2184 type = SpreadColumn::Z; 2185 break; 2186 case 6: 2187 type = SpreadColumn::XErr; 2188 break; 2189 case 2: 2190 type = SpreadColumn::YErr; 2191 break; 2192 case 4: 2193 type = SpreadColumn::Label; 2194 break; 2195 default: 2196 type = SpreadColumn::NONE; 2197 break; 2198 } 2199 spreadSheets[ispread].columns[col_index].type = type; 2200 2201 width /= 0xA; 2202 if (width == 0) 2203 width = 8; 2204 spreadSheets[ispread].columns[col_index].width = width; 2205 unsigned char c1 = cvehd[0x1E]; 2206 unsigned char c2 = cvehd[0x1F]; 2207 switch (c1) { 2208 case 0x00: // Numeric - Dec1000 2209 case 0x09: // Text&Numeric - Dec1000 2210 case 0x10: // Numeric - Scientific 2211 case 0x19: // Text&Numeric - Scientific 2212 case 0x20: // Numeric - Engineering 2213 case 0x29: // Text&Numeric - Engineering 2214 case 0x30: // Numeric - Dec1,000 2215 case 0x39: // Text&Numeric - Dec1,000 2216 spreadSheets[ispread].columns[col_index].valueType = 2217 (c1 % 0x10 == 0x9) ? TextNumeric : Numeric; 2218 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c1 / 0x10; 2219 if (c2 >= 0x80) { 2220 spreadSheets[ispread].columns[col_index].significantDigits = c2 - 0x80; 2221 spreadSheets[ispread].columns[col_index].numericDisplayType = SignificantDigits; 2222 } else if (c2 > 0) { 2223 spreadSheets[ispread].columns[col_index].decimalPlaces = c2 - 0x03; 2224 spreadSheets[ispread].columns[col_index].numericDisplayType = DecimalPlaces; 2225 } 2226 break; 2227 case 0x02: // Time 2228 spreadSheets[ispread].columns[col_index].valueType = Time; 2229 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2 - 0x80; 2230 break; 2231 case 0x03: // Date 2232 case 0x33: 2233 spreadSheets[ispread].columns[col_index].valueType = Date; 2234 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2 - 0x80; 2235 break; 2236 case 0x31: // Text 2237 spreadSheets[ispread].columns[col_index].valueType = Text; 2238 break; 2239 case 0x4: // Month 2240 case 0x34: 2241 spreadSheets[ispread].columns[col_index].valueType = Month; 2242 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2; 2243 break; 2244 case 0x5: // Day 2245 case 0x35: 2246 spreadSheets[ispread].columns[col_index].valueType = Day; 2247 spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2; 2248 break; 2249 default: // Text 2250 spreadSheets[ispread].columns[col_index].valueType = Text; 2251 break; 2252 } 2253 if (cvedtsz > 0) { 2254 spreadSheets[ispread].columns[col_index].comment = cvedt.c_str(); 2255 } 2256 // TODO: check that spreadsheet columns are stored in proper order 2257 // header.push_back(spreadSheets[ispread].columns[col_index]); 2258 } 2259 // TODO: check that spreadsheet columns are stored in proper order 2260 // for (unsigned int i = 0; i < header.size(); i++) 2261 // spreadSheets[spread].columns[i] = header[i]; 2262 2263 } else if (imatrix != -1) { 2264 2265 MatrixSheet sheet = matrixes[imatrix].sheets[ilayer]; 2266 unsigned char c1 = cvehd[0x1E]; 2267 unsigned char c2 = cvehd[0x1F]; 2268 2269 sheet.valueTypeSpecification = c1 / 0x10; 2270 if (c2 >= 0x80) { 2271 sheet.significantDigits = c2 - 0x80; 2272 sheet.numericDisplayType = SignificantDigits; 2273 } else if (c2 > 0) { 2274 sheet.decimalPlaces = c2 - 0x03; 2275 sheet.numericDisplayType = DecimalPlaces; 2276 } 2277 2278 matrixes[imatrix].sheets[ilayer] = sheet; 2279 2280 } else if (iexcel != -1) { 2281 2282 unsigned char c = cvehd[0x11]; 2283 string name = cvehd.substr(0x12).c_str(); 2284 unsigned short width = 0; 2285 stmp.str(cvehd.substr(0x4A)); 2286 GET_SHORT(stmp, width) 2287 unsigned short dataID = 0; 2288 stmp.str(cvehd.substr(0x04)); 2289 GET_SHORT(stmp, dataID) 2290 2291 unsigned int isheet = datasets[dataID - 1].sheet; 2292 vector<Origin::SpreadColumn>::difference_type col_index = 2293 findExcelColumnByName(iexcel, isheet, name); 2294 if (col_index != -1) { 2295 SpreadColumn::ColumnType type; 2296 switch (c) { 2297 case 3: 2298 type = SpreadColumn::X; 2299 break; 2300 case 0: 2301 type = SpreadColumn::Y; 2302 break; 2303 case 5: 2304 type = SpreadColumn::Z; 2305 break; 2306 case 6: 2307 type = SpreadColumn::XErr; 2308 break; 2309 case 2: 2310 type = SpreadColumn::YErr; 2311 break; 2312 case 4: 2313 type = SpreadColumn::Label; 2314 break; 2315 default: 2316 type = SpreadColumn::NONE; 2317 break; 2318 } 2319 excels[iexcel].sheets[isheet].columns[col_index].type = type; 2320 width /= 0xA; 2321 if (width == 0) 2322 width = 8; 2323 excels[iexcel].sheets[isheet].columns[col_index].width = width; 2324 2325 unsigned char c1 = cvehd[0x1E]; 2326 unsigned char c2 = cvehd[0x1F]; 2327 switch (c1) { 2328 case 0x00: // Numeric - Dec1000 2329 case 0x09: // Text&Numeric - Dec1000 2330 case 0x10: // Numeric - Scientific 2331 case 0x19: // Text&Numeric - Scientific 2332 case 0x20: // Numeric - Engineering 2333 case 0x29: // Text&Numeric - Engineering 2334 case 0x30: // Numeric - Dec1,000 2335 case 0x39: // Text&Numeric - Dec1,000 2336 excels[iexcel].sheets[isheet].columns[col_index].valueType = 2337 (c1 % 0x10 == 0x9) ? TextNumeric : Numeric; 2338 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c1 / 0x10; 2339 if (c2 >= 0x80) { 2340 excels[iexcel].sheets[isheet].columns[col_index].significantDigits = c2 - 0x80; 2341 excels[iexcel].sheets[isheet].columns[col_index].numericDisplayType = 2342 SignificantDigits; 2343 } else if (c2 > 0) { 2344 excels[iexcel].sheets[isheet].columns[col_index].decimalPlaces = c2 - 0x03; 2345 excels[iexcel].sheets[isheet].columns[col_index].numericDisplayType = 2346 DecimalPlaces; 2347 } 2348 break; 2349 case 0x02: // Time 2350 excels[iexcel].sheets[isheet].columns[col_index].valueType = Time; 2351 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2 - 0x80; 2352 break; 2353 case 0x03: // Date 2354 excels[iexcel].sheets[isheet].columns[col_index].valueType = Date; 2355 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2 - 0x80; 2356 break; 2357 case 0x31: // Text 2358 excels[iexcel].sheets[isheet].columns[col_index].valueType = Text; 2359 break; 2360 case 0x04: // Month 2361 case 0x34: 2362 excels[iexcel].sheets[isheet].columns[col_index].valueType = Month; 2363 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2; 2364 break; 2365 case 0x05: // Day 2366 case 0x35: 2367 excels[iexcel].sheets[isheet].columns[col_index].valueType = Day; 2368 excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2; 2369 break; 2370 default: // Text 2371 excels[iexcel].sheets[isheet].columns[col_index].valueType = Text; 2372 break; 2373 } 2374 if (cvedtsz > 0) { 2375 excels[iexcel].sheets[isheet].columns[col_index].comment = cvedt.c_str(); 2376 } 2377 } 2378 2379 } else { 2380 2381 GraphLayer &glayer = graphs[igraph].layers[ilayer]; 2382 glayer.curves.push_back(GraphCurve()); 2383 GraphCurve &curve(glayer.curves.back()); 2384 2385 unsigned char h = cvehd[0x26]; 2386 curve.hidden = (h == 33); 2387 curve.type = cvehd[0x4C]; 2388 if (curve.type == GraphCurve::XYZContour || curve.type == GraphCurve::Contour) 2389 glayer.isXYY3D = false; 2390 2391 unsigned short w; 2392 stmp.str(cvehd.substr(0x04)); 2393 GET_SHORT(stmp, w) 2394 pair<string, string> column = findDataByIndex(w - 1); 2395 short nColY = w; 2396 if (column.first.size() > 0) { 2397 curve.dataName = column.first; 2398 if (glayer.is3D() || (curve.type == GraphCurve::XYZContour)) { 2399 curve.zColumnName = column.second; 2400 } else { 2401 curve.yColumnName = column.second; 2402 } 2403 } 2404 2405 stmp.str(cvehd.substr(0x23)); 2406 GET_SHORT(stmp, w) 2407 column = findDataByIndex(w - 1); 2408 if (column.first.size() > 0) { 2409 curve.xDataName = (curve.dataName != column.first) ? column.first : string(); 2410 if (glayer.is3D() || (curve.type == GraphCurve::XYZContour)) { 2411 curve.yColumnName = column.second; 2412 } else if (glayer.isXYY3D) { 2413 curve.xColumnName = column.second; 2414 } else { 2415 curve.xColumnName = column.second; 2416 } 2417 } 2418 2419 if (cvehdsz > 0x4E) { 2420 stmp.str(cvehd.substr(0x4D)); 2421 GET_SHORT(stmp, w) 2422 column = findDataByIndex(w - 1); 2423 if (column.first.size() > 0 2424 && (glayer.is3D() || (curve.type == GraphCurve::XYZContour))) { 2425 curve.xColumnName = column.second; 2426 if (curve.dataName != column.first) { 2427 // graph X and Y from different tables 2428 } 2429 } 2430 } 2431 2432 if (glayer.is3D() || glayer.isXYY3D) 2433 graphs[igraph].is3D = true; 2434 2435 curve.lineConnect = cvehd[0x11]; 2436 curve.lineStyle = cvehd[0x12]; 2437 curve.boxWidth = cvehd[0x14]; 2438 2439 stmp.str(cvehd.substr(0x15)); 2440 GET_SHORT(stmp, w) 2441 curve.lineWidth = (double)w / 500.0; 2442 2443 curve.symbolShape = cvehd[0x17]; 2444 curve.symbolInterior = cvehd[0x18]; 2445 2446 stmp.str(cvehd.substr(0x19)); 2447 GET_SHORT(stmp, w) 2448 curve.symbolSize = (double)w / 500.0; 2449 2450 h = cvehd[0x1C]; 2451 curve.fillArea = (h == 2); 2452 curve.fillAreaType = cvehd[0x1E]; 2453 2454 // text 2455 if (curve.type == GraphCurve::TextPlot) { 2456 stmp.str(cvehd.substr(0x13)); 2457 GET_SHORT(stmp, curve.text.rotation) 2458 curve.text.rotation /= 10; 2459 GET_SHORT(stmp, curve.text.fontSize) 2460 2461 h = cvehd[0x19]; 2462 switch (h) { 2463 case 26: 2464 curve.text.justify = TextProperties::Center; 2465 break; 2466 case 2: 2467 curve.text.justify = TextProperties::Right; 2468 break; 2469 default: 2470 curve.text.justify = TextProperties::Left; 2471 break; 2472 } 2473 2474 h = cvehd[0x20]; 2475 curve.text.fontUnderline = ((h & 0x1) != 0); 2476 curve.text.fontItalic = ((h & 0x2) != 0); 2477 curve.text.fontBold = ((h & 0x8) != 0); 2478 curve.text.whiteOut = ((h & 0x20) != 0); 2479 2480 char offset = cvehd[0x37]; 2481 curve.text.xOffset = offset * 5; 2482 offset = cvehd[0x38]; 2483 curve.text.yOffset = offset * 5; 2484 } 2485 2486 // vector 2487 if (curve.type == GraphCurve::FlowVector || curve.type == GraphCurve::Vector) { 2488 stmp.str(cvehd.substr(0x56)); 2489 GET_FLOAT(stmp, curve.vector.multiplier) 2490 2491 h = cvehd[0x5E]; 2492 column = findDataByIndex(nColY - 1 + h - 0x64); 2493 if (column.first.size() > 0) 2494 curve.vector.endXColumnName = column.second; 2495 2496 h = cvehd[0x62]; 2497 column = findDataByIndex(nColY - 1 + h - 0x64); 2498 if (column.first.size() > 0) 2499 curve.vector.endYColumnName = column.second; 2500 2501 h = cvehd[0x18]; 2502 if (h >= 0x64) { 2503 column = findDataByIndex(nColY - 1 + h - 0x64); 2504 if (column.first.size() > 0) 2505 curve.vector.angleColumnName = column.second; 2506 } else if (h <= 0x08) 2507 curve.vector.constAngle = 45 * h; 2508 2509 h = cvehd[0x19]; 2510 if (h >= 0x64) { 2511 column = findDataByIndex(nColY - 1 + h - 0x64); 2512 if (column.first.size() > 0) 2513 curve.vector.magnitudeColumnName = column.second; 2514 } else 2515 curve.vector.constMagnitude = (int)curve.symbolSize; 2516 2517 stmp.str(cvehd.substr(0x66)); 2518 GET_SHORT(stmp, curve.vector.arrowLength) 2519 curve.vector.arrowAngle = cvehd[0x68]; 2520 2521 h = cvehd[0x69]; 2522 curve.vector.arrowClosed = !(h & 0x1); 2523 2524 stmp.str(cvehd.substr(0x70)); 2525 GET_SHORT(stmp, w) 2526 curve.vector.width = (double)w / 500.0; 2527 2528 h = cvehd[0x142]; 2529 switch (h) { 2530 case 2: 2531 curve.vector.position = VectorProperties::Midpoint; 2532 break; 2533 case 4: 2534 curve.vector.position = VectorProperties::Head; 2535 break; 2536 default: 2537 curve.vector.position = VectorProperties::Tail; 2538 break; 2539 } 2540 } 2541 // pie 2542 if (curve.type == GraphCurve::Pie) { 2543 // code from Origin410/500Parser 2544 h = cvehd[0x14]; 2545 curve.pie.formatPercentages = ((h & 0x08) != 0); 2546 curve.pie.formatValues = !curve.pie.formatPercentages; 2547 curve.pie.positionAssociate = ((h & 0x80) != 0); 2548 curve.pie.formatCategories = ((h & 0x20) != 0); 2549 2550 h = cvehd[0x19]; 2551 curve.pie.radius = 100 - h; 2552 2553 h = cvehd[0x1A]; 2554 curve.pie.distance = h; 2555 curve.pie.formatAutomatic = true; 2556 curve.pie.viewAngle = 90; 2557 curve.pie.thickness = 33; 2558 curve.pie.rotation = 0; 2559 curve.pie.horizontalOffset = 0; 2560 2561 if (cvehdsz > 0xA9) { // code from Origin750Parser.cpp 2562 2563 h = cvehd[0x92]; 2564 curve.pie.formatPercentages = ((h & 0x01) != 0); 2565 curve.pie.formatValues = ((h & 0x02) != 0); 2566 curve.pie.positionAssociate = ((h & 0x08) != 0); 2567 curve.pie.clockwiseRotation = ((h & 0x20) != 0); 2568 curve.pie.formatCategories = ((h & 0x80) != 0); 2569 2570 curve.pie.formatAutomatic = (cvehd[0x93] != 0); 2571 stmp.str(cvehd.substr(0x94)); 2572 GET_SHORT(stmp, curve.pie.distance) 2573 curve.pie.viewAngle = cvehd[0x96]; 2574 curve.pie.thickness = cvehd[0x98]; 2575 2576 stmp.str(cvehd.substr(0x9A)); 2577 GET_SHORT(stmp, curve.pie.rotation) 2578 2579 stmp.str(cvehd.substr(0x9E)); 2580 GET_SHORT(stmp, curve.pie.displacement) 2581 2582 stmp.str(cvehd.substr(0xA0)); 2583 GET_SHORT(stmp, curve.pie.radius) 2584 GET_SHORT(stmp, curve.pie.horizontalOffset) 2585 2586 stmp.str(cvehd.substr(0xA6)); 2587 GET_INT(stmp, curve.pie.displacedSectionCount) 2588 } 2589 } 2590 // surface 2591 if (glayer.isXYY3D || curve.type == GraphCurve::Mesh3D) { 2592 curve.surface.type = cvehd[0x17]; 2593 h = cvehd[0x1C]; 2594 if ((h & 0x60) == 0x60) 2595 curve.surface.grids = SurfaceProperties::X; 2596 else if (h & 0x20) 2597 curve.surface.grids = SurfaceProperties::Y; 2598 else if (h & 0x40) 2599 curve.surface.grids = SurfaceProperties::None; 2600 else 2601 curve.surface.grids = SurfaceProperties::XY; 2602 2603 curve.surface.sideWallEnabled = ((h & 0x10) != 0); 2604 curve.surface.frontColor = getColor(cvehd.substr(0x1D, 4)); 2605 2606 h = cvehd[0x13]; 2607 curve.surface.backColorEnabled = ((h & 0x08) != 0); 2608 curve.surface.surface.fill = ((h & 0x10) != 0); 2609 curve.surface.surface.contour = ((h & 0x40) != 0); 2610 curve.surface.topContour.fill = ((h & 0x02) != 0); 2611 curve.surface.topContour.contour = ((h & 0x04) != 0); 2612 curve.surface.bottomContour.fill = ((h & 0x80) != 0); 2613 curve.surface.bottomContour.contour = ((h & 0x01) != 0); 2614 2615 if (cvehdsz > 0x165) { 2616 stmp.str(cvehd.substr(0x14C)); 2617 GET_SHORT(stmp, w) 2618 curve.surface.gridLineWidth = (double)w / 500.0; 2619 curve.surface.gridColor = getColor(cvehd.substr(0x14E, 4)); 2620 curve.surface.backColor = getColor(cvehd.substr(0x15A, 4)); 2621 curve.surface.xSideWallColor = getColor(cvehd.substr(0x15E, 4)); 2622 curve.surface.ySideWallColor = getColor(cvehd.substr(0x162, 4)); 2623 } 2624 if (cvehdsz > 0xA9) { 2625 stmp.str(cvehd.substr(0x94)); 2626 GET_SHORT(stmp, w) 2627 curve.surface.surface.lineWidth = (double)w / 500.0; 2628 curve.surface.surface.lineColor = getColor(cvehd.substr(0x96, 4)); 2629 2630 stmp.str(cvehd.substr(0xB4)); 2631 GET_SHORT(stmp, w) 2632 curve.surface.topContour.lineWidth = (double)w / 500.0; 2633 curve.surface.topContour.lineColor = getColor(cvehd.substr(0xB6, 4)); 2634 2635 stmp.str(cvehd.substr(0xA4)); 2636 GET_SHORT(stmp, w) 2637 curve.surface.bottomContour.lineWidth = (double)w / 500.0; 2638 curve.surface.bottomContour.lineColor = getColor(cvehd.substr(0xA6, 4)); 2639 } 2640 } 2641 if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour 2642 || curve.type == GraphCurve::XYZContour) { 2643 if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) 2644 glayer.isXYY3D = false; 2645 ColorMap &colorMap = 2646 (curve.type == GraphCurve::Mesh3D ? curve.surface.colorMap : curve.colorMap); 2647 h = cvehd[0x13]; 2648 colorMap.fillEnabled = ((h & 0x82) != 0); 2649 2650 if ((curve.type == GraphCurve::Contour) && (cvehdsz > 0x89)) { 2651 stmp.str(cvehd.substr(0x7A)); 2652 GET_SHORT(stmp, curve.text.fontSize) 2653 2654 h = cvehd[0x83]; 2655 curve.text.fontUnderline = ((h & 0x1) != 0); 2656 curve.text.fontItalic = ((h & 0x2) != 0); 2657 curve.text.fontBold = ((h & 0x8) != 0); 2658 curve.text.whiteOut = ((h & 0x20) != 0); 2659 2660 curve.text.color = getColor(cvehd.substr(0x86, 4)); 2661 } 2662 if (cvedtsz > 0x6C) { 2663 getColorMap(colorMap, cvedt, cvedtsz); 2664 } else { 2665 colorMap = glayer.colorMap; 2666 } 2667 } 2668 2669 if (fileVersion >= 850) { 2670 curve.lineTransparency = cvehd[0x9C]; 2671 h = cvehd[0x9D]; 2672 curve.fillAreaWithLineTransparency = !h; 2673 curve.fillAreaTransparency = cvehd[0x11E]; 2674 } else { 2675 // use sensible default values 2676 curve.fillAreaWithLineTransparency = false; 2677 curve.fillAreaTransparency = 255; 2678 } 2679 2680 if (cvehdsz > 0x143) { 2681 curve.fillAreaColor = getColor(cvehd.substr(0xC2, 4)); 2682 stmp.str(cvehd.substr(0xC6)); 2683 GET_SHORT(stmp, w) 2684 curve.fillAreaPatternWidth = (double)w / 500.0; 2685 2686 curve.fillAreaPatternColor = getColor(cvehd.substr(0xCA, 4)); 2687 curve.fillAreaPattern = cvehd[0xCE]; 2688 curve.fillAreaPatternBorderStyle = cvehd[0xCF]; 2689 stmp.str(cvehd.substr(0xD0)); 2690 GET_SHORT(stmp, w) 2691 curve.fillAreaPatternBorderWidth = (double)w / 500.0; 2692 curve.fillAreaPatternBorderColor = getColor(cvehd.substr(0xD2, 4)); 2693 2694 curve.fillAreaTransparency = cvehd[0x11E]; 2695 2696 curve.lineColor = getColor(cvehd.substr(0x16A, 4)); 2697 2698 if (curve.type != GraphCurve::Contour) 2699 curve.text.color = curve.lineColor; 2700 2701 curve.symbolFillColor = getColor(cvehd.substr(0x12E, 4)); 2702 curve.symbolColor = getColor(cvehd.substr(0x132, 4)); 2703 curve.vector.color = curve.symbolColor; 2704 2705 h = cvehd[0x136]; 2706 curve.symbolThickness = (h == 255 ? 1 : h); 2707 curve.pointOffset = cvehd[0x137]; 2708 h = cvehd[0x138]; 2709 curve.symbolFillTransparency = cvehd[0x139]; 2710 2711 h = cvehd[0x143]; 2712 curve.connectSymbols = ((h & 0x8) != 0); 2713 } 2714 } 2715 } 2716 2717 void OriginAnyParser::getAxisBreakProperties(const string &abdata, unsigned int abdatasz) 2718 { 2719 LOG_PRINT(logfile, "getAxisBreakProperties()\n") 2720 istringstream stmp; 2721 (void)abdatasz; 2722 2723 if (ispread != -1) { // spreadsheet 2724 2725 } else if (imatrix != -1) { // matrix 2726 2727 } else if (iexcel != -1) { // excel 2728 2729 } else { // graph 2730 2731 GraphLayer &glayer = graphs[igraph].layers[ilayer]; 2732 unsigned char h = abdata[0x02]; 2733 if (h == 2) { 2734 glayer.xAxisBreak.minorTicksBefore = glayer.xAxis.minorTicks; 2735 glayer.xAxisBreak.scaleIncrementBefore = glayer.xAxis.step; 2736 glayer.xAxisBreak.show = true; 2737 stmp.str(abdata.substr(0x0B)); 2738 GET_DOUBLE(stmp, glayer.xAxisBreak.from) 2739 GET_DOUBLE(stmp, glayer.xAxisBreak.to) 2740 GET_DOUBLE(stmp, glayer.xAxisBreak.scaleIncrementAfter) 2741 GET_DOUBLE(stmp, glayer.xAxisBreak.position) 2742 h = abdata[0x2B]; 2743 glayer.xAxisBreak.log10 = (h == 1); 2744 glayer.xAxisBreak.minorTicksAfter = abdata[0x2C]; 2745 } else if (h == 4) { 2746 glayer.yAxisBreak.minorTicksBefore = glayer.yAxis.minorTicks; 2747 glayer.yAxisBreak.scaleIncrementBefore = glayer.yAxis.step; 2748 glayer.yAxisBreak.show = true; 2749 stmp.str(abdata.substr(0x0B)); 2750 GET_DOUBLE(stmp, glayer.yAxisBreak.from) 2751 GET_DOUBLE(stmp, glayer.yAxisBreak.to) 2752 GET_DOUBLE(stmp, glayer.yAxisBreak.scaleIncrementAfter) 2753 GET_DOUBLE(stmp, glayer.yAxisBreak.position) 2754 h = abdata[0x2B]; 2755 glayer.yAxisBreak.log10 = (h == 1); 2756 glayer.yAxisBreak.minorTicksAfter = abdata[0x2C]; 2757 } 2758 } 2759 } 2760 2761 void OriginAnyParser::getAxisParameterProperties(const string &apdata, unsigned int apdatasz, 2762 int naxis) 2763 { 2764 LOG_PRINT(logfile, "getAxisParameterProperties()\n") 2765 istringstream stmp; 2766 static int iaxispar = 0; 2767 2768 if (igraph != -1) { 2769 unsigned char h = 0; 2770 unsigned short w = 0; 2771 2772 GraphLayer &glayer = graphs[igraph].layers[ilayer]; 2773 GraphAxis axis = glayer.xAxis; 2774 if (naxis == 1) { 2775 axis = glayer.xAxis; 2776 } else if (naxis == 2) { 2777 axis = glayer.yAxis; 2778 } else if (naxis == 3) { 2779 axis = glayer.zAxis; 2780 } 2781 if (iaxispar == 0) { // minor Grid 2782 h = apdata[0x26]; 2783 axis.minorGrid.hidden = (h == 0); 2784 axis.minorGrid.color = apdata[0x0F]; 2785 axis.minorGrid.style = apdata[0x12]; 2786 stmp.str(apdata.substr(0x15)); 2787 GET_SHORT(stmp, w) 2788 axis.minorGrid.width = (double)w / 500.0; 2789 } else if (iaxispar == 1) { // major Grid 2790 h = apdata[0x26]; 2791 axis.majorGrid.hidden = (h == 0); 2792 axis.majorGrid.color = apdata[0x0F]; 2793 axis.majorGrid.style = apdata[0x12]; 2794 stmp.str(apdata.substr(0x15)); 2795 GET_SHORT(stmp, w) 2796 axis.majorGrid.width = (double)w / 500.0; 2797 } else if (iaxispar == 2) { // tickaxis 0 2798 h = apdata[0x26]; 2799 axis.tickAxis[0].showMajorLabels = ((h & 0x40) != 0); 2800 axis.tickAxis[0].color = apdata[0x0F]; 2801 stmp.str(apdata.substr(0x13)); 2802 GET_SHORT(stmp, w) 2803 axis.tickAxis[0].rotation = w / 10; 2804 GET_SHORT(stmp, w) 2805 axis.tickAxis[0].fontSize = w; 2806 h = apdata[0x1A]; 2807 axis.tickAxis[0].fontBold = ((h & 0x08) != 0); 2808 stmp.str(apdata.substr(0x23)); 2809 GET_SHORT(stmp, w) 2810 h = apdata[0x25]; 2811 unsigned char h1 = apdata[0x26]; 2812 axis.tickAxis[0].valueType = (ValueType)(h & 0x0F); 2813 pair<string, string> column; 2814 switch (axis.tickAxis[0].valueType) { 2815 case Numeric: 2816 /*switch ((h>>4)) { 2817 case 0x9: 2818 axis.tickAxis[0].valueTypeSpecification=1; 2819 break; 2820 case 0xA: 2821 axis.tickAxis[0].valueTypeSpecification=2; 2822 break; 2823 case 0xB: 2824 axis.tickAxis[0].valueTypeSpecification=3; 2825 break; 2826 default: 2827 axis.tickAxis[0].valueTypeSpecification=0; 2828 }*/ 2829 if ((h >> 4) > 7) { 2830 axis.tickAxis[0].valueTypeSpecification = (h >> 4) - 8; 2831 axis.tickAxis[0].decimalPlaces = h1 - 0x40; 2832 } else { 2833 axis.tickAxis[0].valueTypeSpecification = (h >> 4); 2834 axis.tickAxis[0].decimalPlaces = -1; 2835 } 2836 break; 2837 case Time: 2838 case Date: 2839 case Month: 2840 case Day: 2841 case ColumnHeading: 2842 axis.tickAxis[0].valueTypeSpecification = h1 - 0x40; 2843 break; 2844 case Text: 2845 case TickIndexedDataset: 2846 case Categorical: 2847 column = findDataByIndex(w - 1); 2848 if (column.first.size() > 0) { 2849 axis.tickAxis[0].dataName = column.first; 2850 axis.tickAxis[0].columnName = column.second; 2851 } 2852 break; 2853 case TextNumeric: // Numeric Decimal 1.000 2854 axis.tickAxis[0].valueType = Numeric; 2855 axis.tickAxis[0].valueTypeSpecification = 0; 2856 break; 2857 } 2858 } else if (iaxispar == 3) { // formataxis 0 2859 h = apdata[0x26]; 2860 axis.formatAxis[0].hidden = (h == 0); 2861 axis.formatAxis[0].color = apdata[0x0F]; 2862 if (apdatasz > 0x4B) { 2863 stmp.str(apdata.substr(0x4A)); 2864 GET_SHORT(stmp, w) 2865 axis.formatAxis[0].majorTickLength = (double)w / 10.0; 2866 } 2867 stmp.str(apdata.substr(0x15)); 2868 GET_SHORT(stmp, w) 2869 axis.formatAxis[0].thickness = (double)w / 500.0; 2870 h = apdata[0x25]; 2871 axis.formatAxis[0].minorTicksType = (h >> 6); 2872 axis.formatAxis[0].majorTicksType = ((h >> 4) & 3); 2873 axis.formatAxis[0].axisPosition = (h & 0x0F); 2874 short w1 = 0; 2875 switch (axis.formatAxis[0].axisPosition) { // TODO: check if correct 2876 case 1: 2877 stmp.str(apdata.substr(0x37)); 2878 GET_SHORT(stmp, w1) 2879 axis.formatAxis[0].axisPositionValue = (double)w1; 2880 break; 2881 case 2: 2882 stmp.str(apdata.substr(0x2F)); 2883 GET_DOUBLE(stmp, axis.formatAxis[0].axisPositionValue) 2884 break; 2885 } 2886 } else if (iaxispar == 4) { // tickaxis 1 2887 h = apdata[0x26]; 2888 axis.tickAxis[1].showMajorLabels = ((h & 0x40) != 0); 2889 axis.tickAxis[1].color = apdata[0x0F]; 2890 stmp.str(apdata.substr(0x13)); 2891 GET_SHORT(stmp, w) 2892 axis.tickAxis[1].rotation = w / 10; 2893 GET_SHORT(stmp, w) 2894 axis.tickAxis[1].fontSize = w; 2895 h = apdata[0x1A]; 2896 axis.tickAxis[1].fontBold = ((h & 0x08) != 0); 2897 stmp.str(apdata.substr(0x23)); 2898 GET_SHORT(stmp, w) 2899 h = apdata[0x25]; 2900 unsigned char h1 = apdata[0x26]; 2901 axis.tickAxis[1].valueType = (ValueType)(h & 0x0F); 2902 pair<string, string> column; 2903 switch (axis.tickAxis[1].valueType) { 2904 case Numeric: 2905 /*switch ((h>>4)) { 2906 case 0x9: 2907 axis.tickAxis[1].valueTypeSpecification=1; 2908 break; 2909 case 0xA: 2910 axis.tickAxis[1].valueTypeSpecification=2; 2911 break; 2912 case 0xB: 2913 axis.tickAxis[1].valueTypeSpecification=3; 2914 break; 2915 default: 2916 axis.tickAxis[1].valueTypeSpecification=0; 2917 }*/ 2918 if ((h >> 4) > 7) { 2919 axis.tickAxis[1].valueTypeSpecification = (h >> 4) - 8; 2920 axis.tickAxis[1].decimalPlaces = h1 - 0x40; 2921 } else { 2922 axis.tickAxis[1].valueTypeSpecification = (h >> 4); 2923 axis.tickAxis[1].decimalPlaces = -1; 2924 } 2925 break; 2926 case Time: 2927 case Date: 2928 case Month: 2929 case Day: 2930 case ColumnHeading: 2931 axis.tickAxis[1].valueTypeSpecification = h1 - 0x40; 2932 break; 2933 case Text: 2934 case TickIndexedDataset: 2935 case Categorical: 2936 column = findDataByIndex(w - 1); 2937 if (column.first.size() > 0) { 2938 axis.tickAxis[1].dataName = column.first; 2939 axis.tickAxis[1].columnName = column.second; 2940 } 2941 break; 2942 case TextNumeric: // Numeric Decimal 1.000 2943 axis.tickAxis[1].valueType = Numeric; 2944 axis.tickAxis[1].valueTypeSpecification = 0; 2945 break; 2946 } 2947 } else if (iaxispar == 5) { // formataxis 1 2948 h = apdata[0x26]; 2949 axis.formatAxis[1].hidden = (h == 0); 2950 axis.formatAxis[1].color = apdata[0x0F]; 2951 if (apdatasz > 0x4B) { 2952 stmp.str(apdata.substr(0x4A)); 2953 GET_SHORT(stmp, w) 2954 axis.formatAxis[1].majorTickLength = (double)w / 10.0; 2955 } 2956 stmp.str(apdata.substr(0x15)); 2957 GET_SHORT(stmp, w) 2958 axis.formatAxis[1].thickness = (double)w / 500.0; 2959 h = apdata[0x25]; 2960 axis.formatAxis[1].minorTicksType = (h >> 6); 2961 axis.formatAxis[1].majorTicksType = ((h >> 4) & 3); 2962 axis.formatAxis[1].axisPosition = (h & 0x0F); 2963 short w1 = 0; 2964 switch (axis.formatAxis[1].axisPosition) { // TODO: check if correct 2965 case 1: 2966 stmp.str(apdata.substr(0x37)); 2967 GET_SHORT(stmp, w1) 2968 axis.formatAxis[1].axisPositionValue = (double)w1; 2969 break; 2970 case 2: 2971 stmp.str(apdata.substr(0x2F)); 2972 GET_DOUBLE(stmp, axis.formatAxis[1].axisPositionValue) 2973 break; 2974 } 2975 } 2976 2977 if (naxis == 1) { 2978 glayer.xAxis = axis; 2979 } else if (naxis == 2) { 2980 glayer.yAxis = axis; 2981 } else if (naxis == 3) { 2982 glayer.zAxis = axis; 2983 } 2984 2985 iaxispar++; 2986 iaxispar %= 6; 2987 } 2988 } 2989 2990 void OriginAnyParser::getNoteProperties(const string &nwehd, unsigned int nwehdsz, 2991 const string &nwelb, unsigned int nwelbsz, 2992 const string &nwect, unsigned int nwectsz) 2993 { 2994 LOG_PRINT(logfile, "getNoteProperties()\n"); 2995 istringstream stmp; 2996 (void)nwehdsz; 2997 (void)nwelbsz; 2998 (void)nwectsz; 2999 3000 // note window position and size 3001 Rect rect; 3002 unsigned int coord; 3003 stmp.str(nwehd); 3004 GET_INT(stmp, coord) 3005 rect.left = static_cast<short>(coord); 3006 GET_INT(stmp, coord) 3007 rect.top = static_cast<short>(coord); 3008 GET_INT(stmp, coord) 3009 rect.right = static_cast<short>(coord); 3010 GET_INT(stmp, coord) 3011 rect.bottom = static_cast<short>(coord); 3012 3013 string name = nwelb.c_str(); 3014 3015 // ResultsLog note window has left, top, right, bottom all zero. 3016 // All other parameters are also zero, except "name" and "text". 3017 if (!rect.bottom || !rect.right) { 3018 resultsLog = nwect; 3019 return; 3020 } 3021 unsigned char state = nwehd[0x18]; 3022 3023 // files from version < 6.0 have nwehdsz < 1D 3024 if (nwehdsz < 0x2F) 3025 return; 3026 3027 double creationDate, modificationDate; 3028 stmp.str(nwehd.substr(0x20)); 3029 GET_DOUBLE(stmp, creationDate) 3030 GET_DOUBLE(stmp, modificationDate) 3031 3032 if (nwehdsz < 0x38) 3033 return; 3034 unsigned char c = nwehd[0x38]; 3035 3036 if (nwehdsz < 0x3F) 3037 return; 3038 unsigned int labellen = 0; 3039 stmp.str(nwehd.substr(0x3C)); 3040 GET_INT(stmp, labellen) 3041 3042 notes.push_back(Note(name)); 3043 LOG_PRINT(logfile, "notes: %d\n", (int)notes.size()); 3044 notes.back().objectID = objectIndex; 3045 ++objectIndex; 3046 3047 notes.back().frameRect = rect; 3048 notes.back().creationDate = doubleToPosixTime(creationDate); 3049 notes.back().modificationDate = doubleToPosixTime(modificationDate); 3050 3051 if (c == 0x01) 3052 notes.back().title = Window::Label; 3053 else if (c == 0x02) 3054 notes.back().title = Window::Name; 3055 else 3056 notes.back().title = Window::Both; 3057 3058 if (state == 0x07) 3059 notes.back().state = Window::Minimized; 3060 else if (state == 0x0b) 3061 notes.back().state = Window::Maximized; 3062 3063 notes.back().hidden = ((state & 0x40) != 0); 3064 3065 if (labellen > 1) { 3066 notes.back().label = nwect.substr(0, labellen); 3067 notes.back().text = nwect.substr(labellen).c_str(); 3068 } else { 3069 notes.back().text = nwect.c_str(); 3070 } 3071 } 3072 3073 void OriginAnyParser::getColorMap(ColorMap &cmap, const string &cmapdata, unsigned int cmapdatasz) 3074 { 3075 istringstream stmp; 3076 unsigned int cmoffset = 0; 3077 // color maps for matrix annotations have a different offset than graph curve's colormaps 3078 if (imatrix != -1) { 3079 cmoffset = 0x14; 3080 } else if (igraph != -1) { 3081 cmoffset = 0x6C; 3082 } else { 3083 return; 3084 } 3085 3086 stmp.str(cmapdata.substr(cmoffset)); 3087 unsigned int colorMapSize = 0; 3088 GET_INT(stmp, colorMapSize) 3089 3090 // check we have enough data to fill the map 3091 unsigned int minDataSize = cmoffset + 0x114 + (colorMapSize + 2) * 0x38; 3092 if (minDataSize > cmapdatasz) { 3093 LOG_PRINT(logfile, 3094 "WARNING: Too few data while getting ColorMap. Needed: at least %d bytes. Have: " 3095 "%d bytes.\n", 3096 minDataSize, cmapdatasz) 3097 return; 3098 } 3099 3100 unsigned int lvl_offset = 0; 3101 for (unsigned int i = 0; i < colorMapSize + 3; ++i) { 3102 lvl_offset = cmoffset + 0x114 + i * 0x38; 3103 ColorMapLevel level; 3104 3105 level.fillPattern = cmapdata[lvl_offset]; 3106 level.fillPatternColor = getColor(cmapdata.substr(lvl_offset + 0x04, 4)); 3107 3108 stmp.str(cmapdata.substr(lvl_offset + 0x08)); 3109 unsigned short w; 3110 GET_SHORT(stmp, w) 3111 level.fillPatternLineWidth = (double)w / 500.0; 3112 3113 level.lineStyle = cmapdata[lvl_offset + 0x10]; 3114 3115 stmp.str(cmapdata.substr(lvl_offset + 0x12)); 3116 GET_SHORT(stmp, w) 3117 level.lineWidth = (double)w / 500.0; 3118 3119 level.lineColor = getColor(cmapdata.substr(lvl_offset + 0x14, 4)); 3120 3121 unsigned char h = cmapdata[lvl_offset + 0x1A]; 3122 level.labelVisible = (h & 0x1); 3123 level.lineVisible = !(h & 0x2); 3124 3125 level.fillColor = getColor(cmapdata.substr(lvl_offset + 0x28, 4)); 3126 3127 double value = 0.0; 3128 stmp.str(cmapdata.substr(lvl_offset + 0x30)); 3129 GET_DOUBLE(stmp, value) 3130 3131 cmap.levels.push_back(make_pair(value, level)); 3132 } 3133 } 3134 3135 void OriginAnyParser::getZcolorsMap(ColorMap &colorMap, const string &cmapdata, 3136 unsigned int cmapdatasz) 3137 { 3138 istringstream stmp; 3139 (void)cmapdatasz; 3140 3141 Color lowColor; // color below 3142 lowColor.type = Origin::Color::Custom; 3143 lowColor.custom[0] = cmapdata[0x0E]; 3144 lowColor.custom[1] = cmapdata[0x0F]; 3145 lowColor.custom[2] = cmapdata[0x10]; 3146 // skip an unsigned char at 0x11 3147 3148 Color highColor; // color above 3149 highColor.type = Origin::Color::Custom; 3150 highColor.custom[0] = cmapdata[0x12]; 3151 highColor.custom[1] = cmapdata[0x13]; 3152 highColor.custom[2] = cmapdata[0x14]; 3153 // skip an unsigned char at 0x15 3154 3155 unsigned short colorMapSize; 3156 stmp.str(cmapdata.substr(0x16)); 3157 GET_SHORT(stmp, colorMapSize) 3158 // skip a short at 0x18-0x19 3159 3160 for (int i = 0; i < 4; ++i) { // low, high, middle and missing data colors 3161 Color color; 3162 (void)color; 3163 color.type = Origin::Color::Custom; 3164 color.custom[0] = cmapdata[0x1A + 4 * i]; 3165 color.custom[1] = cmapdata[0x1B + 4 * i]; 3166 color.custom[2] = cmapdata[0x1C + 4 * i]; 3167 } 3168 3169 double zmin, zmax, zmissing; 3170 stmp.str(cmapdata.substr(0x2A)); 3171 GET_DOUBLE(stmp, zmin); 3172 GET_DOUBLE(stmp, zmax); 3173 GET_DOUBLE(stmp, zmissing); 3174 3175 short val; 3176 for (int i = 0; i < 2; ++i) { 3177 Color color; 3178 (void)color; 3179 color.type = Origin::Color::Custom; 3180 color.custom[0] = cmapdata[0x66 + 10 * i]; 3181 color.custom[1] = cmapdata[0x67 + 10 * i]; 3182 color.custom[2] = cmapdata[0x68 + 10 * i]; 3183 // skip an unsigned char at 0x69+10*i 3184 stmp.str(cmapdata.substr(0x6A + 10 * i)); 3185 GET_SHORT(stmp, val) 3186 } 3187 3188 ColorMapLevel level = { lowColor, 0, lowColor, 1., true, lowColor, 0, 1., true }; 3189 colorMap.levels.push_back(make_pair(zmin, level)); 3190 3191 for (int i = 0; i < (colorMapSize + 1); ++i) { 3192 Color color; 3193 (void)color; 3194 color.type = Origin::Color::Custom; 3195 color.custom[0] = cmapdata[0x7A + 10 * i]; 3196 color.custom[1] = cmapdata[0x7B + 10 * i]; 3197 color.custom[2] = cmapdata[0x7C + 10 * i]; 3198 // skip an unsigned char at 0x7D+10*i 3199 stmp.str(cmapdata.substr((0x7E) + 10 * i)); 3200 GET_SHORT(stmp, val) 3201 3202 level.fillColor = color; 3203 colorMap.levels.push_back(make_pair(val, level)); 3204 } 3205 3206 level.fillColor = highColor; 3207 colorMap.levels.push_back(make_pair(zmax, level)); 3208 } 3209 3210 void OriginAnyParser::getProjectLeafProperties(tree<ProjectNode>::iterator current_folder, 3211 const string &ptldt, unsigned int ptldtsz) 3212 { 3213 LOG_PRINT(logfile, "getProjectLeafProperties()\n"); 3214 istringstream stmp; 3215 (void)ptldtsz; 3216 3217 stmp.str(ptldt); 3218 unsigned int file_type = 0, file_object_id = 0; 3219 GET_INT(stmp, file_type); 3220 GET_INT(stmp, file_object_id); 3221 3222 LOG_PRINT(logfile, "file_type=%d file_object_id=%d\n", file_type, file_object_id); 3223 if (file_type == 0x100000) { // Note window 3224 LOG_PRINT(logfile, "notes.size()=%d\n", (int)notes.size()); 3225 if ((file_object_id <= notes.size()) && (notes.size() > 0)) { 3226 projectTree.append_child(current_folder, 3227 ProjectNode(notes[file_object_id].name, ProjectNode::Note)); 3228 } 3229 } else { // other windows 3230 tree<Origin::ProjectNode>::iterator childnode; 3231 pair<ProjectNode::NodeType, Origin::Window> object = 3232 findWindowObjectByIndex(file_object_id); 3233 childnode = projectTree.append_child(current_folder, 3234 ProjectNode(object.second.name, object.first)); 3235 (*childnode).creationDate = object.second.creationDate; 3236 (*childnode).modificationDate = object.second.modificationDate; 3237 } 3238 } 3239 3240 void OriginAnyParser::getProjectFolderProperties(tree<ProjectNode>::iterator current_folder, 3241 const string &flehd, unsigned int flehdsz) 3242 { 3243 istringstream stmp; 3244 (void)flehdsz; 3245 3246 unsigned char a = flehd[0x02]; 3247 (*current_folder).active = (a == 1); 3248 3249 double creationDate, modificationDate; 3250 stmp.str(flehd.substr(0x10)); 3251 GET_DOUBLE(stmp, creationDate); 3252 GET_DOUBLE(stmp, modificationDate); 3253 3254 (*current_folder).creationDate = doubleToPosixTime(creationDate); 3255 (*current_folder).modificationDate = doubleToPosixTime(modificationDate); 3256 } 3257 3258 void OriginAnyParser::outputProjectTree(std::ostream &out) 3259 { 3260 size_t windowsCount = 3261 spreadSheets.size() + matrixes.size() + excels.size() + graphs.size() + notes.size(); 3262 3263 out << "Project has " << windowsCount << " windows." << endl; 3264 out << "Origin project Tree" << endl; 3265 3266 char cdsz[21]; 3267 for (tree<ProjectNode>::iterator it = projectTree.begin(projectTree.begin()); 3268 it != projectTree.end(projectTree.begin()); ++it) { 3269 strftime(cdsz, sizeof(cdsz), "%F %T", gmtime(&(*it).creationDate)); 3270 out << string(projectTree.depth(it) - 1, ' ') << (*it).name.c_str() << "\t" << cdsz << endl; 3271 } 3272 }