diff --git a/liborigin/CMakeLists.txt b/liborigin/CMakeLists.txt index ecef92a85..64ff88082 100644 --- a/liborigin/CMakeLists.txt +++ b/liborigin/CMakeLists.txt @@ -1,73 +1,95 @@ # CMakeLists.txt for liborigin #cmake_minimum_required(VERSION 2.8) # c++11 standard #add_compile_options(-std=c++11) -# boost library headers -#find_package(Boost REQUIRED) -#include_directories(${Boost_INCLUDE_DIRS}) - # library version set(LIBORIGIN_VERSION_MAJOR 3) set(LIBORIGIN_VERSION_MINOR 0) set(LIBORIGIN_VERSION_BUGFIX 0) -# remove -fno-operator-names from CXXFLAGS (added by ECM >= 5.31.0) -if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR - CMAKE_C_COMPILER_ID MATCHES "Clang" OR - (CMAKE_C_COMPILER_ID STREQUAL "Intel" AND NOT WIN32)) - string(REPLACE "-fno-operator-names" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") -endif() - # compile-time configuration variables to be linked in configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) include_directories(${CMAKE_CURRENT_BINARY_DIR}) # source files set (sources OriginFile.cpp OriginParser.cpp OriginAnyParser.cpp ) # header files for development set (devel-headers ${CMAKE_CURRENT_BINARY_DIR}/config.h OriginObj.h OriginFile.h OriginParser.h tree.hh ) +# LIB_SUFFIX can either be defined at cmake command line: cmake -DLIB_SUFFIX:STRING=64 ... +#if (NOT (LIB_SUFFIX STREQUAL "${LIB_SUFFIX}")) +# message("LIB_SUFFIX not defined.") +# # ... or deduced from size of void ptr +# if (CMAKE_SIZEOF_VOID_P EQUAL 8) +# set( LIB_SUFFIX "64") +# else () +# set( LIB_SUFFIX "") +# endif () +# message("LIB_SUFFIX set to '${LIB_SUFFIX}'") +#endif() + +# Generate a pkg-config file matching this config +#configure_file("${CMAKE_CURRENT_SOURCE_DIR}/liborigin.pc.in" +# "${CMAKE_CURRENT_BINARY_DIR}/liborigin.pc" @ONLY) + +# allow for installation of individual targets +#set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true) + # dynamic library #add_library (origin SHARED ${sources}) #set_target_properties(origin PROPERTIES # VERSION ${LIBORIGIN_VERSION_MAJOR}.${LIBORIGIN_VERSION_MINOR}.${LIBORIGIN_VERSION_BUGFIX} # SOVERSION ${LIBORIGIN_VERSION_MAJOR} ) # static library add_library (liborigin-static STATIC ${sources}) set_target_properties(liborigin-static PROPERTIES OUTPUT_NAME "origin" POSITION_INDEPENDENT_CODE ON) +# inform on log setting +if (DEFINED GENERATE_CODE_FOR_LOG) + message("File parsing will be logged.") + target_compile_definitions(origin PRIVATE GENERATE_CODE_FOR_LOG=${GENERATE_CODE_FOR_LOG}) + target_compile_definitions(origin-static PRIVATE GENERATE_CODE_FOR_LOG=${GENERATE_CODE_FOR_LOG}) +else() + message("File parsing will NOT be logged. Define GENERATE_CODE_FOR_LOG to activate logging.") +endif () + # install libraries -#install(TARGETS origin origin-static DESTINATION lib) +#install(TARGETS origin DESTINATION lib${LIB_SUFFIX} OPTIONAL) +#install(TARGETS origin-static DESTINATION lib${LIB_SUFFIX} OPTIONAL) # install headers #install(FILES ${devel-headers} DESTINATION include/liborigin) +# install pkg-config file +#install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liborigin.pc DESTINATION lib${LIB_SUFFIX}/pkgconfig) + # command line util #add_executable(opj2dat opj2dat.cpp) #target_link_libraries (opj2dat origin-static) -#install(TARGETS opj2dat DESTINATION bin) +#install(TARGETS opj2dat DESTINATION bin OPTIONAL) # documentation -#install(FILES COPYING FORMAT README DESTINATION share/doc/liborigin) +#install(FILES COPYING FORMAT README DESTINATION share/doc/liborigin OPTIONAL) #configure_file(doc/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) #find_package(Doxygen) #if(DOXYGEN_FOUND) -# add_custom_target(doc ALL ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile +# add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile # WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) -# install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc/liborigin) +# set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_CURRENT_BINARY_DIR}/html) +# install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc/liborigin OPTIONAL) #endif(DOXYGEN_FOUND) diff --git a/liborigin/FORMAT b/liborigin/FORMAT index acbe1d331..43903ca71 100644 --- a/liborigin/FORMAT +++ b/liborigin/FORMAT @@ -1,77 +1,77 @@ Origin 7.5 column value display ############################### Numeric, Text&Numeric: Decimal:1000 = 0 Scientific:1E3 = 1 Engineering:1k = 2 Decimal:1,000 = 3 Time: hh:mm = 0 hh = 1 hh:mm:ss = 2 hh:mm:ss.zz = 3 hh ap = 4 hh:mm ap = 5 mm:ss = 6 mm:ss.zz = 7 hhmm = 8 hhmmss = 9 hh:mm:ss.zzz = 10 Date: dd/MM/yyyy = -128 dd/MM/yyyy HH:mm = -119 dd/MM/yyyy HH:mm:ss = -118 dd.MM.yyyy = 0 - y. = 1 (year abbreviation - for instance, 'ã.' in russian) + y. = 1 (year abbreviation - for instance, 'ã.' in russian) MMM d = 2 M/d = 3 d = 4 ddd = 5 F = 6 (first letter of day of week) yyyy = 7 yy = 8 dd.MM.yyyy hh:mm = 9 dd.MM.yyyy hh:mm:ss = 10 yyMMdd = 11 yyMMdd hh:mm = 12 yyMMdd hh:mm:ss = 13 yyMMdd hhmm = 14 yyMMdd hhmmss = 15 MMM = 16 J = 17 (first letter of month) Q1 = 18 (quartal) M-d-yyyy (Custom1) = 19 hh:mm:ss.zzzz (Custom2) = 20 Month: MMM = 0 MMMM = 1 J = 2 (first letter of month) Day of Week: ddd = 0 dddd = 1 F = 2 (first letter of day of week) Fill Area Patterns none = 0 /// = 1 / / = 2 / = 3 \\\ = 4 \ \ = 5 \ = 6 xxx = 7 x x = 8 x = 9 --- = 10 - - = 11 - = 12 ||| = 13 | | = 14 | = 15 +++ = 16 + + = 17 + = 18 diff --git a/liborigin/OriginAnyParser.cpp b/liborigin/OriginAnyParser.cpp index ce874d871..89c88724e 100644 --- a/liborigin/OriginAnyParser.cpp +++ b/liborigin/OriginAnyParser.cpp @@ -1,2931 +1,2931 @@ /* * OriginAnyParser.cpp * * Copyright 2017 Miquel Garriga * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Parser for all versions. Based mainly on Origin750Parser.cpp */ #include "OriginAnyParser.h" #include /* define a macro to get an int (or uint) from a istringstream in binary mode */ #define GET_INT(iss, ovalue) {iss.read(reinterpret_cast(&ovalue), 4);}; #define GET_SHORT(iss, ovalue) {iss.read(reinterpret_cast(&ovalue), 2);}; #define GET_FLOAT(iss, ovalue) {iss.read(reinterpret_cast(&ovalue), 4);}; #define GET_DOUBLE(iss, ovalue) {iss.read(reinterpret_cast(&ovalue), 8);}; OriginAnyParser::OriginAnyParser(const string& fileName) : file(fileName.c_str(),ios::binary) { objectIndex = 0; } bool OriginAnyParser::parse() { -#ifndef NO_CODE_GENERATION_FOR_LOG +#ifdef GENERATE_CODE_FOR_LOG // append progress in log file logfile = fopen("opjfile.log","a"); -#endif // NO_CODE_GENERATION_FOR_LOG +#endif // GENERATE_CODE_FOR_LOG // get length of file: file.seekg (0, ios_base::end); d_file_size = file.tellg(); file.seekg(0, ios_base::beg); LOG_PRINT(logfile, "File size: %d\n", d_file_size) // get file and program version, check it is a valid file readFileVersion(); unsigned long curpos = 0; curpos = file.tellg(); LOG_PRINT(logfile, "Now at %ld [0x%lX]\n", curpos, curpos) // get global header readGlobalHeader(); curpos = file.tellg(); LOG_PRINT(logfile, "Now at %ld [0x%lX]\n", curpos, curpos) // get dataset list unsigned int dataset_list_size = 0; LOG_PRINT(logfile, "Reading Data sets ...\n") while (true) { if (!readDataSetElement()) break; dataset_list_size++; } LOG_PRINT(logfile, " ... done. Data sets: %d\n", dataset_list_size) curpos = file.tellg(); LOG_PRINT(logfile, "Now at %ld [0x%lX], filesize %d\n", curpos, curpos, d_file_size) for(unsigned int i = 0; i < spreadSheets.size(); ++i){ #ifdef LVERSION // LABPLOT wants all sheets converted and not loose order if(spreadSheets[i].sheets > 0){ #else if(spreadSheets[i].sheets > 1){ #endif LOG_PRINT(logfile, " CONVERT SPREADSHEET \"%s\" to EXCEL\n", spreadSheets[i].name.c_str()); convertSpreadToExcel(i); --i; } } // get window list unsigned int window_list_size = 0; LOG_PRINT(logfile, "Reading Windows ...\n") while (true) { if (!readWindowElement()) break; window_list_size++; } LOG_PRINT(logfile, " ... done. Windows: %d\n", window_list_size) curpos = file.tellg(); LOG_PRINT(logfile, "Now at %ld [0x%lX], filesize %d\n", curpos, curpos, d_file_size) // get parameter list unsigned int parameter_list_size = 0; LOG_PRINT(logfile, "Reading Parameters ...\n") while (true) { if (!readParameterElement()) break; parameter_list_size++; } LOG_PRINT(logfile, " ... done. Parameters: %d\n", parameter_list_size) curpos = file.tellg(); LOG_PRINT(logfile, "Now at %ld [0x%lX], filesize %d\n", curpos, curpos, d_file_size) // Note windows were added between version >4.141 and 4.210, // i.e., with Release 5.0 if (curpos < d_file_size) { // get note windows list unsigned int note_list_size = 0; LOG_PRINT(logfile, "Reading Note windows ...\n") // Note windows have an independent index objectIndex = 0; while (true) { if (!readNoteElement()) break; note_list_size++; } LOG_PRINT(logfile, " ... done. Note windows: %d\n", note_list_size) curpos = file.tellg(); LOG_PRINT(logfile, "Now at %ld [0x%lX], filesize %d\n", curpos, curpos, d_file_size) } // Project Tree was added between version >4.210 and 4.2616, // i.e., with Release 6.0 if (curpos < d_file_size) { // get project tree readProjectTree(); curpos = file.tellg(); LOG_PRINT(logfile, "Now at %ld [0x%lX], filesize %d\n", curpos, curpos, d_file_size) } // Attachments were added between version >4.2673_558 and 4.2764_623, // i.e., with Release 7.0 if (curpos < d_file_size) { readAttachmentList(); curpos = file.tellg(); LOG_PRINT(logfile, "Now at %ld [0x%lX], filesize %d\n", curpos, curpos, d_file_size) } if (curpos >= d_file_size) LOG_PRINT(logfile, "Now at end of file\n") // drop unused matrix datasets vector validMatrices; for(unsigned int i = 0; i < matrixes.size(); ++i){ Matrix m = matrixes[i]; if (m.objectID >= 0) { validMatrices.push_back(m); } else { LOG_PRINT(logfile, "Matrix data set %d: %s is not used.\n", i, m.name.c_str()) } } matrixes.clear(); matrixes = validMatrices; -#ifndef NO_CODE_GENERATION_FOR_LOG +#ifdef GENERATE_CODE_FOR_LOG fclose(logfile); -#endif // NO_CODE_GENERATION_FOR_LOG +#endif // GENERATE_CODE_FOR_LOG return true; } string toLowerCase(string str){ for (unsigned int i = 0; i < str.length(); i++) if (str[i] >= 0x41 && str[i] <= 0x5A) str[i] = str[i] + 0x20; return str; } OriginParser* createOriginAnyParser(const string& fileName) { return new OriginAnyParser(fileName); } unsigned int OriginAnyParser::readObjectSize() { unsigned int obj_size = 0; unsigned long curpos; (void) curpos; char c = 0; file >> obj_size; file >> c; if (c != '\n') { curpos = file.tellg(); LOG_PRINT(logfile, "Wrong delimiter %c at %ld [0x%lX]\n", c, curpos, curpos) exit(2); } return obj_size; } string OriginAnyParser::readObjectAsString(unsigned int size) { char c; unsigned long curpos; (void) curpos; // read a size-byte blob of data followed by '\n' if (size > 0) { // get a string large enough to hold the result, initialize it to all 0's string blob = string(size, '\0'); // read data into that string // cannot use '>>' operator because iendianfstream truncates it at first '\0' file.read(&blob[0], size); // read the '\n' file >> c; if (c != '\n') { curpos = file.tellg(); LOG_PRINT(logfile, "Wrong delimiter %c at %ld [0x%lX]\n", c, curpos, curpos) exit(3); } return blob; } return string(); } void OriginAnyParser::readFileVersion() { // get file and program version, check it is a valid file string sFileVersion; getline(file, sFileVersion); if ((sFileVersion.substr(0,4) != "CPYA") || (*sFileVersion.rbegin() != '#')) { LOG_PRINT(logfile, "File, is not a valid opj file\n") exit(1); } LOG_PRINT(logfile, "File version string: %s\n", sFileVersion.c_str()) } void OriginAnyParser::readGlobalHeader() { // get global header size unsigned int gh_size = 0, gh_endmark = 0; gh_size = readObjectSize(); unsigned long curpos = file.tellg(); (void) curpos; LOG_PRINT(logfile, "Global header size: %d [0x%X], starts at %ld [0x%lX],", gh_size, gh_size, curpos, curpos) // get global header data string gh_data; gh_data = readObjectAsString(gh_size); curpos = file.tellg(); LOG_PRINT(logfile, " ends at %ld [0x%lX]\n", curpos, curpos) // when gh_size > 0x1B, a double with fileVersion/100 can be read at gh_data[0x1B:0x23] if (gh_size > 0x1B) { istringstream stmp; stmp.str(gh_data.substr(0x1B)); double dFileVersion; GET_DOUBLE(stmp, dFileVersion) if (dFileVersion > 8.5) { fileVersion = (unsigned int)trunc(dFileVersion*100.); } else { fileVersion = 10*(unsigned int)trunc(dFileVersion*10.); } LOG_PRINT(logfile, "Project version as read from header: %.2f (%.6f)\n", fileVersion/100.0, dFileVersion) } // now read a zero size end mark gh_endmark = readObjectSize(); if (gh_endmark != 0) { curpos = file.tellg(); LOG_PRINT(logfile, "Wrong end of list mark %d at %ld [0x%lX]\n", gh_endmark, curpos, curpos) exit(4); } } bool OriginAnyParser::readDataSetElement() { /* get info and values of a DataSet (worksheet column, matrix sheet, ...) * return true if a DataSet is found, otherwise return false */ unsigned int dse_header_size = 0, dse_data_size = 0, dse_mask_size = 0; unsigned long curpos = 0, dsh_start = 0, dsd_start = 0, dsm_start = 0; string dse_header; // get dataset header size dse_header_size = readObjectSize(); if (dse_header_size == 0) return false; curpos = file.tellg(); dsh_start = curpos; LOG_PRINT(logfile, "Column: header size %d [0x%X], starts at %ld [0x%lX], ", dse_header_size, dse_header_size, curpos, curpos) dse_header = readObjectAsString(dse_header_size); // get known info string name(25,0); name = dse_header.substr(0x58,25); // go to end of dataset header, get data size file.seekg(dsh_start+dse_header_size+1, ios_base::beg); dse_data_size = readObjectSize(); dsd_start = file.tellg(); string dse_data = readObjectAsString(dse_data_size); curpos = file.tellg(); LOG_PRINT(logfile, "data size %d [0x%X], from %ld [0x%lX] to %ld [0x%lX],", dse_data_size, dse_data_size, dsd_start, dsd_start, curpos, curpos) // get data values getColumnInfoAndData(dse_header, dse_header_size, dse_data, dse_data_size); // go to end of data values, get mask size (often zero) file.seekg(dsd_start+dse_data_size, ios_base::beg); // dse_data_size can be zero if (dse_data_size > 0) file.seekg(1, ios_base::cur); dse_mask_size = readObjectSize(); dsm_start = file.tellg(); if (dse_mask_size > 0) LOG_PRINT(logfile, "\nmask size %d [0x%X], starts at %ld [0x%lX]", dse_mask_size, dse_mask_size, dsm_start, dsm_start) string dse_mask = readObjectAsString(dse_mask_size); // get mask values if (dse_mask_size > 0) { curpos = file.tellg(); LOG_PRINT(logfile, ", ends at %ld [0x%lX]\n", curpos, curpos) // TODO: extract mask values from dse_mask // go to end of dataset mask file.seekg(dsm_start+dse_mask_size+1, ios_base::beg); } curpos = file.tellg(); LOG_PRINT(logfile, " ends at %ld [0x%lX]: ", curpos, curpos) LOG_PRINT(logfile, "%s\n", name.c_str()) return true; } bool OriginAnyParser::readWindowElement() { /* get general info and details of a window * return true if a Window is found, otherwise return false */ unsigned int wde_header_size = 0; unsigned long curpos = 0, wdh_start = 0; // get window header size wde_header_size = readObjectSize(); if (wde_header_size == 0) return false; curpos = file.tellg(); wdh_start = curpos; LOG_PRINT(logfile, "Window found: header size %d [0x%X], starts at %ld [0x%lX]: ", wde_header_size, wde_header_size, curpos, curpos) string wde_header = readObjectAsString(wde_header_size); // get known info string name(25,0); name = wde_header.substr(0x02,25).c_str(); LOG_PRINT(logfile, "%s\n", name.c_str()) // classify type of window ispread = findSpreadByName(name); imatrix = findMatrixByName(name); iexcel = findExcelByName(name); igraph = -1; if (ispread != -1) { LOG_PRINT(logfile, "\n Window is a Worksheet book\n") getWindowProperties(spreadSheets[ispread], wde_header, wde_header_size); } else if (imatrix != -1) { LOG_PRINT(logfile, "\n Window is a Matrix book\n") getWindowProperties(matrixes[imatrix], wde_header, wde_header_size); } else if (iexcel != -1) { LOG_PRINT(logfile, "\n Window is an Excel book\n") getWindowProperties(excels[iexcel], wde_header, wde_header_size); } else { LOG_PRINT(logfile, "\n Window is a Graph\n") graphs.push_back(Graph(name)); igraph = graphs.size()-1; getWindowProperties(graphs[igraph], wde_header, wde_header_size); } // go to end of window header file.seekg(wdh_start+wde_header_size+1, ios_base::beg); // get layer list unsigned int layer_list_size = 0; LOG_PRINT(logfile, " Reading Layers ...\n") while (true) { ilayer = layer_list_size; if (!readLayerElement()) break; layer_list_size++; } LOG_PRINT(logfile, " ... done. Layers: %d\n", layer_list_size) curpos = file.tellg(); LOG_PRINT(logfile, "window ends at %ld [0x%lX]\n", curpos, curpos) return true; } bool OriginAnyParser::readLayerElement() { /* get general info and details of a layer * return true if a Layer is found, otherwise return false */ unsigned int lye_header_size = 0; unsigned long curpos = 0, lyh_start = 0; // get layer header size lye_header_size = readObjectSize(); if (lye_header_size == 0) return false; curpos = file.tellg(); lyh_start = curpos; LOG_PRINT(logfile, " Layer found: header size %d [0x%X], starts at %ld [0x%lX]\n", lye_header_size, lye_header_size, curpos, curpos) string lye_header = readObjectAsString(lye_header_size); // get known info getLayerProperties(lye_header, lye_header_size); // go to end of layer header file.seekg(lyh_start+lye_header_size+1, ios_base::beg); // get annotation list unsigned int annotation_list_size = 0; (void) annotation_list_size; LOG_PRINT(logfile, " Reading Annotations ...\n") /* Some annotations can be groups of annotations. We need a recursive function for those cases */ annotation_list_size = readAnnotationList(); LOG_PRINT(logfile, " ... done. Annotations: %d\n", annotation_list_size) // get curve list unsigned int curve_list_size = 0; LOG_PRINT(logfile, " Reading Curves ...\n") while (true) { if (!readCurveElement()) break; curve_list_size++; } LOG_PRINT(logfile, " ... done. Curves: %d\n", curve_list_size) // get axisbreak list unsigned int axisbreak_list_size = 0; LOG_PRINT(logfile, " Reading Axis breaks ...\n") while (true) { if (!readAxisBreakElement()) break; axisbreak_list_size++; } LOG_PRINT(logfile, " ... done. Axis breaks: %d\n", axisbreak_list_size) // get x axisparameter list unsigned int axispar_x_list_size = 0; LOG_PRINT(logfile, " Reading x-Axis parameters ...\n") while (true) { if (!readAxisParameterElement(1)) break; axispar_x_list_size++; } LOG_PRINT(logfile, " ... done. x-Axis parameters: %d\n", axispar_x_list_size) // get y axisparameter list unsigned int axispar_y_list_size = 0; LOG_PRINT(logfile, " Reading y-Axis parameters ...\n") while (true) { if (!readAxisParameterElement(2)) break; axispar_y_list_size++; } LOG_PRINT(logfile, " ... done. y-Axis parameters: %d\n", axispar_y_list_size) // get z axisparameter list unsigned int axispar_z_list_size = 0; LOG_PRINT(logfile, " Reading z-Axis parameters ...\n") while (true) { if (!readAxisParameterElement(3)) break; axispar_z_list_size++; } LOG_PRINT(logfile, " ... done. z-Axis parameters: %d\n", axispar_z_list_size) curpos = file.tellg(); LOG_PRINT(logfile, " layer ends at %ld [0x%lX]\n", curpos, curpos) return true; } unsigned int OriginAnyParser::readAnnotationList() { /* Purpose of this function is to allow recursive call for groups of annotation elements. */ unsigned int annotation_list_size = 0; while (true) { if (!readAnnotationElement()) break; annotation_list_size++; } return annotation_list_size; } bool OriginAnyParser::readAnnotationElement() { /* get general info and details of an Annotation * return true if an Annotation is found, otherwise return false */ unsigned int ane_header_size = 0; unsigned long curpos = 0, anh_start = 0; // get annotation header size ane_header_size = readObjectSize(); if (ane_header_size == 0) return false; curpos = file.tellg(); anh_start = curpos; LOG_PRINT(logfile, " Annotation found: header size %d [0x%X], starts at %ld [0x%lX]: ", ane_header_size, ane_header_size, curpos, curpos) string ane_header = readObjectAsString(ane_header_size); // get known info string name(41,0); name = ane_header.substr(0x46,41); LOG_PRINT(logfile, "%s\n", name.c_str()) // go to end of annotation header file.seekg(anh_start+ane_header_size+1, ios_base::beg); // data of an annotation element is divided in three blocks // first block unsigned int ane_data_1_size = 0; unsigned long andt1_start = 0; ane_data_1_size = readObjectSize(); andt1_start = file.tellg(); LOG_PRINT(logfile, " block 1 size %d [0x%X] at %ld [0x%lX]\n", ane_data_1_size, ane_data_1_size, andt1_start, andt1_start) string andt1_data = readObjectAsString(ane_data_1_size); // TODO: get known info // go to end of first data block file.seekg(andt1_start+ane_data_1_size+1, ios_base::beg); // second block unsigned int ane_data_2_size = 0; unsigned long andt2_start = 0; ane_data_2_size = readObjectSize(); andt2_start = file.tellg(); LOG_PRINT(logfile, " block 2 size %d [0x%X] at %ld [0x%lX]\n", ane_data_2_size, ane_data_2_size, andt2_start, andt2_start) string andt2_data; // check for group of annotations if ((ane_data_1_size == 0x5e) && (ane_data_2_size == 0x04)) { unsigned int angroup_size = 0; (void) angroup_size; curpos = file.tellg(); LOG_PRINT(logfile, " Annotation group found at %ld [0x%lX] ...\n", curpos, curpos) angroup_size = readAnnotationList(); curpos = file.tellg(); LOG_PRINT(logfile, " ... group end at %ld [0x%lX]. Annotations: %d\n", curpos, curpos, angroup_size) andt2_data = string(""); } else { andt2_data = readObjectAsString(ane_data_2_size); // TODO: get known info // go to end of second data block file.seekg(andt2_start+ane_data_2_size, ios_base::beg); if (ane_data_2_size > 0) file.seekg(1, ios_base::cur); } // third block unsigned int ane_data_3_size = 0; unsigned long andt3_start = 0; (void) andt3_start; ane_data_3_size = readObjectSize(); andt3_start = file.tellg(); LOG_PRINT(logfile, " block 3 size %d [0x%X] at %ld [0x%lX]\n", ane_data_3_size, ane_data_3_size, andt3_start, andt3_start) string andt3_data = readObjectAsString(ane_data_3_size); curpos = file.tellg(); LOG_PRINT(logfile, " annotation ends at %ld [0x%lX]\n", curpos, curpos) // get annotation info getAnnotationProperties(ane_header, ane_header_size, andt1_data, ane_data_1_size, andt2_data, ane_data_2_size, andt3_data, ane_data_3_size); return true; } bool OriginAnyParser::readCurveElement() { /* get general info and details of a Curve * return true if a Curve is found, otherwise return false */ unsigned int cve_header_size = 0, cve_data_size = 0; unsigned long curpos = 0, cvh_start = 0, cvd_start = 0; // get curve header size cve_header_size = readObjectSize(); if (cve_header_size == 0) return false; curpos = file.tellg(); cvh_start = curpos; LOG_PRINT(logfile, " Curve: header size %d [0x%X], starts at %ld [0x%lX], ", cve_header_size, cve_header_size, curpos, curpos) string cve_header = readObjectAsString(cve_header_size); // TODO: get known info from curve header string name = cve_header.substr(0x12,12); // go to end of header, get curve data size file.seekg(cvh_start+cve_header_size+1, ios_base::beg); cve_data_size = readObjectSize(); cvd_start = file.tellg(); LOG_PRINT(logfile, "data size %d [0x%X], from %ld [0x%lX]", cve_data_size, cve_data_size, cvd_start, cvd_start) string cve_data = readObjectAsString(cve_data_size); // TODO: get known info from curve data // go to end of data file.seekg(cvd_start+cve_data_size, ios_base::beg); if (cve_data_size > 0) file.seekg(1, ios_base::cur); curpos = file.tellg(); LOG_PRINT(logfile, "to %ld [0x%lX]: %s\n", curpos, curpos, name.c_str()) // get curve (or column) info getCurveProperties(cve_header, cve_header_size, cve_data, cve_data_size); return true; } bool OriginAnyParser::readAxisBreakElement() { /* get info of Axis breaks * return true if an Axis break, otherwise return false */ unsigned int abe_data_size = 0; unsigned long curpos = 0, abd_start = 0; // get axis break data size abe_data_size = readObjectSize(); if (abe_data_size == 0) return false; curpos = file.tellg(); abd_start = curpos; string abd_data = readObjectAsString(abe_data_size); // get known info // go to end of axis break data file.seekg(abd_start+abe_data_size+1, ios_base::beg); // get axis break info getAxisBreakProperties(abd_data, abe_data_size); return true; } bool OriginAnyParser::readAxisParameterElement(unsigned int naxis) { /* get info of Axis parameters for naxis-axis (x,y,z) = (1,2,3) * return true if an Axis break is found, otherwise return false */ unsigned int ape_data_size = 0; unsigned long curpos = 0, apd_start = 0; // get axis break data size ape_data_size = readObjectSize(); if (ape_data_size == 0) return false; curpos = file.tellg(); apd_start = curpos; string apd_data = readObjectAsString(ape_data_size); // get known info // go to end of axis break data file.seekg(apd_start+ape_data_size+1, ios_base::beg); // get axis parameter info getAxisParameterProperties(apd_data, ape_data_size, naxis); return true; } bool OriginAnyParser::readParameterElement() { // get parameter name unsigned long curpos = 0; (void) curpos; string par_name; char c; getline(file, par_name); if (par_name[0] == '\0') { unsigned int eof_parameters_mark = readObjectSize(); (void) eof_parameters_mark; // supress compiler warning return false; } LOG_PRINT(logfile, " %s:", par_name.c_str()) // get value double value; file >> value; LOG_PRINT(logfile, " %g\n", value) // read the '\n' file >> c; if (c != '\n') { curpos = file.tellg(); LOG_PRINT(logfile, "Wrong delimiter %c at %ld [0x%lX]\n", c, curpos, curpos) exit(3); } return true; } bool OriginAnyParser::readNoteElement() { /* get info of Note windows, including "Results Log" * return true if a Note window is found, otherwise return false */ unsigned int nwe_header_size = 0, nwe_label_size = 0, nwe_contents_size = 0; unsigned long curpos = 0, nwh_start = 0, nwl_start = 0, nwc_start = 0; (void) nwc_start; // get note header size nwe_header_size = readObjectSize(); if (nwe_header_size == 0) return false; curpos = file.tellg(); nwh_start = curpos; LOG_PRINT(logfile, " Note window found: header size %d [0x%X], starts at %ld [0x%lX]\n", nwe_header_size, nwe_header_size, curpos, curpos) string nwe_header = readObjectAsString(nwe_header_size); // TODO: get known info from header // go to end of header file.seekg(nwh_start+nwe_header_size+1, ios_base::beg); // get label size nwe_label_size = readObjectSize(); nwl_start = file.tellg(); string nwe_label = readObjectAsString(nwe_label_size); LOG_PRINT(logfile, " label at %ld [0x%lX]: %s\n", nwl_start, nwl_start, nwe_label.c_str()) // go to end of label file.seekg(nwl_start+nwe_label_size, ios_base::beg); if (nwe_label_size > 0) file.seekg(1, ios_base::cur); // get contents size nwe_contents_size = readObjectSize(); nwc_start = file.tellg(); string nwe_contents = readObjectAsString(nwe_contents_size); LOG_PRINT(logfile, " contents at %ld [0x%lX]: \n%s\n", nwc_start, nwc_start, nwe_contents.c_str()) // get note window info getNoteProperties(nwe_header, nwe_header_size, nwe_label, nwe_label_size, nwe_contents, nwe_contents_size); return true; } void OriginAnyParser::readProjectTree() { unsigned int pte_depth = 0; // first preamble size and data (usually 4) unsigned int pte_pre1_size = readObjectSize(); string pte_pre1 = readObjectAsString(pte_pre1_size); // second preamble size and data (usually 16) unsigned int pte_pre2_size = readObjectSize(); string pte_pre2 = readObjectAsString(pte_pre2_size); // root element and children unsigned int rootfolder = readFolderTree(projectTree.begin(), pte_depth); (void) rootfolder; // supress compiler warning // epilogue (should be zero) unsigned int pte_post_size = readObjectSize(); (void) pte_post_size; // supress compiler warning // log info on project tree -#ifndef NO_CODE_GENERATION_FOR_LOG +#ifdef GENERATE_CODE_FOR_LOG outputProjectTree(); -#endif // NO_CODE_GENERATION_FOR_LOG +#endif // GENERATE_CODE_FOR_LOG return; } unsigned int OriginAnyParser::readFolderTree(tree::iterator parent, unsigned int depth) { unsigned int fle_header_size = 0, fle_eofh_size = 0, fle_name_size = 0, fle_prop_size = 0; unsigned long curpos = 0; (void) curpos; // folder header size, data, end mark fle_header_size = readObjectSize(); string fle_header = readObjectAsString(fle_header_size); fle_eofh_size = readObjectSize(); // (usually 0) (void) fle_eofh_size; // supress compiler warning // folder name size fle_name_size = readObjectSize(); curpos = file.tellg(); string fle_name = readObjectAsString(fle_name_size); LOG_PRINT(logfile, "Folder name at %ld [0x%lX]: %s\n", curpos, curpos, fle_name.c_str()); // additional properties fle_prop_size = readObjectSize(); for (unsigned int i = 0; i < fle_prop_size; i++) { unsigned int obj_size = readObjectSize(); string obj_data = readObjectAsString(obj_size); } // get project folder properties tree::iterator current_folder = projectTree.append_child(parent, ProjectNode(fle_name, ProjectNode::Folder)); getProjectFolderProperties(current_folder, fle_header, fle_header_size); // file entries unsigned int number_of_files_size = 0; number_of_files_size = readObjectSize(); // should be 4 as number_of_files is an integer curpos = file.tellg(); LOG_PRINT(logfile, "Number of files at %ld [0x%lX] ", curpos, curpos); string fle_nfiles = readObjectAsString(number_of_files_size); istringstream stmp(ios_base::binary); stmp.str(fle_nfiles); unsigned int number_of_files = 0; GET_INT(stmp, number_of_files) LOG_PRINT(logfile, "%d\n", number_of_files) for (unsigned int i=0; i < number_of_files; i++) { readProjectLeaf(current_folder); } // subfolder entries unsigned int number_of_folders_size = 0; number_of_folders_size = readObjectSize(); // should be 4 as number_of_subfolders is an integer curpos = file.tellg(); LOG_PRINT(logfile, "Number of subfolders at %ld [0x%lX] ", curpos, curpos); string fle_nfolders = readObjectAsString(number_of_folders_size); stmp.str(fle_nfolders); unsigned int number_of_folders = 0; GET_INT(stmp, number_of_folders) LOG_PRINT(logfile, "%d\n", number_of_folders) for (unsigned int i=0; i < number_of_folders; i++) { depth++; unsigned int files_in_subfolder = readFolderTree(current_folder, depth); (void) files_in_subfolder; // supress compiler warning depth--; } return number_of_files; } void OriginAnyParser::readProjectLeaf(tree::iterator current_folder) { unsigned long curpos = 0; (void) curpos; // preamble size (usually 0) and data unsigned int ptl_pre_size = readObjectSize(); string ptl_pre = readObjectAsString(ptl_pre_size); // file data size (usually 8) and data unsigned int ptl_data_size = readObjectSize(); curpos = file.tellg(); string ptl_data = readObjectAsString(ptl_data_size); LOG_PRINT(logfile, "File at %ld [0x%lX]\n", curpos, curpos) // epilogue (should be zero) unsigned int ptl_post_size = readObjectSize(); (void) ptl_post_size; // supress compiler warning // get project node properties getProjectLeafProperties(current_folder, ptl_data, ptl_data_size); return; } void OriginAnyParser::readAttachmentList() { /* Attachments are divided in two groups (which can be empty) first group is preceeded by two integers: 4096 (0x1000) and number_of_attachments followed as usual by a '\n' mark second group is a series of (header, name, data) triplets without the '\n' mark. */ // figure out if first group is not empty. In this case we will read integer=8 at current file position unsigned int att_1st_empty = 0; file >> att_1st_empty; file.seekg(-4, ios_base::cur); istringstream stmp(ios_base::binary); string att_header; unsigned long curpos = 0; (void) curpos; if (att_1st_empty == 8) { // first group unsigned int att_list1_size = 0; // get two integers // next line fails if first attachment group is empty: readObjectSize exits as there is no '\n' after 4 bytes for uint att_list1_size = readObjectSize(); // should be 8 as we expect two integer values curpos = file.tellg(); string att_list1 = readObjectAsString(att_list1_size); LOG_PRINT(logfile, "First attachment group at %ld [0x%lX]", curpos, curpos) stmp.str(att_list1); unsigned int att_mark = 0, number_of_atts = 0, iattno = 0, att_data_size = 0; GET_INT(stmp, att_mark) // should be 4096 GET_INT(stmp, number_of_atts) LOG_PRINT(logfile, " with %d attachments.\n", number_of_atts) for (unsigned int i=0; i < number_of_atts; i++) { /* Header is a group of 7 integers followed by \n 1st attachment mark (4096: 0x00 0x10 0x00 0x00) 2nd attachment number ( (&att_header[0]), 12); if (file.gcount() != 12) break; // get header size, type and data size unsigned int att_header_size=0, att_type=0, att_size=0; stmp.str(att_header); GET_INT(stmp, att_header_size) GET_INT(stmp, att_type) GET_INT(stmp, att_size) // get name and data unsigned int name_size = att_header_size - 3*4; string att_name = string(name_size, 0); file.read(&att_name[0], name_size); curpos = file.tellg(); string att_data = string(att_size, 0); file.read(&att_data[0], att_size); LOG_PRINT(logfile, "attachment at %ld [0x%lX], type 0x%X, size %d [0x%X]: %s\n", curpos, curpos, att_type, att_size, att_size, att_name.c_str()) } return; } bool OriginAnyParser::getColumnInfoAndData(string col_header, unsigned int col_header_size, string col_data, unsigned int col_data_size) { istringstream stmp(ios_base::binary); static unsigned int dataIndex=0; short data_type; char data_type_u; unsigned char valuesize; string name(25,0), column_name; stmp.str(col_header.substr(0x16)); GET_SHORT(stmp, data_type); data_type_u = col_header[0x3F]; if (fileVersion == 350) { valuesize = col_header[0x36]; } else { valuesize = col_header[0x3D]; } if(valuesize == 0) { LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize); valuesize = 8; } if (fileVersion == 350) { name = col_header.substr(0x57,25).c_str(); } else { name = col_header.substr(0x58,25).c_str(); } string dataset_name = name; string::size_type colpos = name.find_last_of("_"); if(colpos != string::npos){ column_name = name.substr(colpos + 1); name.resize(colpos); } LOG_PRINT(logfile, "\n data_type 0x%.4X, data_type_u 0x%.2X, valuesize %d [0x%X], %s [%s]\n", data_type, data_type_u, valuesize, valuesize, name.c_str(), column_name.c_str()); unsigned short signature; if (col_header_size > 0x72) { stmp.str(col_header.substr(0x71)); GET_SHORT(stmp, signature); int total_rows, first_row, last_row; stmp.str(col_header.substr(0x19)); GET_INT(stmp, total_rows); GET_INT(stmp, first_row); GET_INT(stmp, last_row); LOG_PRINT(logfile, " total %d, first %d, last %d rows\n", total_rows, first_row, last_row) } else { LOG_PRINT(logfile, " NOTE: alternative signature determination\n") signature = col_header[0x18]; } LOG_PRINT(logfile, " signature %d [0x%X], valuesize %d size %d ", signature, signature, valuesize, col_data_size) unsigned int current_col = 1;//, nr = 0, nbytes = 0; static unsigned int col_index = 0; unsigned int current_sheet = 0; int spread = 0; if (column_name.empty()) { // Matrix or function if (data_type == 0x6081) { // Function functions.push_back(Function(name, dataIndex)); ++dataIndex; Origin::Function &f = functions.back(); f.formula = toLowerCase(col_data.c_str()); stmp.str(col_header.substr(0x0A)); short t; GET_SHORT(stmp, t) if (t == 0x1194) f.type = Function::Polar; stmp.str(col_header.substr(0x21)); GET_INT(stmp, f.totalPoints) GET_DOUBLE(stmp, f.begin) double d; GET_DOUBLE(stmp, d) f.end = f.begin + d*(f.totalPoints - 1); LOG_PRINT(logfile, "\n NEW FUNCTION: %s = %s", f.name.c_str(), f.formula.c_str()); LOG_PRINT(logfile, ". Range [%g : %g], number of points: %d\n", f.begin, f.end, f.totalPoints); } else { // Matrix int mIndex = -1; string::size_type pos = name.find_first_of("@"); if (pos != string::npos){ string sheetName = name; name.resize(pos); mIndex = findMatrixByName(name); if (mIndex != -1){ LOG_PRINT(logfile, "\n NEW MATRIX SHEET\n"); matrixes[mIndex].sheets.push_back(MatrixSheet(sheetName, dataIndex)); } } else { LOG_PRINT(logfile, "\n NEW MATRIX\n"); matrixes.push_back(Matrix(name)); matrixes.back().sheets.push_back(MatrixSheet(name, dataIndex)); } ++dataIndex; getMatrixValues(col_data, col_data_size, data_type, data_type_u, valuesize, mIndex); } } else { if(spreadSheets.size() == 0 || findSpreadByName(name) == -1) { LOG_PRINT(logfile, "\n NEW SPREADSHEET\n"); current_col = 1; spreadSheets.push_back(SpreadSheet(name)); spread = spreadSheets.size() - 1; spreadSheets.back().maxRows = 0; current_sheet = 0; } else { spread = findSpreadByName(name); current_col = spreadSheets[spread].columns.size(); if(!current_col) current_col = 1; ++current_col; } spreadSheets[spread].columns.push_back(SpreadColumn(column_name, dataIndex)); spreadSheets[spread].columns.back().colIndex = ++col_index; spreadSheets[spread].columns.back().dataset_name = dataset_name; string::size_type sheetpos = spreadSheets[spread].columns.back().name.find_last_of("@"); if(sheetpos != string::npos){ unsigned int sheet = strtol(column_name.substr(sheetpos + 1).c_str(), 0, 10); if( sheet > 1){ spreadSheets[spread].columns.back().name = column_name; if (current_sheet != (sheet - 1)) current_sheet = sheet - 1; spreadSheets[spread].columns.back().sheet = current_sheet; if (spreadSheets[spread].sheets < sheet) spreadSheets[spread].sheets = sheet; } } ++dataIndex; LOG_PRINT(logfile, " data index %d, valuesize %d, ", dataIndex, valuesize) unsigned int nr = col_data_size / valuesize; LOG_PRINT(logfile, "n. of rows = %d\n\n", nr) spreadSheets[spread].maxRows (nr-5))) { LOG_PRINT(logfile, "%g ", value) } else if (i == 5) { LOG_PRINT(logfile, "... ") } spreadSheets[spread].columns[(current_col-1)].data.push_back(value); } else if((data_type & 0x100) == 0x100) // Text&Numeric { unsigned char c = col_data[i*valuesize]; stmp.seekg(i*valuesize+2, ios_base::beg); if(c != 1) //value { GET_DOUBLE(stmp, value); if ((i < 5) || (i > (nr-5))) { LOG_PRINT(logfile, "%g ", value) } else if (i == 5) { LOG_PRINT(logfile, "... ") } spreadSheets[spread].columns[(current_col-1)].data.push_back(value); } else //text { string svaltmp = col_data.substr(i*valuesize+2, valuesize-2); // TODO: check if this test is still needed if(svaltmp.find(0x0E) != string::npos) { // try find non-printable symbol - garbage test svaltmp = string(); LOG_PRINT(logfile, "Non printable symbol found, place 1 for i=%d\n", i) } if ((i < 5) || (i > (nr-5))) { LOG_PRINT(logfile, "\"%s\" ", svaltmp.c_str()) } else if (i == 5) { LOG_PRINT(logfile, "... ") } spreadSheets[spread].columns[(current_col-1)].data.push_back(svaltmp); } } else //text { string svaltmp = col_data.substr(i*valuesize, valuesize).c_str(); // TODO: check if this test is still needed if(svaltmp.find(0x0E) != string::npos) { // try find non-printable symbol - garbage test svaltmp = string(); LOG_PRINT(logfile, "Non printable symbol found, place 2 for i=%d\n", i) } if ((i < 5) || (i > (nr-5))) { LOG_PRINT(logfile, "\"%s\" ", svaltmp.c_str()) } else if (i == 5) { LOG_PRINT(logfile, "... ") } spreadSheets[spread].columns[(current_col-1)].data.push_back(svaltmp); } } LOG_PRINT(logfile, "\n\n") datasets.push_back(spreadSheets[spread].columns.back()); } return true; } void OriginAnyParser::getMatrixValues(string col_data, unsigned int col_data_size, short data_type, char data_type_u, char valuesize, int mIndex) { if (matrixes.empty()) return; istringstream stmp; stmp.str(col_data); if (mIndex < 0) mIndex = matrixes.size() - 1; unsigned int size = col_data_size/valuesize; bool logValues = true; switch(data_type){ case 0x6001://double for(unsigned int i = 0; i < size; ++i){ double value; GET_DOUBLE(stmp, value) matrixes[mIndex].sheets.back().data.push_back(value); } break; case 0x6003://float for(unsigned int i = 0; i < size; ++i){ float value; GET_FLOAT(stmp, value) matrixes[mIndex].sheets.back().data.push_back((double)value); } break; case 0x6801://int if (data_type_u == 8){//unsigned for(unsigned int i = 0; i < size; ++i){ unsigned int value; GET_INT(stmp, value) matrixes[mIndex].sheets.back().data.push_back((double)value); } } else { for(unsigned int i = 0; i < size; ++i){ int value; GET_INT(stmp, value) matrixes[mIndex].sheets.back().data.push_back((double)value); } } break; case 0x6803://short if (data_type_u == 8){//unsigned for(unsigned int i = 0; i < size; ++i){ unsigned short value; GET_SHORT(stmp, value) matrixes[mIndex].sheets.back().data.push_back((double)value); } } else { for(unsigned int i = 0; i < size; ++i){ short value; GET_SHORT(stmp, value) matrixes[mIndex].sheets.back().data.push_back((double)value); } } break; case 0x6821://char if (data_type_u == 8){//unsigned for(unsigned int i = 0; i < size; ++i){ unsigned char value; value = col_data[i]; matrixes[mIndex].sheets.back().data.push_back((double)value); } } else { for(unsigned int i = 0; i < size; ++i){ char value; value = col_data[i]; matrixes[mIndex].sheets.back().data.push_back((double)value); } } break; default: LOG_PRINT(logfile, " UNKNOWN MATRIX DATATYPE: %02X SKIP DATA\n", data_type); matrixes.pop_back(); logValues = false; } if (logValues){ LOG_PRINT(logfile, " FIRST 10 CELL VALUES: "); for(unsigned int i = 0; i < 10 && i < matrixes[mIndex].sheets.back().data.size(); ++i) LOG_PRINT(logfile, "%g\t", matrixes[mIndex].sheets.back().data[i]); } } void OriginAnyParser::getWindowProperties(Origin::Window& window, string wde_header, unsigned int wde_header_size) { window.objectID = objectIndex; ++objectIndex; istringstream stmp; stmp.str(wde_header.substr(0x1B)); GET_SHORT(stmp, window.frameRect.left) GET_SHORT(stmp, window.frameRect.top) GET_SHORT(stmp, window.frameRect.right) GET_SHORT(stmp, window.frameRect.bottom) char c = wde_header[0x32]; if(c & 0x01) window.state = Window::Minimized; else if(c & 0x02) window.state = Window::Maximized; c = wde_header[0x69]; if(c & 0x01) window.title = Window::Label; else if(c & 0x02) window.title = Window::Name; else window.title = Window::Both; window.hidden = (c & 0x08); if (window.hidden) { LOG_PRINT(logfile, " WINDOW %d NAME : %s is hidden\n", objectIndex, window.name.c_str()); } else { LOG_PRINT(logfile, " WINDOW %d NAME : %s is not hidden\n", objectIndex, window.name.c_str()); } if (wde_header_size > 0x82) { // only projects of version 6.0 and higher have these double creationDate, modificationDate; stmp.str(wde_header.substr(0x73)); GET_DOUBLE(stmp, creationDate); window.creationDate = doubleToPosixTime(creationDate); GET_DOUBLE(stmp, modificationDate) window.modificationDate = doubleToPosixTime(modificationDate); } if(wde_header_size > 0xC3){ window.label = wde_header.substr(0xC3).c_str(); window.label = window.label.substr(0,window.label.find("@${")); LOG_PRINT(logfile, " WINDOW %d LABEL: %s\n", objectIndex, window.label.c_str()); } if (imatrix != -1) { // additional properties for matrix windows unsigned char h = wde_header[0x29]; matrixes[imatrix].activeSheet = h; if (wde_header_size > 0x86) { h = wde_header[0x87]; matrixes[imatrix].header = (h == 194) ? Matrix::XY : Matrix::ColumnRow; } } if (igraph != -1) { // additional properties for graph/layout windows stmp.str(wde_header.substr(0x23)); GET_SHORT(stmp, graphs[igraph].width) GET_SHORT(stmp, graphs[igraph].height) unsigned char c = wde_header[0x38]; graphs[igraph].connectMissingData = (c & 0x40); string templateName = wde_header.substr(0x45,20).c_str(); graphs[igraph].templateName = templateName; if (templateName == "LAYOUT") graphs[igraph].isLayout = true; } } void OriginAnyParser::getLayerProperties(string lye_header, unsigned int lye_header_size) { istringstream stmp; if (ispread != -1) { // spreadsheet spreadSheets[ispread].loose = false; } else if (imatrix != -1) { // matrix MatrixSheet& sheet = matrixes[imatrix].sheets[ilayer]; unsigned short width = 8; stmp.str(lye_header.substr(0x27)); GET_SHORT(stmp, width) if (width == 0) width = 8; sheet.width = width; stmp.str(lye_header.substr(0x2B)); GET_SHORT(stmp, sheet.columnCount) stmp.str(lye_header.substr(0x52)); GET_SHORT(stmp, sheet.rowCount) unsigned char view = lye_header[0x71]; if (view != 0x32 && view != 0x28){ sheet.view = MatrixSheet::ImageView; } else { sheet.view = MatrixSheet::DataView; } if (lye_header_size > 0xD2) { sheet.name = lye_header.substr(0xD2,32).c_str(); } } else if (iexcel != -1) { // excel excels[iexcel].loose = false; } else { // graph graphs[igraph].layers.push_back(GraphLayer()); GraphLayer& glayer = graphs[igraph].layers[ilayer]; stmp.str(lye_header.substr(0x0F)); GET_DOUBLE(stmp, glayer.xAxis.min); GET_DOUBLE(stmp, glayer.xAxis.max); GET_DOUBLE(stmp, glayer.xAxis.step); glayer.xAxis.majorTicks = lye_header[0x2B]; unsigned char g = lye_header[0x2D]; glayer.xAxis.zeroLine = (g & 0x80); glayer.xAxis.oppositeLine = (g & 0x40); glayer.xAxis.minorTicks = lye_header[0x37]; glayer.xAxis.scale = lye_header[0x38]; stmp.str(lye_header.substr(0x3A)); GET_DOUBLE(stmp, glayer.yAxis.min); GET_DOUBLE(stmp, glayer.yAxis.max); GET_DOUBLE(stmp, glayer.yAxis.step); glayer.yAxis.majorTicks = lye_header[0x56]; g = lye_header[0x58]; glayer.yAxis.zeroLine = (g & 0x80); glayer.yAxis.oppositeLine = (g & 0x40); glayer.yAxis.minorTicks = lye_header[0x62]; glayer.yAxis.scale = lye_header[0x63]; g = lye_header[0x68]; glayer.gridOnTop = (g & 0x04); glayer.exchangedAxes = (g & 0x40); stmp.str(lye_header.substr(0x71)); GET_SHORT(stmp, glayer.clientRect.left) GET_SHORT(stmp, glayer.clientRect.top) GET_SHORT(stmp, glayer.clientRect.right) GET_SHORT(stmp, glayer.clientRect.bottom) unsigned char border = lye_header[0x89]; glayer.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); if (lye_header_size > 0x107) glayer.backgroundColor = getColor(lye_header.substr(0x105,4)); } } Origin::Color OriginAnyParser::getColor(string strbincolor) { /* decode a color value from a 4 byte binary string */ Origin::Color result; unsigned char sbincolor[4]; for (int i=0; i < 4; i++) { sbincolor[i] = strbincolor[i]; } switch(sbincolor[3]) { case 0: if(sbincolor[0] < 0x64) { result.type = Origin::Color::Regular; result.regular = sbincolor[0]; } else { switch(sbincolor[2]) { case 0: result.type = Origin::Color::Indexing; break; case 0x40: result.type = Origin::Color::Mapping; break; case 0x80: result.type = Origin::Color::RGB; break; } result.column = sbincolor[0] - 0x64; } break; case 1: result.type = Origin::Color::Custom; for(int i = 0; i < 3; ++i) result.custom[i] = sbincolor[i]; break; case 0x20: result.type = Origin::Color::Increment; result.starting = sbincolor[1]; break; case 0xFF: if(sbincolor[0] == 0xFC) result.type = Origin::Color::None; else if(sbincolor[0] == 0xF7) result.type = Origin::Color::Automatic; else { result.type = Origin::Color::Regular; result.regular = sbincolor[0]; } break; default: result.type = Origin::Color::Regular; result.regular = sbincolor[0]; break; } return result; } void OriginAnyParser::getAnnotationProperties(string anhd, unsigned int anhdsz, string andt1, unsigned int andt1sz, string andt2, unsigned int andt2sz, string andt3, unsigned int andt3sz) { istringstream stmp; (void) anhdsz; (void) andt3; (void) andt3sz; if (ispread != -1) { string sec_name = anhd.substr(0x46,41).c_str(); int col_index = findColumnByName(ispread, sec_name); if (col_index != -1){ //check if it is a formula spreadSheets[ispread].columns[col_index].command = andt1.c_str(); LOG_PRINT(logfile, " Column: %s has formula: %s\n", sec_name.c_str(), spreadSheets[ispread].columns[col_index].command.c_str()) } } else if (imatrix != -1) { MatrixSheet& sheet = matrixes[imatrix].sheets[ilayer]; string sec_name = anhd.substr(0x46,41).c_str(); stmp.str(andt1.c_str()); if (sec_name == "MV") { sheet.command = andt1.c_str(); } else if (sec_name == "Y2") { stmp >> sheet.coordinates[0]; } else if (sec_name == "X2") { stmp >> sheet.coordinates[1]; } else if (sec_name == "Y1") { stmp >> sheet.coordinates[2]; } else if (sec_name == "X1") { stmp >> sheet.coordinates[3]; } else if (sec_name == "COLORMAP") { // Color maps for matrix annotations are similar to color maps for graph curves (3D). // They differ only in the start offset to the data string. getColorMap(sheet.colorMap, andt2, andt2sz); } } else if (iexcel != -1) { string sec_name = anhd.substr(0x46,41).c_str(); int col_index = findExcelColumnByName(iexcel, ilayer, sec_name); if (col_index != -1){ //check if it is a formula excels[iexcel].sheets[ilayer].columns[col_index].command = andt1.c_str(); } } else { GraphLayer& glayer = graphs[igraph].layers[ilayer]; string sec_name = anhd.substr(0x46,41).c_str(); Rect r; stmp.str(anhd.substr(0x03)); GET_SHORT(stmp, r.left) GET_SHORT(stmp, r.top) GET_SHORT(stmp, r.right) GET_SHORT(stmp, r.bottom) unsigned char attach = anhd[0x28]; unsigned char border = anhd[0x29]; Color color = getColor(anhd.substr(0x33,4)); if (sec_name == "PL") glayer.yAxis.formatAxis[0].prefix = andt1.c_str(); if (sec_name == "PR") glayer.yAxis.formatAxis[1].prefix = andt1.c_str(); if (sec_name == "PB") glayer.xAxis.formatAxis[0].prefix = andt1.c_str(); if (sec_name == "PT") glayer.xAxis.formatAxis[1].prefix = andt1.c_str(); if (sec_name == "SL") glayer.yAxis.formatAxis[0].suffix = andt1.c_str(); if (sec_name == "SR") glayer.yAxis.formatAxis[1].suffix = andt1.c_str(); if (sec_name == "SB") glayer.xAxis.formatAxis[0].suffix = andt1.c_str(); if (sec_name == "ST") glayer.xAxis.formatAxis[1].suffix = andt1.c_str(); if (sec_name == "OL") glayer.yAxis.formatAxis[0].factor = andt1.c_str(); if (sec_name == "OR") glayer.yAxis.formatAxis[1].factor = andt1.c_str(); if (sec_name == "OB") glayer.xAxis.formatAxis[0].factor = andt1.c_str(); if (sec_name == "OT") glayer.xAxis.formatAxis[1].factor = andt1.c_str(); unsigned char type = andt1[0x00]; LineVertex begin, end; /* OriginNNNParser identify line/arrow annotation by checking size of andt1 Origin410: 21||24; Origin 500: 24; Origin 610: 24||96; Origin700 and higher: 120; An alternative is to look at anhd[0x02]: (0x21 for Circle/Rect, 0x22 for Line/Arrow, 0x23 for Polygon/Polyline) */ unsigned char ankind = anhd[0x02]; if (ankind == 0x22) {//Line/Arrow if ((attach == Origin::Scale) && (andt1sz > 0x5F)) { if (type == 2) { stmp.str(andt1.substr(0x20)); GET_DOUBLE(stmp, begin.x) GET_DOUBLE(stmp, end.x) stmp.str(andt1.substr(0x40)); GET_DOUBLE(stmp, begin.y) GET_DOUBLE(stmp, end.y) } else if (type == 4) {//curved arrow: start point, 2 middle points and end point stmp.str(andt1.substr(0x20)); GET_DOUBLE(stmp, begin.x) GET_DOUBLE(stmp, end.x) GET_DOUBLE(stmp, end.x) GET_DOUBLE(stmp, end.x) GET_DOUBLE(stmp, begin.y) GET_DOUBLE(stmp, end.y) GET_DOUBLE(stmp, end.y) GET_DOUBLE(stmp, end.y) } } else { short x1, x2, y1, y2; if (type == 2) {//straight line/arrow stmp.str(andt1.substr(0x01)); GET_SHORT(stmp, x1) GET_SHORT(stmp, x2) stmp.seekg(4, ios_base::cur); GET_SHORT(stmp, y1) GET_SHORT(stmp, y2) } else if (type == 4) {//curved line/arrow has 4 points stmp.str(andt1.substr(0x01)); GET_SHORT(stmp, x1) stmp.seekg(4, ios_base::cur); GET_SHORT(stmp, x2) GET_SHORT(stmp, y1) stmp.seekg(4, ios_base::cur); GET_SHORT(stmp, y2) } double dx = fabs(x2 - x1); double dy = fabs(y2 - y1); double minx = (x1 <= x2) ? x1 : x2; double miny = (y1 <= y2) ? y1 : y2; begin.x = (x1 == x2) ? r.left + 0.5*r.width() : r.left + (x1 - minx)/dx*r.width(); end.x = (x1 == x2) ? r.left + 0.5*r.width() : r.left + (x2 - minx)/dx*r.width(); begin.y = (y1 == y2) ? r.top + 0.5*r.height(): r.top + (y1 - miny)/dy*r.height(); end.y = (y1 == y2) ? r.top + 0.5*r.height(): r.top + (y2 - miny)/dy*r.height(); } unsigned char arrows = andt1[0x11]; switch (arrows) { case 0: begin.shapeType = 0; end.shapeType = 0; break; case 1: begin.shapeType = 1; end.shapeType = 0; break; case 2: begin.shapeType = 0; end.shapeType = 1; break; case 3: begin.shapeType = 1; end.shapeType = 1; break; } if (andt1sz > 0x77) { begin.shapeType = andt1[0x60]; unsigned int w = 0; stmp.str(andt1.substr(0x64)); GET_INT(stmp, w) begin.shapeWidth = (double)w/500.0; GET_INT(stmp, w) begin.shapeLength = (double)w/500.0; end.shapeType = andt1[0x6C]; stmp.str(andt1.substr(0x70)); GET_INT(stmp, w) end.shapeWidth = (double)w/500.0; GET_INT(stmp, w) end.shapeLength = (double)w/500.0; } } //text properties short rotation; stmp.str(andt1.substr(0x02)); GET_SHORT(stmp, rotation) unsigned char fontSize = andt1[0x4]; unsigned char tab = andt1[0x0A]; //line properties unsigned char lineStyle = andt1[0x12]; unsigned short w1 = 0; if (andt1sz > 0x14) { stmp.str(andt1.substr(0x13)); GET_SHORT(stmp, w1) } double width = (double)w1/500.0; Figure figure; stmp.str(andt1.substr(0x05)); GET_SHORT(stmp, w1) figure.width = (double)w1/500.0; figure.style = andt1[0x08]; if (andt1sz > 0x4D) { figure.fillAreaColor = getColor(andt1.substr(0x42,4)); stmp.str(andt1.substr(0x46)); GET_SHORT(stmp, w1) figure.fillAreaPatternWidth = (double)w1/500.0; figure.fillAreaPatternColor = getColor(andt1.substr(0x4A,4)); figure.fillAreaPattern = andt1[0x4E]; } if (andt1sz > 0x56) { unsigned char h = andt1[0x57]; figure.useBorderColor = (h == 0x10); } if (sec_name == "XB") { string text = andt2.c_str(); glayer.xAxis.position = GraphAxis::Bottom; glayer.xAxis.formatAxis[0].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); } else if (sec_name == "XT") { string text = andt2.c_str(); glayer.xAxis.position = GraphAxis::Top; glayer.xAxis.formatAxis[1].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); } else if (sec_name == "YL") { string text = andt2.c_str(); glayer.yAxis.position = GraphAxis::Left; glayer.yAxis.formatAxis[0].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); } else if (sec_name == "YR") { string text = andt2.c_str(); glayer.yAxis.position = GraphAxis::Right; glayer.yAxis.formatAxis[1].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); } else if (sec_name == "ZF") { string text = andt2.c_str(); glayer.zAxis.position = GraphAxis::Front; glayer.zAxis.formatAxis[0].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); } else if (sec_name == "ZB") { string text = andt2.c_str(); glayer.zAxis.position = GraphAxis::Back; glayer.zAxis.formatAxis[1].label = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); } else if (sec_name == "3D") { stmp.str(andt2); GET_DOUBLE(stmp, glayer.zAxis.min) GET_DOUBLE(stmp, glayer.zAxis.max) GET_DOUBLE(stmp, glayer.zAxis.step) glayer.zAxis.majorTicks = andt2[0x1C]; glayer.zAxis.minorTicks = andt2[0x28]; glayer.zAxis.scale = andt2[0x29]; stmp.str(andt2.substr(0x5A)); GET_FLOAT(stmp, glayer.xAngle) GET_FLOAT(stmp, glayer.yAngle) GET_FLOAT(stmp, glayer.zAngle) stmp.str(andt2.substr(0x218)); GET_FLOAT(stmp, glayer.xLength) GET_FLOAT(stmp, glayer.yLength) GET_FLOAT(stmp, glayer.zLength) glayer.xLength /= 23.0; glayer.yLength /= 23.0; glayer.zLength /= 23.0; glayer.orthographic3D = (andt2[0x240] != 0); } else if (sec_name == "Legend") { string text = andt2.c_str(); glayer.legend = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); } else if (sec_name == "__BCO2") { // histogram stmp.str(andt2.substr(0x10)); GET_DOUBLE(stmp, glayer.histogramBin) stmp.str(andt2.substr(0x20)); GET_DOUBLE(stmp, glayer.histogramEnd) GET_DOUBLE(stmp, glayer.histogramBegin) // TODO: check if 0x5E is right (obtained from anhdsz-0x46+93-andt1sz = 111-70+93-40 = 94) glayer.percentile.p1SymbolType = andt2[0x5E]; glayer.percentile.p99SymbolType = andt2[0x5F]; glayer.percentile.meanSymbolType = andt2[0x60]; glayer.percentile.maxSymbolType = andt2[0x61]; glayer.percentile.minSymbolType = andt2[0x62]; // 0x9F = 0x5E+65 glayer.percentile.labels = andt2[0x9F]; // 0x6B = 0x5E+106-93 = 107 glayer.percentile.whiskersRange = andt2[0x6B]; glayer.percentile.boxRange = andt2[0x6C]; // 0x8e = 0x5E+141-93 = 142 glayer.percentile.whiskersCoeff = andt2[0x8e]; glayer.percentile.boxCoeff = andt2[0x8f]; unsigned char h = andt2[0x90]; glayer.percentile.diamondBox = (h == 0x82) ? true : false; // 0xCB = 0x5E+109 = 203 stmp.str(andt2.substr(0xCB)); GET_SHORT(stmp, glayer.percentile.symbolSize) glayer.percentile.symbolSize = glayer.percentile.symbolSize/2 + 1; // 0x101 = 0x5E+163 glayer.percentile.symbolColor = getColor(andt2.substr(0x101,4)); glayer.percentile.symbolFillColor = getColor(andt2.substr(0x105,4)); } else if (sec_name == "_206") { // box plot labels } else if (sec_name == "VLine") { stmp.str(andt1.substr(0x0A)); double start; GET_DOUBLE(stmp, start) stmp.str(andt1.substr(0x1A)); double width; GET_DOUBLE(stmp, width) glayer.vLine = start + 0.5*width; glayer.imageProfileTool = 2; } else if (sec_name == "HLine") { stmp.str(andt1.substr(0x12)); double start; GET_DOUBLE(stmp, start) stmp.str(andt1.substr(0x22)); double width; GET_DOUBLE(stmp, width) glayer.hLine = start + 0.5*width; glayer.imageProfileTool = 2; } else if (sec_name == "vline") { stmp.str(andt1.substr(0x20)); GET_DOUBLE(stmp, glayer.vLine) glayer.imageProfileTool = 1; } else if (sec_name == "hline") { stmp.str(andt1.substr(0x40)); GET_DOUBLE(stmp, glayer.hLine) glayer.imageProfileTool = 1; } else if (sec_name == "ZCOLORS") { glayer.isXYY3D = true; if (fileVersion < 600) { ColorMap& colorMap = glayer.colorMap; getZcolorsMap(colorMap, andt2, andt2sz); } } else if (sec_name == "SPECTRUM1") { glayer.isXYY3D = false; glayer.colorScale.visible = true; glayer.colorScale.reverseOrder = andt2[0x18]; stmp.str(andt2.substr(0x20)); GET_SHORT(stmp, glayer.colorScale.colorBarThickness) GET_SHORT(stmp, glayer.colorScale.labelGap) glayer.colorScale.labelsColor = getColor(andt2.substr(0x5C,4)); } else if (sec_name == "&0") { glayer.isWaterfall = true; string text = andt1.c_str(); string::size_type commaPos = text.find_first_of(","); stmp.str(text.substr(0,commaPos)); stmp >> glayer.xOffset; stmp.str(text.substr(commaPos+1)); stmp >> glayer.yOffset; } /* OriginNNNParser identify text, circle, rectangle and bitmap annotation by checking size of andt1: text/pie text rectangle/circle line bitmap Origin410: 22 0xA(10) 21/24 38 Origin500: 22 0xA(10) 24 40 Origin610: 22 0xA(10) 24/96 40 Origin700: 0x5E(94) 120 0x28(40) Origin750: 0x3E(62)/78 0x5E(94) 0x78(120) 0x28(40) Origin850: 0x3E(62)/78 0x5E(94) 0x78(120) 0x28(40) An alternative is to look at anhd[0x02]: (0x00 for Text, 0x21 for Circle/Rect, 0x22 for Line/Arrow, 0x23 for Polygon/Polyline) */ else if ((ankind == 0x0) && (sec_name != "DelData")) { // text string text = andt2.c_str(); if (sec_name.substr(0,3) == "PIE") glayer.pieTexts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); else glayer.texts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); } else if (ankind == 0x21) { // rectangle & circle switch (type) { // type = andt1[0x00] case 0: case 1: figure.type = Figure::Rectangle; break; case 2: case 3: figure.type = Figure::Circle; break; } figure.clientRect = r; figure.attach = (Attach)attach; figure.color = color; glayer.figures.push_back(figure); } else if ((ankind == 0x22) && (sec_name != "sLine") && (sec_name != "sline")) { // line/arrow glayer.lines.push_back(Line()); Line& line(glayer.lines.back()); line.color = color; line.clientRect = r; line.attach = (Attach)attach; line.width = width; line.style = lineStyle; line.begin = begin; line.end = end; } else if (andt1sz == 40) { // bitmap if (type == 4) { // type = andt1[0x00] unsigned long filesize = andt2sz + 14; glayer.bitmaps.push_back(Bitmap()); Bitmap& bitmap(glayer.bitmaps.back()); bitmap.clientRect = r; bitmap.attach = (Attach)attach; bitmap.size = filesize; bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); bitmap.data = new unsigned char[filesize]; unsigned char* data = bitmap.data; //add Bitmap header memcpy(data, "BM", 2); data += 2; memcpy(data, &filesize, 4); data += 4; unsigned int d = 0; memcpy(data, &d, 4); data += 4; d = 0x36; memcpy(data, &d, 4); data += 4; memcpy(data, andt2.c_str(), andt2sz); } else if (type == 6) { // TODO check if 0x5E is right (obtained from anhdsz-0x46+93-andt1sz = 111-70+93-40 = 94) string gname = andt2.substr(0x5E).c_str(); glayer.bitmaps.push_back(Bitmap(gname)); Bitmap& bitmap(glayer.bitmaps.back()); bitmap.clientRect = r; bitmap.attach = (Attach)attach; bitmap.size = 0; bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); } } } return; } void OriginAnyParser::getCurveProperties(string cvehd, unsigned int cvehdsz, string cvedt, unsigned int cvedtsz) { istringstream stmp; if (ispread != -1) { // spreadsheet: curves are columns // TODO: check that spreadsheet columns are stored in proper order // vector header; unsigned char c = cvehd[0x11]; string name = cvehd.substr(0x12).c_str(); unsigned short width = 0; if (cvehdsz > 0x4B) { stmp.str(cvehd.substr(0x4A)); GET_SHORT(stmp, width) } int col_index = findColumnByName(ispread, name); if (col_index != -1) { if (spreadSheets[ispread].columns[col_index].name != name) spreadSheets[ispread].columns[col_index].name = name; SpreadColumn::ColumnType type; switch(c){ case 3: type = SpreadColumn::X; break; case 0: type = SpreadColumn::Y; break; case 5: type = SpreadColumn::Z; break; case 6: type = SpreadColumn::XErr; break; case 2: type = SpreadColumn::YErr; break; case 4: type = SpreadColumn::Label; break; default: type = SpreadColumn::NONE; break; } spreadSheets[ispread].columns[col_index].type = type; width /= 0xA; if(width == 0) width = 8; spreadSheets[ispread].columns[col_index].width = width; unsigned char c1 = cvehd[0x1E]; unsigned char c2 = cvehd[0x1F]; switch (c1) { case 0x00: // Numeric - Dec1000 case 0x09: // Text&Numeric - Dec1000 case 0x10: // Numeric - Scientific case 0x19: // Text&Numeric - Scientific case 0x20: // Numeric - Engineering case 0x29: // Text&Numeric - Engineering case 0x30: // Numeric - Dec1,000 case 0x39: // Text&Numeric - Dec1,000 spreadSheets[ispread].columns[col_index].valueType = (c1%0x10 == 0x9) ? TextNumeric : Numeric; spreadSheets[ispread].columns[col_index].valueTypeSpecification = c1 / 0x10; if (c2 >= 0x80) { spreadSheets[ispread].columns[col_index].significantDigits = c2 - 0x80; spreadSheets[ispread].columns[col_index].numericDisplayType = SignificantDigits; } else if (c2 > 0) { spreadSheets[ispread].columns[col_index].decimalPlaces = c2 - 0x03; spreadSheets[ispread].columns[col_index].numericDisplayType = DecimalPlaces; } break; case 0x02: // Time spreadSheets[ispread].columns[col_index].valueType = Time; spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2 - 0x80; break; case 0x03: // Date case 0x33: spreadSheets[ispread].columns[col_index].valueType = Date; spreadSheets[ispread].columns[col_index].valueTypeSpecification= c2 - 0x80; break; case 0x31: // Text spreadSheets[ispread].columns[col_index].valueType = Text; break; case 0x4: // Month case 0x34: spreadSheets[ispread].columns[col_index].valueType = Month; spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2; break; case 0x5: // Day case 0x35: spreadSheets[ispread].columns[col_index].valueType = Day; spreadSheets[ispread].columns[col_index].valueTypeSpecification = c2; break; default: // Text spreadSheets[ispread].columns[col_index].valueType = Text; break; } if (cvedtsz > 0) { spreadSheets[ispread].columns[col_index].comment = cvedt.c_str(); } // TODO: check that spreadsheet columns are stored in proper order // header.push_back(spreadSheets[ispread].columns[col_index]); } // TODO: check that spreadsheet columns are stored in proper order // for (unsigned int i = 0; i < header.size(); i++) // spreadSheets[spread].columns[i] = header[i]; } else if (imatrix != -1) { MatrixSheet sheet = matrixes[imatrix].sheets[ilayer]; unsigned char c1 = cvehd[0x1E]; unsigned char c2 = cvehd[0x1F]; sheet.valueTypeSpecification = c1/0x10; if (c2 >= 0x80) { sheet.significantDigits = c2-0x80; sheet.numericDisplayType = SignificantDigits; } else if (c2 > 0) { sheet.decimalPlaces = c2-0x03; sheet.numericDisplayType = DecimalPlaces; } matrixes[imatrix].sheets[ilayer] = sheet; } else if (iexcel != -1) { unsigned char c = cvehd[0x11]; string name = cvehd.substr(0x12).c_str(); unsigned short width = 0; stmp.str(cvehd.substr(0x4A)); GET_SHORT(stmp, width) unsigned short dataID = 0; stmp.str(cvehd.substr(0x04)); GET_SHORT(stmp, dataID) unsigned int isheet = datasets[dataID-1].sheet; int col_index = findExcelColumnByName(iexcel, isheet, name); if (col_index != -1) { SpreadColumn::ColumnType type; switch(c){ case 3: type = SpreadColumn::X; break; case 0: type = SpreadColumn::Y; break; case 5: type = SpreadColumn::Z; break; case 6: type = SpreadColumn::XErr; break; case 2: type = SpreadColumn::YErr; break; case 4: type = SpreadColumn::Label; break; default: type = SpreadColumn::NONE; break; } excels[iexcel].sheets[isheet].columns[col_index].type = type; width /= 0xA; if (width == 0) width = 8; excels[iexcel].sheets[isheet].columns[col_index].width = width; unsigned char c1 = cvehd[0x1E]; unsigned char c2 = cvehd[0x1F]; switch (c1) { case 0x00: // Numeric - Dec1000 case 0x09: // Text&Numeric - Dec1000 case 0x10: // Numeric - Scientific case 0x19: // Text&Numeric - Scientific case 0x20: // Numeric - Engineering case 0x29: // Text&Numeric - Engineering case 0x30: // Numeric - Dec1,000 case 0x39: // Text&Numeric - Dec1,000 excels[iexcel].sheets[isheet].columns[col_index].valueType = (c1%0x10 == 0x9) ? TextNumeric : Numeric; excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c1 / 0x10; if (c2 >= 0x80) { excels[iexcel].sheets[isheet].columns[col_index].significantDigits = c2 - 0x80; excels[iexcel].sheets[isheet].columns[col_index].numericDisplayType = SignificantDigits; } else if (c2 > 0) { excels[iexcel].sheets[isheet].columns[col_index].decimalPlaces = c2 - 0x03; excels[iexcel].sheets[isheet].columns[col_index].numericDisplayType = DecimalPlaces; } break; case 0x02: // Time excels[iexcel].sheets[isheet].columns[col_index].valueType = Time; excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2 - 0x80; break; case 0x03: // Date excels[iexcel].sheets[isheet].columns[col_index].valueType = Date; excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2 - 0x80; break; case 0x31: // Text excels[iexcel].sheets[isheet].columns[col_index].valueType = Text; break; case 0x04: // Month case 0x34: excels[iexcel].sheets[isheet].columns[col_index].valueType = Month; excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2; break; case 0x05: // Day case 0x35: excels[iexcel].sheets[isheet].columns[col_index].valueType = Day; excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2; break; default: // Text excels[iexcel].sheets[isheet].columns[col_index].valueType = Text; break; } if (cvedtsz > 0) { excels[iexcel].sheets[isheet].columns[col_index].comment = cvedt.c_str(); } } } else { GraphLayer& glayer = graphs[igraph].layers[ilayer]; glayer.curves.push_back(GraphCurve()); GraphCurve& curve(glayer.curves.back()); unsigned char h = cvehd[0x26]; curve.hidden = (h == 33); curve.type = cvehd[0x4C]; if (curve.type == GraphCurve::XYZContour || curve.type == GraphCurve::Contour) glayer.isXYY3D = false; unsigned short w; stmp.str(cvehd.substr(0x04)); GET_SHORT(stmp, w) pair column = findDataByIndex(w-1); short nColY = w; if (column.first.size() > 0) { curve.dataName = column.first; if (glayer.is3D() || (curve.type == GraphCurve::XYZContour)) { curve.zColumnName = column.second; } else { curve.yColumnName = column.second; } } stmp.str(cvehd.substr(0x23)); GET_SHORT(stmp, w) column = findDataByIndex(w-1); if (column.first.size() > 0) { curve.xDataName = (curve.dataName != column.first) ? column.first : ""; if (glayer.is3D() || (curve.type == GraphCurve::XYZContour)) { curve.yColumnName = column.second; } else if (glayer.isXYY3D){ curve.xColumnName = column.second; } else { curve.xColumnName = column.second; } } if (cvehdsz > 0x4E) { stmp.str(cvehd.substr(0x4D)); GET_SHORT(stmp, w) column = findDataByIndex(w-1); if (column.first.size() > 0 && (glayer.is3D() || (curve.type == GraphCurve::XYZContour))) { curve.xColumnName = column.second; if (curve.dataName != column.first) { // graph X and Y from different tables } } } if (glayer.is3D() || glayer.isXYY3D) graphs[igraph].is3D = true; curve.lineConnect = cvehd[0x11]; curve.lineStyle = cvehd[0x12]; curve.boxWidth = cvehd[0x14]; stmp.str(cvehd.substr(0x15)); GET_SHORT(stmp, w) curve.lineWidth = (double)w/500.0; stmp.str(cvehd.substr(0x17)); GET_SHORT(stmp, curve.symbolType) stmp.str(cvehd.substr(0x19)); GET_SHORT(stmp, w) curve.symbolSize = (double)w/500.0; h = cvehd[0x1C]; curve.fillArea = (h==2); curve.fillAreaType = cvehd[0x1E]; //text if (curve.type == GraphCurve::TextPlot) { stmp.str(cvehd.substr(0x13)); GET_SHORT(stmp, curve.text.rotation) curve.text.rotation /= 10; GET_SHORT(stmp, curve.text.fontSize) h = cvehd[0x19]; switch (h) { case 26: curve.text.justify = TextProperties::Center; break; case 2: curve.text.justify = TextProperties::Right; break; default: curve.text.justify = TextProperties::Left; break; } h = cvehd[0x20]; curve.text.fontUnderline = (h & 0x1); curve.text.fontItalic = (h & 0x2); curve.text.fontBold = (h & 0x8); curve.text.whiteOut = (h & 0x20); char offset = cvehd[0x37]; curve.text.xOffset = offset * 5; offset = cvehd[0x38]; curve.text.yOffset = offset * 5; } //vector if (curve.type == GraphCurve::FlowVector || curve.type == GraphCurve::Vector) { stmp.str(cvehd.substr(0x56)); GET_FLOAT(stmp, curve.vector.multiplier) h = cvehd[0x5E]; column = findDataByIndex(nColY - 1 + h - 0x64); if (column.first.size() > 0) curve.vector.endXColumnName = column.second; h = cvehd[0x62]; column = findDataByIndex(nColY - 1 + h - 0x64); if (column.first.size() > 0) curve.vector.endYColumnName = column.second; h = cvehd[0x18]; if (h >= 0x64) { column = findDataByIndex(nColY - 1 + h - 0x64); if (column.first.size() > 0) curve.vector.angleColumnName = column.second; } else if (h <= 0x08) curve.vector.constAngle = 45*h; h = cvehd[0x19]; if (h >= 0x64){ column = findDataByIndex(nColY - 1 + h - 0x64); if (column.first.size() > 0) curve.vector.magnitudeColumnName = column.second; } else curve.vector.constMagnitude = (int)curve.symbolSize; stmp.str(cvehd.substr(0x66)); GET_SHORT(stmp, curve.vector.arrowLenght) curve.vector.arrowAngle = cvehd[0x68]; h = cvehd[0x69]; curve.vector.arrowClosed = !(h & 0x1); stmp.str(cvehd.substr(0x70)); GET_SHORT(stmp, w) curve.vector.width = (double)w/500.0; h = cvehd[0x142]; switch (h) { case 2: curve.vector.position = VectorProperties::Midpoint; break; case 4: curve.vector.position = VectorProperties::Head; break; default: curve.vector.position = VectorProperties::Tail; break; } } //pie if (curve.type == GraphCurve::Pie) { // code from Origin410/500Parser h = cvehd[0x14]; curve.pie.formatPercentages = (h & 0x08); curve.pie.formatValues = !curve.pie.formatPercentages; curve.pie.positionAssociate = (h & 0x80); curve.pie.formatCategories = (h & 0x20); h = cvehd[0x19]; curve.pie.radius = 100 - h; h = cvehd[0x1A]; curve.pie.distance = h; curve.pie.formatAutomatic = true; curve.pie.viewAngle = 90; curve.pie.thickness = 33; curve.pie.rotation = 0; curve.pie.horizontalOffset = 0; if (cvehdsz > 0xA9) { // code from Origin750Parser.cpp h = cvehd[0x92]; curve.pie.formatPercentages = (h & 0x01); curve.pie.formatValues = (h & 0x02); curve.pie.positionAssociate = (h & 0x08); curve.pie.clockwiseRotation = (h & 0x20); curve.pie.formatCategories = (h & 0x80); curve.pie.formatAutomatic = cvehd[0x93]; stmp.str(cvehd.substr(0x94)); GET_SHORT(stmp, curve.pie.distance) curve.pie.viewAngle = cvehd[0x96]; curve.pie.thickness = cvehd[0x98]; stmp.str(cvehd.substr(0x9A)); GET_SHORT(stmp, curve.pie.rotation) stmp.str(cvehd.substr(0x9E)); GET_SHORT(stmp, curve.pie.displacement) stmp.str(cvehd.substr(0xA0)); GET_SHORT(stmp, curve.pie.radius) GET_SHORT(stmp, curve.pie.horizontalOffset) stmp.str(cvehd.substr(0xA6)); GET_INT(stmp, curve.pie.displacedSectionCount) } } //surface if (glayer.isXYY3D || curve.type == GraphCurve::Mesh3D) { curve.surface.type = cvehd[0x17]; h = cvehd[0x1C]; if ((h & 0x60) == 0x60) curve.surface.grids = SurfaceProperties::X; else if (h & 0x20) curve.surface.grids = SurfaceProperties::Y; else if (h & 0x40) curve.surface.grids = SurfaceProperties::None; else curve.surface.grids = SurfaceProperties::XY; curve.surface.sideWallEnabled = (h & 0x10); curve.surface.frontColor = getColor(cvehd.substr(0x1D,4)); h = cvehd[0x13]; curve.surface.backColorEnabled = (h & 0x08); curve.surface.surface.fill = (h & 0x10); curve.surface.surface.contour = (h & 0x40); curve.surface.topContour.fill = (h & 0x02); curve.surface.topContour.contour = (h & 0x04); curve.surface.bottomContour.fill = (h & 0x80); curve.surface.bottomContour.contour = (h & 0x01); if (cvehdsz > 0x165) { stmp.str(cvehd.substr(0x14C)); GET_SHORT(stmp, w) curve.surface.gridLineWidth = (double)w/500.0; curve.surface.gridColor = getColor(cvehd.substr(0x14E,4)); curve.surface.backColor = getColor(cvehd.substr(0x15A,4)); curve.surface.xSideWallColor = getColor(cvehd.substr(0x15E,4)); curve.surface.ySideWallColor = getColor(cvehd.substr(0x162,4)); } if (cvehdsz > 0xA9) { stmp.str(cvehd.substr(0x94)); GET_SHORT(stmp, w) curve.surface.surface.lineWidth = (double)w/500.0; curve.surface.surface.lineColor = getColor(cvehd.substr(0x96,4)); stmp.str(cvehd.substr(0xB4)); GET_SHORT(stmp, w) curve.surface.topContour.lineWidth = (double)w/500.0; curve.surface.topContour.lineColor = getColor(cvehd.substr(0xB6,4)); stmp.str(cvehd.substr(0xA4)); GET_SHORT(stmp, w) curve.surface.bottomContour.lineWidth = (double)w/500.0; curve.surface.bottomContour.lineColor = getColor(cvehd.substr(0xA6,4)); } } if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) { if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) glayer.isXYY3D = false; ColorMap& colorMap = (curve.type == GraphCurve::Mesh3D ? curve.surface.colorMap : curve.colorMap); h = cvehd[0x13]; colorMap.fillEnabled = (h & 0x82); if ((curve.type == GraphCurve::Contour) && (cvehdsz > 0x89)) { stmp.str(cvehd.substr(0x7A)); GET_SHORT(stmp, curve.text.fontSize) h = cvehd[0x83]; curve.text.fontUnderline = (h & 0x1); curve.text.fontItalic = (h & 0x2); curve.text.fontBold = (h & 0x8); curve.text.whiteOut = (h & 0x20); curve.text.color = getColor(cvehd.substr(0x86,4)); } if (cvedtsz > 0x6C) { getColorMap(colorMap, cvedt, cvedtsz); } else { colorMap = glayer.colorMap; } } if (fileVersion >= 850) { curve.lineTransparency = cvehd[0x9C]; h = cvehd[0x9D]; curve.fillAreaWithLineTransparency = !h; curve.fillAreaTransparency = cvehd[0x11E]; } if (cvehdsz > 0x143) { curve.fillAreaColor = getColor(cvehd.substr(0xC2,4)); stmp.str(cvehd.substr(0xC6)); GET_SHORT(stmp, w) curve.fillAreaPatternWidth = (double)w/500.0; curve.fillAreaPatternColor = getColor(cvehd.substr(0xCA,4)); curve.fillAreaPattern = cvehd[0xCE]; curve.fillAreaPatternBorderStyle = cvehd[0xCF]; stmp.str(cvehd.substr(0xD0)); GET_SHORT(stmp, w) curve.fillAreaPatternBorderWidth = (double)w/500.0; curve.fillAreaPatternBorderColor = getColor(cvehd.substr(0xD2,4)); curve.fillAreaTransparency = cvehd[0x11E]; curve.lineColor = getColor(cvehd.substr(0x16A,4)); if (curve.type != GraphCurve::Contour) curve.text.color = curve.lineColor; curve.symbolFillColor = getColor(cvehd.substr(0x12E,4)); curve.symbolColor = getColor(cvehd.substr(0x132,4)); curve.vector.color = curve.symbolColor; h = cvehd[0x136]; curve.symbolThickness = (h == 255 ? 1 : h); curve.pointOffset = cvehd[0x137]; h = cvehd[0x138]; curve.symbolFillTransparency = cvehd[0x139]; h = cvehd[0x143]; curve.connectSymbols = (h&0x8); } } } void OriginAnyParser::getAxisBreakProperties(string abdata, unsigned int abdatasz) { istringstream stmp; (void) abdatasz; if (ispread != -1) { // spreadsheet } else if (imatrix != -1) { // matrix } else if (iexcel != -1) { // excel } else { // graph GraphLayer& glayer = graphs[igraph].layers[ilayer]; unsigned char h = abdata[0x02]; if (h == 2) { glayer.xAxisBreak.minorTicksBefore = glayer.xAxis.minorTicks; glayer.xAxisBreak.scaleIncrementBefore = glayer.xAxis.step; glayer.xAxisBreak.show = true; stmp.str(abdata.substr(0x0B)); GET_DOUBLE(stmp, glayer.xAxisBreak.from) GET_DOUBLE(stmp, glayer.xAxisBreak.to) GET_DOUBLE(stmp, glayer.xAxisBreak.scaleIncrementAfter) GET_DOUBLE(stmp, glayer.xAxisBreak.position) h = abdata[0x2B]; glayer.xAxisBreak.log10 = (h == 1); glayer.xAxisBreak.minorTicksAfter = abdata[0x2C]; } else if (h == 4) { glayer.yAxisBreak.minorTicksBefore = glayer.yAxis.minorTicks; glayer.yAxisBreak.scaleIncrementBefore = glayer.yAxis.step; glayer.yAxisBreak.show = true; stmp.str(abdata.substr(0x0B)); GET_DOUBLE(stmp, glayer.yAxisBreak.from) GET_DOUBLE(stmp, glayer.yAxisBreak.to) GET_DOUBLE(stmp, glayer.yAxisBreak.scaleIncrementAfter) GET_DOUBLE(stmp, glayer.yAxisBreak.position) h = abdata[0x2B]; glayer.yAxisBreak.log10 = (h == 1); glayer.yAxisBreak.minorTicksAfter = abdata[0x2C]; } } } void OriginAnyParser::getAxisParameterProperties(string apdata, unsigned int apdatasz, int naxis) { istringstream stmp; static int iaxispar = 0; if (igraph != -1) { unsigned char h = 0; unsigned short w = 0; GraphLayer& glayer = graphs[igraph].layers[ilayer]; GraphAxis axis = glayer.xAxis; if (naxis == 1) { axis = glayer.xAxis; } else if (naxis == 2) { axis = glayer.yAxis; } else if (naxis == 3) { axis = glayer.zAxis; } if (iaxispar == 0) { // minor Grid h = apdata[0x26]; axis.minorGrid.hidden = (h==0); axis.minorGrid.color = apdata[0x0F]; axis.minorGrid.style = apdata[0x12]; stmp.str(apdata.substr(0x15)); GET_SHORT(stmp, w) axis.minorGrid.width = (double)w/500.0; } else if (iaxispar == 1) { // major Grid h = apdata[0x26]; axis.majorGrid.hidden = (h==0); axis.majorGrid.color = apdata[0x0F]; axis.majorGrid.style = apdata[0x12]; stmp.str(apdata.substr(0x15)); GET_SHORT(stmp, w) axis.majorGrid.width = (double)w/500.0; } else if (iaxispar == 2) { // tickaxis 0 h = apdata[0x26]; axis.tickAxis[0].showMajorLabels = (h & 0x40); axis.tickAxis[0].color = apdata[0x0F]; stmp.str(apdata.substr(0x13)); GET_SHORT(stmp, w) axis.tickAxis[0].rotation = w/10; GET_SHORT(stmp, w) axis.tickAxis[0].fontSize = w; h = apdata[0x1A]; axis.tickAxis[0].fontBold = (h & 0x08); stmp.str(apdata.substr(0x23)); GET_SHORT(stmp, w) h = apdata[0x25]; unsigned char h1 = apdata[0x26]; axis.tickAxis[0].valueType = (ValueType)(h & 0x0F); pair column; switch (axis.tickAxis[0].valueType) { case Numeric: /*switch ((h>>4)) { case 0x9: axis.tickAxis[0].valueTypeSpecification=1; break; case 0xA: axis.tickAxis[0].valueTypeSpecification=2; break; case 0xB: axis.tickAxis[0].valueTypeSpecification=3; break; default: axis.tickAxis[0].valueTypeSpecification=0; }*/ if ((h>>4) > 7) { axis.tickAxis[0].valueTypeSpecification = (h>>4) - 8; axis.tickAxis[0].decimalPlaces = h1 - 0x40; } else { axis.tickAxis[0].valueTypeSpecification = (h>>4); axis.tickAxis[0].decimalPlaces = -1; } break; case Time: case Date: case Month: case Day: case ColumnHeading: axis.tickAxis[0].valueTypeSpecification = h1 - 0x40; break; case Text: case TickIndexedDataset: case Categorical: column = findDataByIndex(w-1); if (column.first.size() > 0) { axis.tickAxis[0].dataName = column.first; axis.tickAxis[0].columnName = column.second; } break; case TextNumeric: // Numeric Decimal 1.000 axis.tickAxis[0].valueType = Numeric; axis.tickAxis[0].valueTypeSpecification = 0; break; } } else if (iaxispar == 3) { // formataxis 0 h = apdata[0x26]; axis.formatAxis[0].hidden = (h == 0); axis.formatAxis[0].color = apdata[0x0F]; if (apdatasz > 0x4B) { stmp.str(apdata.substr(0x4A)); GET_SHORT(stmp, w) axis.formatAxis[0].majorTickLength = (double)w/10.0; } stmp.str(apdata.substr(0x15)); GET_SHORT(stmp, w) axis.formatAxis[0].thickness = (double)w/500.0; h = apdata[0x25]; axis.formatAxis[0].minorTicksType = (h>>6); axis.formatAxis[0].majorTicksType = ((h>>4) & 3); axis.formatAxis[0].axisPosition = (h & 0x0F); switch (axis.formatAxis[0].axisPosition) { // TODO: check if correct case 1: h = apdata[0x37]; axis.formatAxis[0].axisPositionValue = (double)h; break; case 2: stmp.str(apdata.substr(0x2F)); GET_DOUBLE(stmp, axis.formatAxis[0].axisPositionValue) break; } } else if (iaxispar == 4) { // tickaxis 1 h = apdata[0x26]; axis.tickAxis[1].showMajorLabels = (h & 0x40); axis.tickAxis[1].color = apdata[0x0F]; stmp.str(apdata.substr(0x13)); GET_SHORT(stmp, w) axis.tickAxis[1].rotation = w/10; GET_SHORT(stmp, w) axis.tickAxis[1].fontSize = w; h = apdata[0x1A]; axis.tickAxis[1].fontBold = (h & 0x08); stmp.str(apdata.substr(0x23)); GET_SHORT(stmp, w) h = apdata[0x25]; unsigned char h1 = apdata[0x26]; axis.tickAxis[1].valueType = (ValueType)(h & 0x0F); pair column; switch (axis.tickAxis[1].valueType) { case Numeric: /*switch ((h>>4)) { case 0x9: axis.tickAxis[1].valueTypeSpecification=1; break; case 0xA: axis.tickAxis[1].valueTypeSpecification=2; break; case 0xB: axis.tickAxis[1].valueTypeSpecification=3; break; default: axis.tickAxis[1].valueTypeSpecification=0; }*/ if ((h>>4) > 7) { axis.tickAxis[1].valueTypeSpecification = (h>>4) - 8; axis.tickAxis[1].decimalPlaces = h1 - 0x40; } else { axis.tickAxis[1].valueTypeSpecification = (h>>4); axis.tickAxis[1].decimalPlaces = -1; } break; case Time: case Date: case Month: case Day: case ColumnHeading: axis.tickAxis[1].valueTypeSpecification = h1 - 0x40; break; case Text: case TickIndexedDataset: case Categorical: column = findDataByIndex(w-1); if (column.first.size() > 0) { axis.tickAxis[1].dataName = column.first; axis.tickAxis[1].columnName = column.second; } break; case TextNumeric: // Numeric Decimal 1.000 axis.tickAxis[1].valueType = Numeric; axis.tickAxis[1].valueTypeSpecification = 0; break; } } else if (iaxispar == 5) { // formataxis 1 h = apdata[0x26]; axis.formatAxis[1].hidden = (h == 0); axis.formatAxis[1].color = apdata[0x0F]; if (apdatasz > 0x4B) { stmp.str(apdata.substr(0x4A)); GET_SHORT(stmp, w) axis.formatAxis[1].majorTickLength = (double)w/10.0; } stmp.str(apdata.substr(0x15)); GET_SHORT(stmp, w) axis.formatAxis[1].thickness = (double)w/500.0; h = apdata[0x25]; axis.formatAxis[1].minorTicksType = (h>>6); axis.formatAxis[1].majorTicksType = ((h>>4) & 3); axis.formatAxis[1].axisPosition = (h & 0x0F); switch (axis.formatAxis[1].axisPosition) { // TODO: check if correct case 1: h = apdata[0x37]; axis.formatAxis[1].axisPositionValue = (double)h; break; case 2: stmp.str(apdata.substr(0x2F)); GET_DOUBLE(stmp, axis.formatAxis[1].axisPositionValue) break; } } if (naxis == 1) { glayer.xAxis = axis; } else if (naxis == 2) { glayer.yAxis = axis; } else if (naxis == 3) { glayer.zAxis = axis; } iaxispar++; iaxispar %= 6; } } void OriginAnyParser::getNoteProperties(string nwehd, unsigned int nwehdsz, string nwelb, unsigned int nwelbsz, string nwect, unsigned int nwectsz) { istringstream stmp; (void) nwehdsz; (void) nwelbsz; (void) nwectsz; // note window position and size Rect rect; unsigned int coord; stmp.str(nwehd); GET_INT(stmp, coord) rect.left = coord; GET_INT(stmp, coord) rect.top = coord; GET_INT(stmp, coord) rect.right = coord; GET_INT(stmp, coord) rect.bottom = coord; string name = nwelb.c_str(); // ResultsLog note window has left, top, right, bottom all zero. // All other parameters are also zero, except "name" and "text". if (!rect.bottom || !rect.right) { resultsLog = nwect.c_str(); return; } unsigned char state = nwehd[0x18]; double creationDate, modificationDate; stmp.str(nwehd.substr(0x20)); GET_DOUBLE(stmp, creationDate) GET_DOUBLE(stmp, modificationDate) unsigned char c = nwehd[0x38]; unsigned int labellen = 0; stmp.str(nwehd.substr(0x3C)); GET_INT(stmp, labellen) notes.push_back(Note(name)); notes.back().objectID = objectIndex; ++objectIndex; notes.back().frameRect = rect; notes.back().creationDate = doubleToPosixTime(creationDate); notes.back().modificationDate = doubleToPosixTime(modificationDate); if (c == 0x01) notes.back().title = Window::Label; else if (c == 0x02) notes.back().title = Window::Name; else notes.back().title = Window::Both; if (state == 0x07) notes.back().state = Window::Minimized; else if (state == 0x0b) notes.back().state = Window::Maximized; notes.back().hidden = (state & 0x40); if (labellen > 1) { notes.back().label = nwect.substr(0,labellen); notes.back().text = nwect.substr(labellen).c_str(); } else { notes.back().text = nwect.c_str(); } } void OriginAnyParser::getColorMap(ColorMap& cmap, string cmapdata, unsigned int cmapdatasz) { istringstream stmp; unsigned int cmoffset = 0; // color maps for matrix annotations have a different offset than graph curve's colormaps if (imatrix != -1) { cmoffset = 0x14; } else if (igraph != -1) { cmoffset = 0x6C; } else { return; } stmp.str(cmapdata.substr(cmoffset)); unsigned int colorMapSize = 0; GET_INT(stmp, colorMapSize) // check we have enough data to fill the map unsigned int minDataSize = cmoffset + 0x114 + (colorMapSize+2)*0x38; if (minDataSize > cmapdatasz) { cerr << "WARNING: Too few data while getting ColorMap. Needed: at least " << minDataSize << " bytes. Have: " << cmapdatasz << " bytes." << endl; LOG_PRINT(logfile, "WARNING: Too few data while getting ColorMap. Needed: at least %d bytes. Have: %d bytes.\n", minDataSize, cmapdatasz) return; } unsigned int lvl_offset = 0; for (unsigned int i = 0; i < colorMapSize + 3; ++i) { lvl_offset = cmoffset + 0x114 + i*0x38; ColorMapLevel level; level.fillPattern = cmapdata[lvl_offset]; level.fillPatternColor = getColor(cmapdata.substr(lvl_offset+0x04, 4)); stmp.str(cmapdata.substr(lvl_offset+0x08)); unsigned short w; GET_SHORT(stmp, w) level.fillPatternLineWidth = (double)w/500.0; level.lineStyle = cmapdata[lvl_offset+0x10]; stmp.str(cmapdata.substr(lvl_offset+0x12)); GET_SHORT(stmp, w) level.lineWidth = (double)w/500.0; level.lineColor = getColor(cmapdata.substr(lvl_offset+0x14, 4)); unsigned char h = cmapdata[lvl_offset+0x1A]; level.labelVisible = (h & 0x1); level.lineVisible = !(h & 0x2); level.fillColor = getColor(cmapdata.substr(lvl_offset+0x28, 4)); double value = 0.0; stmp.str(cmapdata.substr(lvl_offset+0x30)); GET_DOUBLE(stmp, value) cmap.levels.push_back(make_pair(value, level)); } } void OriginAnyParser::getZcolorsMap(ColorMap& colorMap, string cmapdata, unsigned int cmapdatasz) { istringstream stmp; (void) cmapdatasz; Color lowColor;//color below lowColor.type = Origin::Color::Custom; lowColor.custom[0] = cmapdata[0x0E]; lowColor.custom[1] = cmapdata[0x0F]; lowColor.custom[2] = cmapdata[0x10]; // skip an unsigned char at 0x11 Color highColor;//color above highColor.type = Origin::Color::Custom; highColor.custom[0] = cmapdata[0x12]; highColor.custom[1] = cmapdata[0x13]; highColor.custom[2] = cmapdata[0x14]; // skip an unsigned char at 0x15 unsigned short colorMapSize; stmp.str(cmapdata.substr(0x16)); GET_SHORT(stmp, colorMapSize) // skip a short at 0x18-0x19 for (int i = 0; i < 4; ++i) {//low, high, middle and missing data colors Color color; (void) color; color.type = Origin::Color::Custom; color.custom[0] = cmapdata[0x1A+4*i]; color.custom[1] = cmapdata[0x1B+4*i]; color.custom[2] = cmapdata[0x1C+4*i]; } double zmin, zmax, zmissing; stmp.str(cmapdata.substr(0x2A)); GET_DOUBLE(stmp, zmin); GET_DOUBLE(stmp, zmax); GET_DOUBLE(stmp, zmissing); short val; for (int i = 0; i < 2; ++i) { Color color; (void) color; color.type = Origin::Color::Custom; color.custom[0] = cmapdata[0x66+10*i]; color.custom[1] = cmapdata[0x67+10*i]; color.custom[2] = cmapdata[0x68+10*i]; // skip an unsigned char at 0x69+10*i stmp.str(cmapdata.substr(0x6A+10*i)); GET_SHORT(stmp, val) } ColorMapLevel level; level.fillColor = lowColor; colorMap.levels.push_back(make_pair(zmin, level)); for (int i = 0; i < (colorMapSize + 1); ++i) { Color color; (void) color; color.type = Origin::Color::Custom; color.custom[0] = cmapdata[0x7A+10*i]; color.custom[1] = cmapdata[0x7B+10*i]; color.custom[2] = cmapdata[0x7C+10*i]; // skip an unsigned char at 0x7D+10*i stmp.str(cmapdata.substr((0x7E)+10*i)); GET_SHORT(stmp, val) level.fillColor = color; colorMap.levels.push_back(make_pair(val, level)); } level.fillColor = highColor; colorMap.levels.push_back(make_pair(zmax, level)); } void OriginAnyParser::getProjectLeafProperties(tree::iterator current_folder, string ptldt, unsigned int ptldtsz) { istringstream stmp; (void) ptldtsz; stmp.str(ptldt); unsigned int file_type = 0, file_object_id = 0; GET_INT(stmp, file_type); GET_INT(stmp, file_object_id); if (file_type == 0x100000) { // Note window if ((file_object_id <= notes.size()) && (notes.size()>0)) { projectTree.append_child(current_folder, ProjectNode(notes[file_object_id].name, ProjectNode::Note)); } } else { // other windows pair object = findObjectByIndex(file_object_id); projectTree.append_child(current_folder, ProjectNode(object.second, object.first)); } } void OriginAnyParser::getProjectFolderProperties(tree::iterator current_folder, string flehd, unsigned int flehdsz) { istringstream stmp; (void) flehdsz; unsigned char a = flehd[0x02]; (*current_folder).active = (a == 1); double creationDate, modificationDate; stmp.str(flehd.substr(0x10)); GET_DOUBLE(stmp, creationDate); GET_DOUBLE(stmp, modificationDate); (*current_folder).creationDate = doubleToPosixTime(creationDate); (*current_folder).modificationDate = doubleToPosixTime(modificationDate); } void OriginAnyParser::outputProjectTree() { unsigned int windowsCount = spreadSheets.size()+matrixes.size()+excels.size()+graphs.size()+notes.size(); cout << "Project has " << windowsCount << " windows." << endl; cout << "Origin project Tree" << endl; char cdsz[21]; for (tree::iterator it = projectTree.begin(projectTree.begin()); it != projectTree.end(projectTree.begin()); ++it) { strftime(cdsz, sizeof(cdsz), "%F %T", gmtime(&(*it).creationDate)); cout << string(projectTree.depth(it) - 1, ' ') << (*it).name.c_str() << "\t" << cdsz << endl; } } diff --git a/liborigin/OriginAnyParser.h b/liborigin/OriginAnyParser.h index 672e6bc0d..33e8d6dfb 100644 --- a/liborigin/OriginAnyParser.h +++ b/liborigin/OriginAnyParser.h @@ -1,87 +1,88 @@ /* * OriginAnyParser.h * * Copyright 2017 Miquel Garriga * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Parser for all versions. Based mainly on Origin750Parser.h */ #ifndef ORIGIN_ANY_PARSER_H #define ORIGIN_ANY_PARSER_H #include "OriginParser.h" #include "endianfstream.hh" #include #include // for floor() using namespace std; using namespace Origin; class OriginAnyParser : public OriginParser { public: OriginAnyParser(const string& fileName); bool parse(); protected: unsigned int readObjectSize(); string readObjectAsString(unsigned int); void readFileVersion(); void readGlobalHeader(); bool readDataSetElement(); bool readWindowElement(); bool readLayerElement(); unsigned int readAnnotationList(); bool readAnnotationElement(); bool readCurveElement(); bool readAxisBreakElement(); bool readAxisParameterElement(unsigned int); bool readParameterElement(); bool readNoteElement(); void readProjectTree(); unsigned int readFolderTree(tree::iterator, unsigned int); void readProjectLeaf(tree::iterator); void readAttachmentList(); bool getColumnInfoAndData(string, unsigned int, string, unsigned int); void getMatrixValues(string, unsigned int, short, char, char, int); void getWindowProperties(Origin::Window&, string, unsigned int); void getLayerProperties(string, unsigned int); Origin::Color getColor(string); void getAnnotationProperties(string, unsigned int, string, unsigned int, string, unsigned int, string, unsigned int); void getCurveProperties(string, unsigned int, string, unsigned int); void getAxisBreakProperties(string, unsigned int); void getAxisParameterProperties(string, unsigned int, int); void getNoteProperties(string, unsigned int, string, unsigned int, string, unsigned int); void getColorMap(ColorMap&, string, unsigned int); void getZcolorsMap(ColorMap&, string, unsigned int); void getProjectLeafProperties(tree::iterator, string, unsigned int); void getProjectFolderProperties(tree::iterator, string, unsigned int); void outputProjectTree(); inline time_t doubleToPosixTime(double jdt) { /* 2440587.5 is julian date for the unixtime epoch */ return (time_t) floor((jdt - 2440587) * 86400. + 0.5); } iendianfstream file; FILE *logfile; - unsigned int d_file_size, objectIndex; + unsigned long d_file_size; + unsigned int objectIndex; int ispread, imatrix, iexcel, igraph; int ilayer; }; #endif // ORIGIN_ANY_PARSER_H diff --git a/liborigin/OriginFile.cpp b/liborigin/OriginFile.cpp index 715aadb3e..0128a5bb9 100644 --- a/liborigin/OriginFile.cpp +++ b/liborigin/OriginFile.cpp @@ -1,243 +1,244 @@ /*************************************************************************** File : OriginFile.cpp -------------------------------------------------------------------- Copyright : (C) 2005-2008, 2017 Stefan Gerlach Copyright : (C) 2007-2008 Alex Kargovsky, Ion Vasilief Email (use @ for *) : kargovsky*yumr.phys.msu.su, ion_vasilief*yahoo.fr Description : Origin file import class ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "OriginFile.h" #include #include OriginFile::OriginFile(const string& fileName) : fileVersion(0) { ifstream file(fileName.c_str(), ios_base::binary); if (!file.is_open()) { cerr << "Could not open " << fileName.c_str() << "!" << endl; exit(EXIT_FAILURE); } -#ifndef NO_CODE_GENERATION_FOR_LOG +#ifdef GENERATE_CODE_FOR_LOG FILE *logfile = NULL; logfile = fopen("./opjfile.log", "w"); if (logfile == NULL) { cerr << "Could not open opjfile.log !" << endl; exit(EXIT_FAILURE); } -#endif // NO_CODE_GENERATION_FOR_LOG +#endif // GENERATE_CODE_FOR_LOG string vers; getline(file, vers); unsigned int majorVersion = strtol(vers.substr(5,1).c_str(),0,10); char locale_decpoint = vers[6]; (void) locale_decpoint; // supress compiler warning buildVersion = strtol(vers.substr(7).c_str(),0,10); unsigned int buildNumber = strtol(vers.substr(12).c_str(),0,10); (void) buildNumber; // supress compiler warning file.close(); LOG_PRINT(logfile, "File: %s\n", fileName.c_str()) // translate version unsigned int newFileVersion = 0; if (majorVersion==3) { if (buildVersion < 830) fileVersion = 350; else fileVersion = 410; } else if (buildVersion >= 110 && buildVersion <= 141) // 4.1 fileVersion = 410; else if (buildVersion <= 210) // 5.0 fileVersion = 500; else if (buildVersion < 2624) // 6.0 fileVersion = 600; else if (buildVersion < 2628) // 6.0 SR1 fileVersion = 601; else if (buildVersion < 2635) // 6.0 SR4 fileVersion = 604; else if (buildVersion < 2656) // 6.1 fileVersion = 610; else if (buildVersion < 2659) // 7.0 SR0 (2656-2658) fileVersion = 700; - else if (buildVersion <2664) // 7.0 SR1 (2659-2663) + else if (buildVersion < 2664) // 7.0 SR1 (2659-2663) fileVersion = 701; else if (buildVersion < 2672) // 7.0 SR2 (2664-2671) fileVersion = 702; else if (buildVersion < 2673) // 7.0 SR3 (2672-2672) fileVersion = 703; else if (buildVersion < 2766) // 7.0 SR4 (2673-2765) fileVersion = 704; else if (buildVersion < 2878) // 7.5 (2766-2877) fileVersion = 750; else if (buildVersion < 2881) // 8.0 SR0 (2878-2880) fileVersion = 800; else if (buildVersion < 2892) // 8.0 SR1,SR2,SR3 (2878-2891) fileVersion = 801; else if (buildVersion < 2944) // 8.0 SR4, 8.1 SR1-SR4 (2891-2943) fileVersion = 810; else if (buildVersion < 2947) // 8.5 SR0, SR1 (2944-2946) fileVersion = 850; else if (buildVersion < 2962) // 8.5.1 SR0, SR1, SR2 fileVersion = 851; else if (buildVersion < 2980) // 8.6 SR0, SR1, SR2, SR3 fileVersion = 860; else if (buildVersion < 3025) // 9.0 SR0, SR1, SR2 fileVersion = 900; else if (buildVersion < 3078) // 9.1 SR0, SR1, SR2, SR3 fileVersion = 910; else if (buildVersion < 3117) { // 2015 (9.2) SR0, SR1, SR2 fileVersion = 920; newFileVersion = 20150; } else if (buildVersion < 3169) { // 2016 (9.3.0) SR0 fileVersion = 930; newFileVersion = 20160; } else if (buildVersion < 3172) { // 2016.1 (9.3.1), 2016.2 (9.3.2) SR1, SR2 fileVersion = 931; newFileVersion = 20161; } else if (buildVersion < 3225) { // 2017.0 (9.4.0) SR0 fileVersion = 940; newFileVersion = 20170; } else { // 2017.1 (9.4.1) SR1 or newer fileVersion = 941; newFileVersion = 20171; LOG_PRINT(logfile, "Found project version 2017.1 (9.4.1) or newer\n") } - if (fileVersion < 920) + if (newFileVersion == 0) { LOG_PRINT(logfile, "Found project version %.2f\n", fileVersion/100.0) - else if (fileVersion < 941) + } else if (fileVersion < 941) { LOG_PRINT(logfile, "Found project version %.1f (%.2f)\n", newFileVersion/10.0, fileVersion/100.0) + } // Close logfile, will be reopened in parser routine. // There are ways to keep logfile open and pass it to parser routine, // but I choose to do the same as with 'file', close it and reopen in 'parse' // routines. -#ifndef NO_CODE_GENERATION_FOR_LOG +#ifdef GENERATE_CODE_FOR_LOG fclose(logfile); -#endif // NO_CODE_GENERATION_FOR_LOG +#endif // GENERATE_CODE_FOR_LOG parser.reset(createOriginAnyParser(fileName)); } bool OriginFile::parse() { parser->buildVersion = buildVersion; parser->fileVersion = fileVersion; return parser->parse(); } double OriginFile::version() const { return (parser->fileVersion)/100.0; } const tree* OriginFile::project() const { return &parser->projectTree; } vector::size_type OriginFile::datasetCount() const { return parser->datasets.size(); } Origin::SpreadColumn& OriginFile::dataset(vector::size_type ds) const { return parser->datasets[ds]; } vector::size_type OriginFile::spreadCount() const { return parser->spreadSheets.size(); } Origin::SpreadSheet& OriginFile::spread(vector::size_type s) const { return parser->spreadSheets[s]; } vector::size_type OriginFile::matrixCount() const { return parser->matrixes.size(); } Origin::Matrix& OriginFile::matrix(vector::size_type m) const { return parser->matrixes[m]; } vector::size_type OriginFile::functionCount() const { return parser->functions.size(); } vector::size_type OriginFile::functionIndex(const string& name) const { return parser->findFunctionByName(name); } Origin::Function& OriginFile::function(vector::size_type f) const { return parser->functions[f]; } vector::size_type OriginFile::graphCount() const { return parser->graphs.size(); } Origin::Graph& OriginFile::graph(vector::size_type g) const { return parser->graphs[g]; } vector::size_type OriginFile::noteCount() const { return parser->notes.size(); } Origin::Note& OriginFile::note(vector::size_type n) const { return parser->notes[n]; } vector::size_type OriginFile::excelCount() const { return parser->excels.size(); } Origin::Excel& OriginFile::excel(vector::size_type e) const { return parser->excels[e]; } string OriginFile::resultsLogString() const { return parser->resultsLog; } diff --git a/liborigin/OriginObj.h b/liborigin/OriginObj.h index 97f0c1b35..0f2e65f72 100644 --- a/liborigin/OriginObj.h +++ b/liborigin/OriginObj.h @@ -1,910 +1,897 @@ /*************************************************************************** File : OriginObj.h -------------------------------------------------------------------- Copyright : (C) 2005-2007, 2017 Stefan Gerlach (C) 2007-2008 Alex Kargovsky, Ion Vasilief Email (use @ for *) : kargovsky*yumr.phys.msu.su, ion_vasilief*yahoo.fr Description : Origin internal object classes ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef ORIGIN_OBJ_H #define ORIGIN_OBJ_H #include #include #include #include -#ifndef LVERSION // LabPlot does not need boost -#include "boost/variant.hpp" -#endif using namespace std; #define _ONAN (-1.23456789E-300) namespace Origin { enum ValueType {Numeric = 0, Text = 1, Time = 2, Date = 3, Month = 4, Day = 5, ColumnHeading = 6, TickIndexedDataset = 7, TextNumeric = 9, Categorical = 10}; // Numeric Format: // 1000 | 1E3 | 1k | 1,000 enum NumericFormat {Decimal = 0, Scientific = 1, Engineering = 2, DecimalWithMarks = 3}; // Time Format: // hh:mm | hh | hh:mm:ss | hh:mm:ss.zz | hh ap | hh:mm ap | mm:ss // mm:ss.zz | hhmm | hhmmss | hh:mm:ss.zzz enum TimeFormat {TIME_HH_MM = 0, TIME_HH = 1, TIME_HH_MM_SS = 2, TIME_HH_MM_SS_ZZ = 3, TIME_HH_AP = 4, TIME_HH_MM_AP = 5, TIME_MM_SS = 6, TIME_MM_SS_ZZ = 7, TIME_HHMM = 8, TIME_HHMMSS = 9, TIME_HH_MM_SS_ZZZ = 10}; // Date Format: // dd/MM/yyyy | dd/MM/yyyy HH:mm | dd/MM/yyyy HH:mm:ss | dd.MM.yyyy | y. (year abbreviation) | MMM d // M/d | d | ddd | First letter of day | yyyy | yy | dd.MM.yyyy hh:mm | dd.MM.yyyy hh:mm:ss // yyMMdd | yyMMdd hh:mm | yyMMdd hh:mm:ss | yyMMdd hhmm | yyMMdd hhmmss | MMM // First letter of month | Quartal | M-d-yyyy (Custom1) | hh:mm:ss.zzzz (Custom2) enum DateFormat {DATE_DD_MM_YYYY = -128, DATE_DD_MM_YYYY_HH_MM = -119, DATE_DD_MM_YYYY_HH_MM_SS = -118, DATE_DDMMYYYY = 0, DATE_Y = 1, DATE_MMM_D = 2, DATE_M_D = 3, DATE_D = 4, DATE_DDD = 5, DATE_DAY_LETTER = 6, DATE_YYYY = 7, DATE_YY = 8, DATE_DDMMYYYY_HH_MM = 9, DATE_DDMMYYYY_HH_MM_SS = 10, DATE_YYMMDD = 11, DATE_YYMMDD_HH_MM = 12, DATE_YYMMDD_HH_MM_SS = 13, DATE_YYMMDD_HHMM = 14, DATE_YYMMDD_HHMMSS = 15, DATE_MMM = 16, DATE_MONTH_LETTER = 17, DATE_Q = 18, DATE_M_D_YYYY = 19, DATE_HH_MM_SS_ZZZZ = 20}; // Month Format: // MMM | MMMM | First letter of month enum MonthFormat {MONTH_MMM = 0, MONTH_MMMM = 1, MONTH_LETTER = 2}; // ddd | dddd | First letter of day enum DayOfWeekFormat {DAY_DDD = 0, DAY_DDDD = 1, DAY_LETTER = 2}; enum NumericDisplayType {DefaultDecimalDigits = 0, DecimalPlaces = 1, SignificantDigits = 2}; enum Attach {Frame = 0, Page = 1, Scale = 2}; enum BorderType {BlackLine = 0, Shadow = 1, DarkMarble = 2, WhiteOut = 3, BlackOut = 4, None = -1}; enum FillPattern {NoFill = 0, BDiagDense = 1, BDiagMedium = 2, BDiagSparse = 3, FDiagDense = 4, FDiagMedium = 5, FDiagSparse = 6, DiagCrossDense = 7, DiagCrossMedium = 8, DiagCrossSparse = 9, HorizontalDense = 10, HorizontalMedium = 11, HorizontalSparse = 12, VerticalDense = 13, VerticalMedium = 14, VerticalSparse = 15, CrossDense = 16, CrossMedium = 17, CrossSparse = 18}; struct Color { enum ColorType {None = 0, Automatic = 1, Regular = 2, Custom = 3, Increment = 4, Indexing = 5, RGB = 6, Mapping = 7}; enum RegularColor {Black = 0, Red = 1, Green = 2, Blue = 3, Cyan = 4, Magenta = 5, Yellow = 6, DarkYellow = 7, Navy = 8, Purple = 9, Wine = 10, Olive = 11, DarkCyan = 12, Royal= 13, Orange = 14, Violet = 15, Pink = 16, White = 17, LightGray = 18, Gray = 19, LTYellow = 20, LTCyan = 21, LTMagenta = 22, DarkGray = 23/*, Custom = 255*/}; ColorType type; union { unsigned char regular; unsigned char custom[3]; unsigned char starting; unsigned char column; }; }; struct Rect { short left; short top; short right; short bottom; Rect(short width = 0, short height = 0) : left(0) , top(0) , right(width) , bottom(height) { }; int height() const { return bottom - top; }; int width() const { return right - left; }; bool isValid() const { return height() > 0 && width() > 0; } }; struct ColorMapLevel { Color fillColor; unsigned char fillPattern; Color fillPatternColor; double fillPatternLineWidth; bool lineVisible; Color lineColor; unsigned char lineStyle; double lineWidth; bool labelVisible; }; typedef vector > ColorMapVector; struct ColorMap { bool fillEnabled; ColorMapVector levels; }; struct Window { enum State {Normal, Minimized, Maximized}; enum Title {Name, Label, Both}; string name; string label; int objectID; bool hidden; State state; Title title; Rect frameRect; time_t creationDate; time_t modificationDate; Window(const string& _name= "", const string& _label = "", bool _hidden = false) : name(_name) , label(_label) , objectID(-1) , hidden(_hidden) , state(Normal) , title(Both) {}; }; -#ifdef LVERSION // LabPlot uses boost-free functions + // Variant type with boost-free functions + // see https://github.com/highperformancecoder/scidavis/commit/7c6e07dfad80dbe190af29ffa8a56c82a8aa9180 // see https://www.ojdip.net/2013/10/implementing-a-variant-type-in-cpp/ // https://stackoverflow.com/questions/35648390/tagged-union-c // https://books.google.de/books?id=PSUNAAAAQBAJ&pg=PA217&lpg=PA217&dq=c%2B%2B+tagged+union+string&source=bl&ots=DqArIieZ8H&sig=k2a6okxxgUuEkLw48hFJChkIG9o&hl=en&sa=X&ved=0ahUKEwjylreR08DUAhWBVRoKHWPSBqE4ChDoAQhUMAg#v=onepage&q=c%2B%2B%20tagged%20union%20string&f=false - typedef struct Variant { - enum vtype {V_DOUBLE, V_STRING} type; - union { - double as_double; - string as_string; - }; - - Variant() { - type = V_DOUBLE; - } - Variant(const double d) { - if (type == V_STRING) - as_string.~string(); - type = V_DOUBLE; - as_double = d; - //printf("Variant(d) = %g (check = %g)\n", d, as_double); - } - Variant(const string& s) { - if (type == V_STRING) - as_string = s; - else { - type = V_STRING; - new(&as_string) string(s); - } - //printf("Variant(s) = %s (check = %s)\n", s.c_str(), as_string.c_str()); + typedef class Variant { + public: + enum vtype {V_DOUBLE, V_STRING}; + vtype type() const {return m_type;} + double as_double() const {return m_double;} + const char* as_string() const {return m_string;} + + Variant() {} + Variant(const double d): m_double(d) {} + Variant(const string& s): m_type(V_STRING) + { + asgString(s.c_str()); } - Variant(const Variant& v) { - //printf("Variant(v) type = %d\n", v.type); - type = v.type; - switch (v.type) { + Variant(const Variant& v): m_type(v.m_type) { + switch (v.m_type) { case V_DOUBLE: - as_double = v.as_double; + m_double = v.m_double; break; case V_STRING: - new(&as_string) string(v.as_string); + asgString(v.m_string); + break; } } -/* - Origin::Variant& operator=(const Origin::Variant& v) { - printf("Variant=() type = %d, new type = %d\n", type, v.type); - if (type == V_STRING && v.type == V_STRING) { - as_string = v.as_string; - return *this; - } - if (type == V_STRING) - as_string.~string(); + Origin::Variant& operator=(const Origin::Variant& v) { + if (m_type == V_STRING) + delete [] m_string; - switch (v.type) { + switch (v.m_type) { case V_DOUBLE: - as_double = v.as_double; + m_double = v.m_double; break; case V_STRING: - new(&as_string) string(v.as_string); - type = v.type; + asgString(v.m_string); + break; } + m_type = v.m_type; return *this; } -*/ + ~Variant() { - // printf("~Variant()\n"); - // if (type == V_STRING) - // as_string.~string(); + //printf("~Variant()\n"); + if (m_type == V_STRING) + delete [] m_string; + } + private: + vtype m_type=V_DOUBLE; + union { + double m_double=0.; + char* m_string; + }; + void asgString(const char* x) + { + m_string=new char[strlen(x)+1]; + strcpy(m_string,x); } } variant; -#else - typedef boost::variant variant; -#endif struct SpreadColumn { enum ColumnType {X, Y, Z, XErr, YErr, Label, NONE}; string name; string dataset_name; ColumnType type; ValueType valueType; int valueTypeSpecification; int significantDigits; int decimalPlaces; NumericDisplayType numericDisplayType; string command; string comment; int width; unsigned int index; unsigned int colIndex; unsigned int sheet; vector data; SpreadColumn(const string& _name = "", unsigned int _index = 0) : name(_name) , valueType(Numeric) , valueTypeSpecification(0) , significantDigits(6) , decimalPlaces(6) , numericDisplayType(DefaultDecimalDigits) , command("") , comment("") , width(8) , index(_index) , colIndex(0) , sheet(0) {}; }; struct SpreadSheet : public Window { unsigned int maxRows; bool loose; unsigned int sheets; vector columns; SpreadSheet(const string& _name = "") : Window(_name) , loose(true) , sheets(1) {}; }; struct Excel : public Window { unsigned int maxRows; bool loose; vector sheets; Excel(const string& _name = "", const string& _label = "", int _maxRows = 0, bool _hidden = false, bool _loose = true) : Window(_name, _label, _hidden) , maxRows(_maxRows) , loose(_loose) { }; }; struct MatrixSheet { enum ViewType {DataView, ImageView}; string name; unsigned short rowCount; unsigned short columnCount; int valueTypeSpecification; int significantDigits; int decimalPlaces; NumericDisplayType numericDisplayType; string command; unsigned short width; unsigned int index; ViewType view; ColorMap colorMap; vector data; vector coordinates; MatrixSheet(const string& _name = "", unsigned int _index = 0) : name(_name) , valueTypeSpecification(0) , significantDigits(6) , decimalPlaces(6) , numericDisplayType(DefaultDecimalDigits) , command("") , width(8) , index(_index) , view(DataView) {coordinates.push_back(10.0);coordinates.push_back(10.0);coordinates.push_back(1.0);coordinates.push_back(1.0);}; }; struct Matrix : public Window { enum HeaderViewType {ColumnRow, XY}; unsigned int activeSheet; HeaderViewType header; vector sheets; Matrix(const string& _name = "") : Window(_name) , activeSheet(0) , header(ColumnRow) {}; }; struct Function { enum FunctionType {Normal, Polar}; string name; FunctionType type; string formula; double begin; double end; int totalPoints; unsigned int index; Function(const string& _name = "", unsigned int _index = 0) : name(_name) , type(Normal) , formula("") , begin(0.0) , end(0.0) , totalPoints(0) , index(_index) {}; }; struct TextBox { string text; Rect clientRect; Color color; unsigned short fontSize; int rotation; int tab; BorderType borderType; Attach attach; TextBox(const string& _text = "") : text(_text) {}; TextBox(const string& _text, const Rect& _clientRect, const Color& _color, unsigned short _fontSize, int _rotation, int _tab, BorderType _borderType, Attach _attach) : text(_text) , clientRect(_clientRect) , color(_color) , fontSize(_fontSize) , rotation(_rotation) , tab(_tab) , borderType(_borderType) , attach(_attach) {}; }; struct PieProperties { unsigned char viewAngle; unsigned char thickness; bool clockwiseRotation; short rotation; unsigned short radius; unsigned short horizontalOffset; unsigned long displacedSectionCount; // maximum - 32 sections unsigned short displacement; //labels bool formatAutomatic; bool formatValues; bool formatPercentages; bool formatCategories; bool positionAssociate; unsigned short distance; PieProperties() : clockwiseRotation(false) , formatAutomatic(false) , formatValues(false) , formatPercentages(false) , formatCategories(false) , positionAssociate(false) {}; }; struct VectorProperties { enum VectorPosition {Tail, Midpoint, Head}; Color color; double width; unsigned short arrowLenght; unsigned char arrowAngle; bool arrowClosed; string endXColumnName; string endYColumnName; VectorPosition position; string angleColumnName; string magnitudeColumnName; float multiplier; int constAngle; int constMagnitude; VectorProperties() : arrowClosed(false) , position(Tail) , multiplier(1.0) , constAngle(0) , constMagnitude(0) {}; }; struct TextProperties { enum Justify {Left, Center, Right}; Color color; bool fontBold; bool fontItalic; bool fontUnderline; bool whiteOut; Justify justify; short rotation; short xOffset; short yOffset; unsigned short fontSize; }; struct SurfaceProperties { struct SurfaceColoration { bool fill; bool contour; Color lineColor; double lineWidth; }; enum Type {ColorMap3D, ColorFill, WireFrame, Bars}; enum Grids {None, X, Y, XY}; unsigned char type; Grids grids; double gridLineWidth; Color gridColor; bool backColorEnabled; Color frontColor; Color backColor; bool sideWallEnabled; Color xSideWallColor; Color ySideWallColor; SurfaceColoration surface; SurfaceColoration topContour; SurfaceColoration bottomContour; ColorMap colorMap; }; struct PercentileProperties { unsigned char maxSymbolType; unsigned char p99SymbolType; unsigned char meanSymbolType; unsigned char p1SymbolType; unsigned char minSymbolType; Color symbolColor; Color symbolFillColor; unsigned short symbolSize; unsigned char boxRange; unsigned char whiskersRange; double boxCoeff; double whiskersCoeff; bool diamondBox; unsigned char labels; }; struct GraphCurve { enum Plot {Line = 200, Scatter=201, LineSymbol=202, Column = 203, Area = 204, HiLoClose = 205, Box = 206, ColumnFloat = 207, Vector = 208, PlotDot = 209, Wall3D = 210, Ribbon3D = 211, Bar3D = 212, ColumnStack = 213, AreaStack = 214, Bar = 215, BarStack = 216, FlowVector = 218, Histogram = 219, MatrixImage = 220, Pie = 225, Contour = 226, Unknown = 230, ErrorBar = 231, TextPlot = 232, XErrorBar = 233, SurfaceColorMap = 236, SurfaceColorFill = 237, SurfaceWireframe = 238, SurfaceBars = 239, Line3D = 240, Text3D = 241, Mesh3D = 242, XYZContour = 243, XYZTriangular = 245, LineSeries = 246, YErrorBar = 254, XYErrorBar = 255, GraphScatter3D = 0x8AF0, GraphTrajectory3D = 0x8AF1, Polar = 0x00020000, SmithChart = 0x00040000, FillArea = 0x00800000}; enum LineStyle {Solid = 0, Dash = 1, Dot = 2, DashDot = 3, DashDotDot = 4, ShortDash = 5, ShortDot = 6, ShortDashDot = 7}; enum LineConnect {NoLine = 0, Straight = 1, TwoPointSegment = 2, ThreePointSegment = 3, BSpline = 8, Spline = 9, StepHorizontal = 11, StepVertical = 12, StepHCenter = 13, StepVCenter = 14, Bezier = 15}; bool hidden; unsigned char type; string dataName; string xDataName; string xColumnName; string yColumnName; string zColumnName; Color lineColor; unsigned char lineTransparency; unsigned char lineStyle; unsigned char lineConnect; unsigned char boxWidth; double lineWidth; bool fillArea; unsigned char fillAreaType; unsigned char fillAreaPattern; Color fillAreaColor; unsigned char fillAreaTransparency; bool fillAreaWithLineTransparency; Color fillAreaPatternColor; double fillAreaPatternWidth; unsigned char fillAreaPatternBorderStyle; Color fillAreaPatternBorderColor; double fillAreaPatternBorderWidth; unsigned short symbolType; Color symbolColor; Color symbolFillColor; unsigned char symbolFillTransparency; double symbolSize; unsigned char symbolThickness; unsigned char pointOffset; bool connectSymbols; //pie PieProperties pie; //vector VectorProperties vector; //text TextProperties text; //surface SurfaceProperties surface; //contour ColorMap colorMap; }; struct GraphAxisBreak { bool show; bool log10; double from; double to; double position; double scaleIncrementBefore; double scaleIncrementAfter; unsigned char minorTicksBefore; unsigned char minorTicksAfter; GraphAxisBreak() : show(false) {}; }; struct GraphGrid { bool hidden; unsigned char color; unsigned char style; double width; }; struct GraphAxisFormat { bool hidden; unsigned char color; double thickness; double majorTickLength; int majorTicksType; int minorTicksType; int axisPosition; double axisPositionValue; TextBox label; string prefix; string suffix; string factor; }; struct GraphAxisTick { bool showMajorLabels; unsigned char color; ValueType valueType; int valueTypeSpecification; int decimalPlaces; unsigned short fontSize; bool fontBold; string dataName; string columnName; int rotation; }; struct GraphAxis { enum AxisPosition {Left = 0, Bottom, Right, Top, Front, Back}; enum Scale {Linear = 0, Log10 = 1, Probability = 2, Probit = 3, Reciprocal = 4, OffsetReciprocal = 5, Logit = 6, Ln = 7, Log2 = 8}; AxisPosition position; bool zeroLine; bool oppositeLine; double min; double max; double step; unsigned char majorTicks; unsigned char minorTicks; unsigned char scale; GraphGrid majorGrid; GraphGrid minorGrid; GraphAxisFormat formatAxis[2]; GraphAxisTick tickAxis[2]; //bottom-top, left-right }; struct Figure { enum FigureType {Rectangle, Circle}; FigureType type; Rect clientRect; Attach attach; Color color; unsigned char style; double width; Color fillAreaColor; unsigned char fillAreaPattern; Color fillAreaPatternColor; double fillAreaPatternWidth; bool useBorderColor; Figure(FigureType _type = Rectangle) : type(_type) { }; }; struct LineVertex { unsigned char shapeType; double shapeWidth; double shapeLength; double x; double y; LineVertex() : shapeType(0) , shapeWidth(0.0) , shapeLength(0.0) , x(0.0) , y(0.0) {}; }; struct Line { Rect clientRect; Color color; Attach attach; double width; unsigned char style; LineVertex begin; LineVertex end; }; struct Bitmap { Rect clientRect; Attach attach; unsigned long size; string windowName; BorderType borderType; unsigned char* data; Bitmap(const string& _name = "") : size(0) , windowName(_name) , borderType(Origin::None) , data(0) { }; Bitmap(const Bitmap& bitmap) : clientRect(bitmap.clientRect) , attach(bitmap.attach) , size(bitmap.size) , windowName(bitmap.windowName) , borderType(bitmap.borderType) { if(size > 0) { data = new unsigned char[size]; memcpy(data, bitmap.data, size); } }; ~Bitmap() { if(size > 0) delete data; }; }; struct ColorScale { bool visible; bool reverseOrder; unsigned short labelGap; unsigned short colorBarThickness; Color labelsColor; }; struct GraphLayer { Rect clientRect; TextBox legend; Color backgroundColor; BorderType borderType; GraphAxis xAxis; GraphAxis yAxis; GraphAxis zAxis; GraphAxisBreak xAxisBreak; GraphAxisBreak yAxisBreak; GraphAxisBreak zAxisBreak; double histogramBin; double histogramBegin; double histogramEnd; PercentileProperties percentile; ColorScale colorScale; ColorMap colorMap; vector texts; vector pieTexts; vector lines; vector
figures; vector bitmaps; vector curves; float xAngle; float yAngle; float zAngle; float xLength; float yLength; float zLength; int imageProfileTool; double vLine; double hLine; bool isWaterfall; int xOffset; int yOffset; bool gridOnTop; bool exchangedAxes; bool isXYY3D; bool orthographic3D; GraphLayer() : imageProfileTool(0) , isWaterfall(false) , gridOnTop(false) , exchangedAxes(false) , isXYY3D(false) , orthographic3D(false) {colorScale.visible = false;}; //bool threeDimensional; bool is3D() const { for (vector::const_iterator it = curves.begin(); it != curves.end(); ++it) { if (it->type == GraphCurve::Line3D) return true; if (it->type == GraphCurve::Mesh3D) return true; } return false; } }; struct GraphLayerRange { double min; double max; double step; GraphLayerRange(double _min = 0.0, double _max = 0.0, double _step = 0.0) : min(_min) , max(_max) , step(_step) {}; }; struct Graph : public Window { vector layers; unsigned short width; unsigned short height; bool is3D; bool isLayout; bool connectMissingData; string templateName; Graph(const string& _name = "") : Window(_name) , is3D(false) , isLayout(false) , connectMissingData(false) , templateName("") {}; }; struct Note : public Window { string text; Note(const string& _name = "") : Window(_name) {}; }; struct ProjectNode { enum NodeType {SpreadSheet, Matrix, Excel, Graph, Graph3D, Note, Folder}; NodeType type; string name; time_t creationDate; time_t modificationDate; bool active; ProjectNode(const string& _name = "", NodeType _type = Folder, const time_t _creationDate = time(NULL), const time_t _modificationDate = time(NULL), bool _active = false) : type(_type) , name(_name) , creationDate(_creationDate) , modificationDate(_modificationDate) , active(_active) {}; }; } #endif // ORIGIN_OBJ_H diff --git a/liborigin/OriginParser.h b/liborigin/OriginParser.h index e24e63b5b..cc038e64a 100644 --- a/liborigin/OriginParser.h +++ b/liborigin/OriginParser.h @@ -1,97 +1,91 @@ /*************************************************************************** File : OriginParser.h -------------------------------------------------------------------- Copyright : (C) 2008 Alex Kargovsky (kargovsky@yumr.phys.msu.su) Copyright : (C) 2017 Stefan Gerlach (stefan.gerlach@uni.kn) Description : Origin file parser base class ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #ifndef ORIGIN_PARSER_H #define ORIGIN_PARSER_H #include "OriginObj.h" #include "tree.hh" -#ifndef NO_CODE_GENERATION_FOR_LOG +#ifdef GENERATE_CODE_FOR_LOG #ifdef HAVE_WINDOWS - -#ifdef NDEBUG -#define LOG_PRINT( logfile, args, ... ) { fprintf(logfile, args); } -#else -#define LOG_PRINT( logfile, args, ... ) { int ioret = fprintf(logfile, args); assert(ioret > 0); } -#endif - +#define LOG_PRINT( logfile, ... ) { fprintf(logfile, __VA_ARGS__); } #else // NOT WINDOWS #ifdef NDEBUG #define LOG_PRINT( logfile, args... ) { fprintf(logfile, args); } #else #define LOG_PRINT( logfile, args... ) { int ioret = fprintf(logfile, args); assert(ioret > 0); } #endif #endif -#else // !NO_CODE_GENERATION_FOR_LOG +#else // !GENERATE_CODE_FOR_LOG #define LOG_PRINT( logfile, args, ... ) {}; #endif class OriginParser { public: virtual ~OriginParser() {}; virtual bool parse() = 0; vector::difference_type findSpreadByName(const string& name) const; vector::difference_type findMatrixByName(const string& name) const; vector::difference_type findFunctionByName(const string& name) const; vector::difference_type findExcelByName(const string& name) const; protected: vector::difference_type findSpreadColumnByName(vector::size_type spread, const string& name) const; vector::difference_type findExcelColumnByName(vector::size_type excel, vector::size_type sheet, const string& name) const; pair findDataByIndex(unsigned int index) const; pair findObjectByIndex(unsigned int index) const; void convertSpreadToExcel(vector::size_type spread); int findColumnByName(int spread, const string& name); private: bool iequals(const string&, const string&, const std::locale& = std::locale()) const; public: vector datasets; vector spreadSheets; vector matrixes; vector excels; vector functions; vector graphs; vector notes; tree projectTree; string resultsLog; unsigned int windowsCount; unsigned int fileVersion, buildVersion; }; OriginParser* createOriginAnyParser(const string& fileName); #endif // ORIGIN_PARSER_H diff --git a/liborigin/README b/liborigin/README index 2d12c31ee..1dd56ef88 100644 --- a/liborigin/README +++ b/liborigin/README @@ -1,33 +1,64 @@ liborigin, standalone version --------------------- -This code is an (almost) standalone library for reading OriginLab project files. +This code is a standalone library for reading OriginLab project files. It is based on the code at http://sourceforge.net/projects/liborigin http://soft.proindependent.com/liborigin2 -AUTHORS: Stefan Gerlach, Ion Vasilief, Alex Kargovsky, Miquel Garriga +AUTHORS: Knut Franke, Miquel Garriga, Stefan Gerlach, Alex Kargovsky, Russell Standish, Ion Vasilief + +DEPENDENCIES: tree.hh (included) http://tree.phi-sci.com/ -DEPENDENCIES: to compile, liborigin (still) depends on - BOOST C++ libraries http://www.boost.org/ - boost/algorithm/string.hpp, boost/variant.hpp and its dependencies. - tree.hh (included) http://tree.phi-sci.com/ - Note that the BOOST libraries are not needed at run time, - neither are linked in the executable. --------------------------------------------------------------------------- COMPILING: liborigin uses CMake for the building process. CMake is available at http://www.cmake.org/ -After installing CMake and the BOOST C++ library headers on your system, issue the following commands: +After installing CMake on your system, issue the following commands: $ mkdir build $ cd build - $ cmake ../ + $ cmake .. $ make $ make install +This will compile and install: + a shared and a static version of liborigin library + opj2dat, a program to extract data tables of an origin project into ASCII .dat files + liborigin.pc a pkg-config metadata file to get compiler and linker flags + c++ devel headers + +Individual components (origin-static, origin, opj2dat, or doc) can be generated and installed by requesting +a specific target on the make command line. +For example: + $ make origin-static +builds the static liborigin.a library only. Then: + $ make install +installs the c++ devel headers, liborigin.pc, and liborigin.a + +Doc generation requires doxygen (http://doxygen.org) + +To include liborigin in a project using cmake add + find_package(PkgConfig) + pkg_check_modules(liborigin liborigin=>3.0.0) + target_link_libraries( my_target ${liborigin_LIBRARIES} ) + target_include_directories( my_target PUBLIC ${liborigin_INCLUDE_DIRS} ) +to the project CMakeLists.txt file. + +To include liborigin in a project using qmake add + CONFIG += link_pkgconfig + PKGCONFIG += liborigin +to the project.pro file. + +Logging of origin file parsing process is deactivated by default. +To enable it define a GENERATE_CODE_FOR_LOG variable at the cmake command: + $ cmake -DGENERATE_CODE_FOR_LOG=1 .. + --------------------------------------------------------------------------- -FEATURES : +FEATURES: * supports the import of any project from version 3.5 to latest (2017) + * includes a pkg-config metadata file --------------------------------------------------------------------------- +EXAMPLES: + * opj2dat (included) extracts the data tables of an origin project file into dat files diff --git a/liborigin/doc/Doxyfile.in b/liborigin/doc/Doxyfile.in index 548084e9d..fb4716ce8 100644 --- a/liborigin/doc/Doxyfile.in +++ b/liborigin/doc/Doxyfile.in @@ -1,236 +1,336 @@ +# Doxyfile 1.8.13 + #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = liborigin -PROJECT_NUMBER = ${LIBORIGIN_VERSION_MAJOR}.${LIBORIGIN_VERSION_MINOR}.${LIBORIGIN_VERSION_BUGFIX} +PROJECT_NUMBER = @LIBORIGIN_VERSION_MAJOR@.@LIBORIGIN_VERSION_MINOR@.@LIBORIGIN_VERSION_BUGFIX@ +PROJECT_BRIEF = +PROJECT_LOGO = OUTPUT_DIRECTORY = . CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English -USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = YES INHERIT_DOCS = YES -DISTRIBUTE_GROUP_DOC = NO +SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = +TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 0 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES +EXTRACT_PACKAGE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = YES +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES -SHOW_DIRECTORIES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = #--------------------------------------------------------------------------- -# configuration options related to warning and progress messages +# Configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- -# configuration options related to the input files +# Configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = ${CMAKE_CURRENT_SOURCE_DIR} +INPUT = @CMAKE_CURRENT_SOURCE_DIR@ +INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ - *.dox \ + *.dox \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ - *.txt \ + *.txt \ *.CC \ *.C++ \ *.HH \ *.H++ \ *.C \ *.H RECURSIVE = yes -EXCLUDE = +EXCLUDE = CMakeFiles EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = *moc_* +EXCLUDE_PATTERNS = *moc_* */tree.hh */endianfstream.hh +EXCLUDE_SYMBOLS = EXAMPLE_PATH = .. EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO -IMAGE_PATH = +IMAGE_PATH = @CMAKE_CURRENT_SOURCE_DIR@ INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- -# configuration options related to source browsing +# Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index +# Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- -# configuration options related to the HTML output +# Configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = -HTML_ALIGN_MEMBERS = YES +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO +CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO -ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = NO +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- -# configuration options related to the LaTeX output +# Configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO #--------------------------------------------------------------------------- -# configuration options related to the RTF output +# Configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- -# configuration options related to the man page output +# Configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 +MAN_SUBDIR = MAN_LINKS = NO #--------------------------------------------------------------------------- -# configuration options related to the XML output +# Configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- -# configuration options related to the Perl module output +# Configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- -# Configuration::additions related to external references +# Configuration options related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES +MSCGEN_PATH = +DIA_PATH = HIDE_UNDOC_RELATIONS = YES -# recommendation: install graphviz and use HAVE_DOT = YES HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO +CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO DOT_PATH = DOTFILE_DIRS = -MAX_DOT_GRAPH_WIDTH = 1024 -MAX_DOT_GRAPH_HEIGHT = 1024 +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- -SEARCHENGINE = NO diff --git a/liborigin/doc/html/images/origin_import.png b/liborigin/doc/html/images/origin_import.png index 1bf35a40f..6aed07251 100644 Binary files a/liborigin/doc/html/images/origin_import.png and b/liborigin/doc/html/images/origin_import.png differ diff --git a/liborigin/doc/liborigin.dox b/liborigin/doc/liborigin.dox index cd84c709b..c3e5e5b2e 100644 --- a/liborigin/doc/liborigin.dox +++ b/liborigin/doc/liborigin.dox @@ -1,59 +1,51 @@ /*! - \mainpage liborigin2 + \mainpage liborigin - A library for reading OriginLab project files created with versions ranging from 6.0 to 8.1. - Any help from developers interested in working on the import of files created with other OriginLab versions is most welcome. + A library for reading OriginLab project files created with versions starting from 3.5 to latest (2017). \image html images/origin_import.png \section license License - liborigin2 is distributed under the terms of the \ref gpllicense. + liborigin is distributed under the terms of the \ref gpllicense. \section platforms Platforms - liborigin2 might be usable in all environments where you find a C/C++ compiler. + liborigin might be usable in all environments where you find a C/C++ compiler. \section dependencies Dependencies - liborigin2 depends on the following libraries: - BOOST C++ libraries (version >= 1.33.0), - tree.hh and - an old version of loglite (provided in the source archive).\n + liborigin depends on the following libraries: + tree.hh (provided in the source archive).\n + + \section Download + From liborigin sourceforge page - \section downloads Downloads - liborigin2.zip - \section installonmainpage Installation - Have a look at the \ref projectfile project file in the source archive. It is prepared for building - dynamic libraries in Win32 and Unix/X11 environments. If you don't know what to do with it, read the \ref liborigin2install file and/or - Trolltechs qmake manual. + See the \ref liborigin2install file. \section relatedprojects Related Projects - QtiPlot, data analysis and scientific plotting tool. + - SciDAVis, Scientific Data Analysis and Visualization tool. + - LabPlot a KDE-application for interactive graphing and analysis of scientific data. \section credits Credits: - \par Authors: - Ion Vasilief, Alex Kargovsky (not active anymore) - \par Contributors: - Stefan Gerlach - \par Contact: - Ion Vasilief + \par Developers: + Knut Franke, Miquel Garriga, Stefan Gerlach, Alex Kargovsky, Russell Standish, Ion Vasilief */ /*! \page gpllicense GPL License, Version 3 - \include "copying" + \include "COPYING" */ /*! - \page projectfile liborigin2.pro - \include "liborigin2.pro" + \page projectfile CMake file + \include "CMakeLists.txt" */ /*! \page liborigin2install README - \include "readme" + \include "README" */ diff --git a/liborigin/opj2dat.cpp b/liborigin/opj2dat.cpp index a6a0fba00..5cb72008c 100644 --- a/liborigin/opj2dat.cpp +++ b/liborigin/opj2dat.cpp @@ -1,125 +1,125 @@ /*************************************************************************** File : opj2dat.cpp -------------------------------------------------------------------- Copyright : (C) 2008 Stefan Gerlach (C) 2017 Miquel Garriga Email (use @ for *) : stefan.gerlach*uni-konstanz.de Description : Origin project converter ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "OriginFile.h" #include #include #include #include using namespace std; int main(int argc, char *argv[]) { if (argc < 2) { cout << "Usage : ./opj2dat [--check-only] " << endl; return -1; } cout << "opj2dat " << LIBORIGIN_VERSION_STRING << ", Copyright (C) 2008 Stefan Gerlach, 2017 Miquel Garriga" << endl; if (string(argv[1]) == "-v") return 0; bool write_spreads = true; if ((argc > 2) && (string(argv[1]) == "--check-only")) write_spreads = false; string inputfile=argv[argc-1]; OriginFile opj(inputfile); int status = opj.parse(); cout << "Parsing status = " << status << endl; cout << "OPJ PROJECT \"" << inputfile.c_str() << "\" VERSION = " << opj.version() << endl; cout << "number of datasets = " << opj.datasetCount() << endl; cout << "number of spreadsheets = " << opj.spreadCount() << endl; cout << "number of matrixes = " << opj.matrixCount() << endl; cout << "number of excels = " << opj.excelCount() << endl; cout << "number of functions = " << opj.functionCount() << endl; cout << "number of graphs = " << opj.graphCount() << endl; cout << "number of notes = " << opj.noteCount() << endl; for (unsigned int s=0;s(value); + if (value.type() == Origin::variant::V_DOUBLE) { + v = value.as_double(); if (v != _ONAN) { outf << v << "; "; } else { outf << nan("NaN") << "; "; } } - if (value.type() == typeid(string)) { - outf << std::get(value).c_str() << "; "; + if (value.type() == Origin::variant::V_STRING) { + outf << value.as_string() << "; "; } } else { outf << "; "; } } outf << endl; } outf.close(); } } return 0; } diff --git a/src/kdefrontend/datasources/ImportOpj.cpp b/src/kdefrontend/datasources/ImportOpj.cpp index cad3d54b6..e005e5363 100644 --- a/src/kdefrontend/datasources/ImportOpj.cpp +++ b/src/kdefrontend/datasources/ImportOpj.cpp @@ -1,709 +1,709 @@ /*************************************************************************** File : ImportOpj.cpp Project : LabPlot Description : Import Origin project -------------------------------------------------------------------- Copyright : (C) 2017 Stefan Gerlach (stefan.gerlach@uni.kn) adapted from SciDAVis (importOPJ.cpp) ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * ***************************************************************************/ #include "ImportOpj.h" #include "kdefrontend/MainWin.h" #include "backend/lib/macros.h" #include "backend/core/Workbook.h" #include "backend/core/column/Column.h" #include "backend/spreadsheet/Spreadsheet.h" #include "backend/matrix/Matrix.h" #include "backend/note/Note.h" #include "backend/worksheet/Worksheet.h" #include "backend/worksheet/plots/cartesian/CartesianPlot.h" #include "backend/worksheet/plots/cartesian/CartesianPlotLegend.h" #include "backend/worksheet/TextLabel.h" #include "backend/core/datatypes/Double2StringFilter.h" #include "backend/core/datatypes/DateTime2StringFilter.h" #include #include #include #include /*! \class ImportOpj \brief Importing an Origin project. \ingroup kdefrontend */ ImportOpj::ImportOpj(MainWin* parent, const QString& filename) : mw(parent) { DEBUG("Opj import started ..."); OriginFile opj((const char *)filename.toLocal8Bit()); int status = opj.parse(); DEBUG("Parsing done with status " << status); DEBUG("Starting conversion ..."); importTables(opj); importGraphs(opj); importNotes(opj); // if(filename.endsWith(".opj", Qt::CaseInsensitive)) // createProjectTree(opj); } int ImportOpj::importTables(const OriginFile &opj) { // excels (origin workbook with one or more sheets) for (unsigned int e = 0; e < opj.excelCount(); ++e) { Origin::Excel excelwb = opj.excel(e); if (excelwb.sheets.size() == 1) { // single sheet -> spreadsheet Origin::SpreadSheet spread = excelwb.sheets[0]; spread.name = excelwb.name; spread.label = excelwb.label; importSpreadsheet(0, opj, spread); } else { // multiple sheets -> workbook Workbook *workbook = new Workbook(0, excelwb.name.c_str() + QString(" - ") + excelwb.label.c_str()); for (unsigned int s = 0; s < excelwb.sheets.size(); ++s) { Origin::SpreadSheet spread = excelwb.sheets[s]; importSpreadsheet(workbook, opj, spread); } mw->addAspectToProject(workbook); } } // matrices for (unsigned int m = 0; m < opj.matrixCount(); ++m) { Origin::Matrix matrix = opj.matrix(m); importMatrix(opj, matrix); } return 0; } int ImportOpj::importSpreadsheet(Workbook* workbook, const OriginFile &opj, const Origin::SpreadSheet &spread) { Q_UNUSED(opj); int cols = spread.columns.size(); int rows = spread.maxRows; if (!cols) // do not create spreadsheet without columns return -1; QLocale locale = mw->locale(); Spreadsheet* spreadsheet; if (workbook == 0 && spread.label.length() > 0) // single sheet with label (long name) spreadsheet = new Spreadsheet(0, spread.name.c_str() + QString(" - ") + spread.label.c_str()); else // multiple sheets (TODO: name of sheets are not saved in liborigin: "Sheet1", "Sheet2", ...) spreadsheet = new Spreadsheet(0, spread.name.c_str()); spreadsheet->setRowCount(rows); spreadsheet->setColumnCount(cols); int scaling_factor = 10; //in Origin width is measured in characters while here in pixels --- need to be accurate for (int j = 0; j < cols; ++j) { Origin::SpreadColumn column = spread.columns[j]; Column *col = spreadsheet->column(j); QString name(column.name.c_str()); col->setName(name.replace(QRegExp(".*_"),"")); if (column.command.size() > 0) col->setFormula(Interval(0, rows), QString(column.command.c_str())); col->setComment(QString(column.comment.c_str())); col->setWidth((int)column.width * scaling_factor); switch(column.type){ case Origin::SpreadColumn::X: col->setPlotDesignation(AbstractColumn::X); break; case Origin::SpreadColumn::Y: col->setPlotDesignation(AbstractColumn::Y); break; case Origin::SpreadColumn::Z: col->setPlotDesignation(AbstractColumn::Z); break; case Origin::SpreadColumn::XErr: col->setPlotDesignation(AbstractColumn::XError); break; case Origin::SpreadColumn::YErr: col->setPlotDesignation(AbstractColumn::YError); break; case Origin::SpreadColumn::Label: case Origin::SpreadColumn::NONE: default: col->setPlotDesignation(AbstractColumn::NoDesignation); } QString format; switch(column.valueType) { case Origin::Numeric: case Origin::TextNumeric: { /* TODO: check this A TextNumeric column in Origin is a column whose filled cells contain either a double or a string. Here there is no equivalent column type. Set the column type as 'Numeric' or 'Text' depending on the type of first element in column. IDEA: Add a "per column" flag, settable at import dialog, to choose between both types. */ double datavalue; bool setAsText = false; col->setColumnMode(AbstractColumn::Numeric); //printf("column has %ld rows\n", column.data.size()); for (int i = 0; i < std::min((int)column.data.size(), rows); ++i) { Origin::variant v(column.data.at(i)); //printf("i=%d type = %d\n", i, v.type); - if (v.type == Origin::Variant::V_DOUBLE) { + if (v.type() == Origin::Variant::V_DOUBLE) { //printf("DOUBLE !\n"); - datavalue = v.as_double; + datavalue = v.as_double(); //printf("datavalue = %g\n", datavalue); if (datavalue == _ONAN) continue; // mark for empty cell if (!setAsText) col->setValueAt(i, datavalue); else // convert double to string for Text columns col->setTextAt(i, locale.toString(datavalue, 'g', 16)); - } else if (v.type == Origin::Variant::V_STRING) { // string + } else if (v.type() == Origin::Variant::V_STRING) { // string //printf("STRING !\n"); if (!setAsText && i == 0) { col->setColumnMode(AbstractColumn::Text); setAsText = true; } - col->setTextAt(i, (v.as_string).c_str()); + col->setTextAt(i, v.as_string()); } else { - printf("ERROR: data type = %d unknown!\n", v.type); + printf("ERROR: data type = %d unknown!\n", v.type()); } } if (column.numericDisplayType != 0) { int f = 0; switch(column.valueTypeSpecification) { case Origin::Decimal: f=1; break; case Origin::Scientific: f=2; break; case Origin::Engineering: case Origin::DecimalWithMarks: break; } Double2StringFilter *filter = static_cast(col->outputFilter()); filter->setNumericFormat(f); filter->setNumDigits(column.decimalPlaces); } break; } case Origin::Text: col->setColumnMode(AbstractColumn::Text); for (int i = 0; i < min((int)column.data.size(), rows); ++i) - col->setTextAt(i, (column.data[i].as_string).c_str()); + col->setTextAt(i, column.data[i].as_string()); break; case Origin::Time: { switch(column.valueTypeSpecification + 128) { case Origin::TIME_HH_MM: format="hh:mm"; break; case Origin::TIME_HH: format="hh"; break; case Origin::TIME_HH_MM_SS: format="hh:mm:ss"; break; case Origin::TIME_HH_MM_SS_ZZ: format="hh:mm:ss.zzz"; break; case Origin::TIME_HH_AP: format="hh ap"; break; case Origin::TIME_HH_MM_AP: format="hh:mm ap"; break; case Origin::TIME_MM_SS: format="mm:ss"; break; case Origin::TIME_MM_SS_ZZ: format="mm:ss.zzz"; break; case Origin::TIME_HHMM: format="hhmm"; break; case Origin::TIME_HHMMSS: format="hhmmss"; break; case Origin::TIME_HH_MM_SS_ZZZ: format="hh:mm:ss.zzz"; break; } for (int i = 0; i < min((int)column.data.size(), rows); ++i) - col->setValueAt(i, column.data[i].as_double); + col->setValueAt(i, column.data[i].as_double()); col->setColumnMode(AbstractColumn::DateTime); DateTime2StringFilter *filter = static_cast(col->outputFilter()); filter->setFormat(format); break; } case Origin::Date: { switch(column.valueTypeSpecification) { case Origin::DATE_DD_MM_YYYY: format="dd/MM/yyyy"; break; case Origin::DATE_DD_MM_YYYY_HH_MM: format="dd/MM/yyyy HH:mm"; break; case Origin::DATE_DD_MM_YYYY_HH_MM_SS: format="dd/MM/yyyy HH:mm:ss"; break; case Origin::DATE_DDMMYYYY: case Origin::DATE_DDMMYYYY_HH_MM: case Origin::DATE_DDMMYYYY_HH_MM_SS: format="dd.MM.yyyy"; break; case Origin::DATE_MMM_D: format="MMM d"; break; case Origin::DATE_M_D: format="M/d"; break; case Origin::DATE_D: format="d"; break; case Origin::DATE_DDD: case Origin::DATE_DAY_LETTER: format="ddd"; break; case Origin::DATE_YYYY: format="yyyy"; break; case Origin::DATE_YY: format="yy"; break; case Origin::DATE_YYMMDD: case Origin::DATE_YYMMDD_HH_MM: case Origin::DATE_YYMMDD_HH_MM_SS: case Origin::DATE_YYMMDD_HHMM: case Origin::DATE_YYMMDD_HHMMSS: format="yyMMdd"; break; case Origin::DATE_MMM: case Origin::DATE_MONTH_LETTER: format="MMM"; break; case Origin::DATE_M_D_YYYY: format="M-d-yyyy"; break; default: format="dd.MM.yyyy"; } for (int i = 0; i < min((int)column.data.size(), rows); ++i) - col->setValueAt(i, column.data[i].as_double); + col->setValueAt(i, column.data[i].as_double()); col->setColumnMode(AbstractColumn::DateTime); DateTime2StringFilter *filter = static_cast(col->outputFilter()); filter->setFormat(format); break; } case Origin::Month: { switch (column.valueTypeSpecification) { case Origin::MONTH_MMM: format = "MMM"; break; case Origin::MONTH_MMMM: format = "MMMM"; break; case Origin::MONTH_LETTER: format = "M"; break; } for (int i = 0; i < min((int)column.data.size(), rows); ++i) - col->setValueAt(i, column.data[i].as_double); + col->setValueAt(i, column.data[i].as_double()); col->setColumnMode(AbstractColumn::Month); DateTime2StringFilter *filter = static_cast(col->outputFilter()); filter->setFormat(format); break; } case Origin::Day: { switch(column.valueTypeSpecification) { case Origin::DAY_DDD: format = "ddd"; break; case Origin::DAY_DDDD: format = "dddd"; break; case Origin::DAY_LETTER: format = "d"; break; } for (int i = 0; i < min((int)column.data.size(), rows); ++i) - col->setValueAt(i, column.data[i].as_double); + col->setValueAt(i, column.data[i].as_double()); col->setColumnMode(AbstractColumn::Day); DateTime2StringFilter *filter = static_cast(col->outputFilter()); filter->setFormat(format); break; } case Origin::ColumnHeading: case Origin::TickIndexedDataset: case Origin::Categorical: break; } } //TODO // if (spread.hidden || spread.loose) // mw->hideWindow(spreadsheet); if (workbook == 0) // single sheet mw->addAspectToProject(spreadsheet); else // multiple sheets workbook->addChild(spreadsheet); return 0; } int ImportOpj::importMatrix(const OriginFile &opj, const Origin::Matrix &matrix) { Q_UNUSED(opj); unsigned int layers = matrix.sheets.size(); int scaling_factor = 10; //in Origin width is measured in characters while here in pixels --- need to be accurate for (unsigned int l = 0; l < layers; ++l) { Origin::MatrixSheet layer = matrix.sheets[l]; int colCount = layer.columnCount; int rowCount = layer.rowCount; Matrix* m = new Matrix(0, matrix.name.c_str()); m->setRowCount(rowCount); m->setColumnCount(colCount); if (!m) return false; m->setFormula(layer.command.c_str()); for (int j = 0; j < colCount; j++) m->setColumnWidth(j, layer.width * scaling_factor); for (int i = 0; i < rowCount; i++) { for (int j = 0; j < colCount; j++) { m->setCell(i, j, layer.data[j + i*colCount]); } } char format = 'g'; int prec = 6; switch (layer.valueTypeSpecification) { case 0: //Decimal 1000 format='f'; prec = layer.decimalPlaces; break; case 1: //Scientific format='e'; prec = layer.decimalPlaces; break; case 2: //Engineering case 3: //Decimal 1,000 format='g'; prec = layer.significantDigits; break; } //TODO: prec not support by Matrix Q_UNUSED(prec); m->setNumericFormat(format); mw->addAspectToProject(m); } return 0; } int ImportOpj::importNotes(const OriginFile &opj) { // int visible_count = 0; for(unsigned int n = 0; n < opj.noteCount(); ++n) { Origin::Note _note = opj.note(n); QString name = _note.name.c_str(); QRegExp rx("^@(\\S+)$"); if(rx.indexIn(name) == 0) name = name.mid(2, name.length() - 3); Note *note = new Note(name); if(!note) return -1; //note->setWindowLabel(_note.label.c_str()); note->setNote(QString(_note.text.c_str())); // TODO //cascade the notes //int dx = 20; //int dy = note->parentWidget()->frameGeometry().height() - note->height(); //note->parentWidget()->move(QPoint(visible_count*dx+xoffset*OBJECTXOFFSET, visible_count*dy)); mw->addAspectToProject(note); // visible_count++; } // if(visible_count > 0) // xoffset++; return 0; } int ImportOpj::importGraphs(const OriginFile &opj) { for(unsigned int g = 0; g < opj.graphCount(); ++g) { Origin::Graph graph = opj.graph(g); Worksheet *worksheet = new Worksheet(0, graph.name.c_str()); if (!worksheet) return -1; // worksheet->hide();//!hack used in order to avoid resize and repaint events worksheet->setComment(graph.label.c_str()); for (const auto& layer: graph.layers) { CartesianPlot* plot = new CartesianPlot(""); if (!plot) return -2; if (!layer.legend.text.empty()) { CartesianPlotLegend* legend = new CartesianPlotLegend(plot, ""); TextLabel* title = new TextLabel(legend->name(), TextLabel::PlotLegendTitle); DEBUG("TEXT =" << layer.legend.text.c_str()); QDEBUG("PARSED TEXT =" << parseOriginText(QString::fromLocal8Bit(layer.legend.text.c_str()))); title->setText(parseOriginText(QString::fromLocal8Bit(layer.legend.text.c_str()))); //legend->title() = title; legend->addChild(title); plot->addChild(legend); } // TODO: we only support one legend //add texts for (const auto &s: layer.texts) DEBUG("EXTRA TEXT =" << s.text.c_str()); // plot->newLegend(parseOriginText(QString::fromLocal8Bit(layer.texts[i].text.c_str()))); int auto_color = 0; int style = 0; for (const auto& curve: layer.curves) { QString data(curve.dataName.c_str()); int color = 0; switch(curve.type) { case Origin::GraphCurve::Line: // style = Graph::Line; break; case Origin::GraphCurve::Scatter: // style = Graph::Scatter; break; case Origin::GraphCurve::LineSymbol: // style = Graph::LineSymbols; break; case Origin::GraphCurve::ErrorBar: case Origin::GraphCurve::XErrorBar: // style = Graph::ErrorBars; break; case Origin::GraphCurve::Column: // style = Graph::VerticalBars; break; case Origin::GraphCurve::Bar: // style = Graph::HorizontalBars; break; case Origin::GraphCurve::Histogram: // style = Graph::Histogram; break; default: continue; } /* QString tableName; switch(data[0].toAscii()) { case 'T': case 'E': { tableName = data.right(data.length() - 2); Table* table = mw->table(tableName); if (!table) break; if(style == Graph::ErrorBars) { int flags=_curve.symbolType; graph->addErrorBars(QString("%1_%2").arg(tableName, _curve.xColumnName.c_str()), table, QString("%1_%2").arg(tableName, _curve.yColumnName.c_str()), ((flags&0x10)==0x10?0:1), ceil(_curve.lineWidth), ceil(_curve.symbolSize), QColor(Qt::black), (flags&0x40)==0x40, (flags&2)==2, (flags&1)==1); } else if(style == Graph::Histogram) { graph->insertCurve(table, QString("%1_%2").arg(tableName, _curve.yColumnName.c_str()), style); } else { graph->insertCurve(table, QString("%1_%2").arg(tableName, _curve.xColumnName.c_str()), QString("%1_%2").arg(tableName, _curve.yColumnName.c_str()), style); } break; } //TODO } */ /* CurveLayout cl = graph->initCurveLayout(style, layer.curves.size()); cl.sSize = ceil(_curve.symbolSize*0.5); cl.penWidth = _curve.symbolThickness; color = _curve.symbolColor.regular; if((style == Graph::Scatter || style == Graph::LineSymbols) && color == 0xF7) // 0xF7 -Automatic color color = auto_color++; cl.symCol = color; switch(_curve.symbolType & 0xFF) { case 0: //NoSymbol cl.sType = 0; break; //TODO } */ //TODO } worksheet->addChild(plot); } mw->addAspectToProject(worksheet); } return 0; } QString ImportOpj::parseOriginText(const QString &str) { QStringList lines = str.split("\n"); QString text = ""; for (int i = 0; i < lines.size(); ++i) { if(i > 0) text.append("\n"); text.append(parseOriginTags(lines[i])); } return text; } QString strreverse(const QString &str) { //QString reversing QByteArray ba = str.toLocal8Bit(); std::reverse(ba.begin(), ba.end()); return QString(ba); } // taken from SciDAVis QString ImportOpj::parseOriginTags(const QString &str) { QString line = str; //replace \l(...) and %(...) tags QRegExp rxline("\\\\\\s*l\\s*\\(\\s*\\d+\\s*\\)"); QRegExp rxcol("\\%\\(\\d+\\)"); int pos = rxline.indexIn(line); while (pos > -1) { QString value = rxline.cap(0); int len=value.length(); value.replace(QRegExp(" "),""); value="\\c{"+value.mid(3,value.length()-4)+"}"; line.replace(pos, len, value); pos = rxline.indexIn(line); } //Lookbehind conditions are not supported - so need to reverse string QRegExp rx("\\)[^\\)\\(]*\\((?!\\s*[buig\\+\\-]\\s*\\\\)"); QRegExp rxfont("\\)[^\\)\\(]*\\((?![^\\:]*\\:f\\s*\\\\)"); QString linerev = strreverse(line); QString lBracket=strreverse("&lbracket;"); QString rBracket=strreverse("&rbracket;"); QString ltagBracket=strreverse("<agbracket;"); QString rtagBracket=strreverse("&rtagbracket;"); int pos1 = rx.indexIn(linerev); int pos2 = rxfont.indexIn(linerev); while (pos1>-1 || pos2>-1) { if(pos1==pos2) { QString value = rx.cap(0); int len=value.length(); value=rBracket+value.mid(1,len-2)+lBracket; linerev.replace(pos1, len, value); } else if ((pos1>pos2&&pos2!=-1)||pos1==-1) { QString value = rxfont.cap(0); int len=value.length(); value=rtagBracket+value.mid(1,len-2)+ltagBracket; linerev.replace(pos2, len, value); } else if ((pos2>pos1&&pos1!=-1)||pos2==-1) { QString value = rx.cap(0); int len=value.length(); value=rtagBracket+value.mid(1,len-2)+ltagBracket; linerev.replace(pos1, len, value); } pos1=rx.indexIn(linerev); pos2=rxfont.indexIn(linerev); } linerev.replace(ltagBracket, "("); linerev.replace(rtagBracket, ")"); line = strreverse(linerev); //replace \b(...), \i(...), \u(...), \g(...), \+(...), \-(...), \f:font(...) tags const QString rxstr[] = { "\\\\\\s*b\\s*\\(", "\\\\\\s*i\\s*\\(", "\\\\\\s*u\\s*\\(", "\\\\\\s*g\\s*\\(", "\\\\\\s*\\+\\s*\\(", "\\\\\\s*\\-\\s*\\(", "\\\\\\s*f\\:[^\\(]*\\("}; int postag[]={0,0,0,0,0,0,0}; QString ltag[]={"","","","","","",""}; QString rtag[]={"","","","","","",""}; QRegExp rxtags[7]; for(int i=0; i<7; ++i) rxtags[i].setPattern(rxstr[i]+"[^\\(\\)]*\\)"); bool flag=true; while(flag) { for(int i=0; i<7; ++i) { postag[i] = rxtags[i].indexIn(line); while (postag[i] > -1) { QString value = rxtags[i].cap(0); int len=value.length(); int pos2=value.indexOf("("); if(i<6) value=ltag[i]+value.mid(pos2+1,len-pos2-2)+rtag[i]; else { int posfont=value.indexOf("f:"); value=ltag[i].arg(value.mid(posfont+2,pos2-posfont-2))+value.mid(pos2+1,len-pos2-2)+rtag[i]; } line.replace(postag[i], len, value); postag[i] = rxtags[i].indexIn(line); } } flag=false; for(int i=0; i<7; ++i) { if(rxtags[i].indexIn(line)>-1) { flag=true; break; } } } //replace unclosed tags for(int i=0; i<6; ++i) line.replace(QRegExp(rxstr[i]), ltag[i]); rxfont.setPattern(rxstr[6]); pos = rxfont.indexIn(line); while (pos > -1) { QString value = rxfont.cap(0); int len=value.length(); int posfont=value.indexOf("f:"); value=ltag[6].arg(value.mid(posfont+2,len-posfont-3)); line.replace(pos, len, value); pos = rxfont.indexIn(line); } line.replace("&lbracket;", "("); line.replace("&rbracket;", ")"); return line; }