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