From 1032e234a746946182d79d9feb4fb98e4ad67751 Mon Sep 17 00:00:00 2001 From: Russell Standish Date: Sun, 7 Mar 2021 09:29:39 +1100 Subject: [PATCH] Revert "Update makeDist.sh to handle submodules." This reverts commit 1c27a636ef7aef249e5c789b109eaf9598f9e60c. --- 3rdparty/CMakeLists.txt | 84 + 3rdparty/config.h | 40 + 3rdparty/liborigin.pro | 36 + 3rdparty/liborigin2/FORMAT | 77 + 3rdparty/liborigin2/Origin410Parser.cpp | 1218 +++++++ 3rdparty/liborigin2/Origin410Parser.h | 44 + 3rdparty/liborigin2/Origin500Parser.cpp | 1366 ++++++++ 3rdparty/liborigin2/Origin500Parser.h | 46 + 3rdparty/liborigin2/Origin610Parser.cpp | 1592 ++++++++++ 3rdparty/liborigin2/Origin610Parser.h | 49 + 3rdparty/liborigin2/Origin700Parser.cpp | 1249 ++++++++ 3rdparty/liborigin2/Origin700Parser.h | 45 + 3rdparty/liborigin2/Origin750Parser.cpp | 2680 ++++++++++++++++ 3rdparty/liborigin2/Origin750Parser.h | 90 + 3rdparty/liborigin2/Origin800Parser.cpp | 951 ++++++ 3rdparty/liborigin2/Origin800Parser.h | 51 + 3rdparty/liborigin2/Origin810Parser.cpp | 160 + 3rdparty/liborigin2/Origin810Parser.h | 44 + 3rdparty/liborigin2/Origin850Parser.cpp | 1075 +++++++ 3rdparty/liborigin2/Origin850Parser.h | 43 + 3rdparty/liborigin2/OriginDefaultParser.cpp | 471 +++ 3rdparty/liborigin2/OriginDefaultParser.h | 47 + 3rdparty/liborigin2/OriginFile.cpp | 239 ++ 3rdparty/liborigin2/OriginFile.h | 75 + 3rdparty/liborigin2/OriginObj.h | 809 +++++ 3rdparty/liborigin2/OriginParser.cpp | 217 ++ 3rdparty/liborigin2/OriginParser.h | 89 + 3rdparty/liborigin2/copying | 674 ++++ 3rdparty/liborigin2/doc/Doxyfile | 236 ++ .../doc/html/images/origin_import.png | Bin 0 -> 57301 bytes 3rdparty/liborigin2/doc/liborigin2.dox | 62 + 3rdparty/liborigin2/endianfstream.hh | 233 ++ 3rdparty/liborigin2/liborigin2.pri | 26 + 3rdparty/liborigin2/liborigin2.pro | 19 + 3rdparty/liborigin2/readme | 24 + 3rdparty/liborigin2/tree.hh | 2786 +++++++++++++++++ 3rdparty/minigzip/minigzip.c | 317 ++ 3rdparty/patch-configs.py | 23 + makeDist.sh | 13 +- 39 files changed, 17288 insertions(+), 12 deletions(-) create mode 100644 3rdparty/CMakeLists.txt create mode 100644 3rdparty/config.h create mode 100644 3rdparty/liborigin.pro create mode 100644 3rdparty/liborigin2/FORMAT create mode 100644 3rdparty/liborigin2/Origin410Parser.cpp create mode 100644 3rdparty/liborigin2/Origin410Parser.h create mode 100644 3rdparty/liborigin2/Origin500Parser.cpp create mode 100644 3rdparty/liborigin2/Origin500Parser.h create mode 100644 3rdparty/liborigin2/Origin610Parser.cpp create mode 100644 3rdparty/liborigin2/Origin610Parser.h create mode 100644 3rdparty/liborigin2/Origin700Parser.cpp create mode 100644 3rdparty/liborigin2/Origin700Parser.h create mode 100644 3rdparty/liborigin2/Origin750Parser.cpp create mode 100644 3rdparty/liborigin2/Origin750Parser.h create mode 100644 3rdparty/liborigin2/Origin800Parser.cpp create mode 100644 3rdparty/liborigin2/Origin800Parser.h create mode 100644 3rdparty/liborigin2/Origin810Parser.cpp create mode 100644 3rdparty/liborigin2/Origin810Parser.h create mode 100644 3rdparty/liborigin2/Origin850Parser.cpp create mode 100644 3rdparty/liborigin2/Origin850Parser.h create mode 100644 3rdparty/liborigin2/OriginDefaultParser.cpp create mode 100644 3rdparty/liborigin2/OriginDefaultParser.h create mode 100644 3rdparty/liborigin2/OriginFile.cpp create mode 100644 3rdparty/liborigin2/OriginFile.h create mode 100644 3rdparty/liborigin2/OriginObj.h create mode 100644 3rdparty/liborigin2/OriginParser.cpp create mode 100644 3rdparty/liborigin2/OriginParser.h create mode 100644 3rdparty/liborigin2/copying create mode 100644 3rdparty/liborigin2/doc/Doxyfile create mode 100644 3rdparty/liborigin2/doc/html/images/origin_import.png create mode 100644 3rdparty/liborigin2/doc/liborigin2.dox create mode 100644 3rdparty/liborigin2/endianfstream.hh create mode 100644 3rdparty/liborigin2/liborigin2.pri create mode 100644 3rdparty/liborigin2/liborigin2.pro create mode 100644 3rdparty/liborigin2/readme create mode 100644 3rdparty/liborigin2/tree.hh create mode 100755 3rdparty/minigzip/minigzip.c create mode 100644 3rdparty/patch-configs.py diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt new file mode 100644 index 000000000..c9da3c384 --- /dev/null +++ b/3rdparty/CMakeLists.txt @@ -0,0 +1,84 @@ + +set( CMAKE_AUTOMOC OFF ) +set( CMAKE_AUTOUIC OFF ) +set( CMAKE_AUTORCC OFF ) + +# minigzip: mini gzip implementation +add_library( minigzip "minigzip/minigzip.c" ) +target_link_libraries( minigzip ZLIB::ZLIB ) + +if (Qt5Gui_FOUND) + get_target_property(QT_INCLUDE_DIR Qt5::Gui INTERFACE_INCLUDE_DIRECTORIES) + message( STATUS "Qt5 GUI found ${QT_INCLUDE_DIR}" ) +else() + message( STATUS Qt5 GUI not found ) +endif () + +# Qwt5 +option( BUILD_QWT "Build Qwt using own code" OFF ) + +if( NOT BUILD_QWT ) + find_library ( QWT_LIBRARY + NAMES qwt5-qt5 qwt-qt5 + HINTS ${QT_LIBRARY_DIR} /usr/lib64 + ) + if( NOT QWT_LIBRARY ) + set( BUILD_QWT ON CACHE BOOL "Build Qwt using own code" FORCE ) + endif() +endif() + +if( NOT BUILD_QWT ) + find_path ( QWT_INCLUDE_DIR + NAMES qwt_plot.h + HINTS ${QT_INCLUDE_DIR} + PATH_SUFFIXES qwt5 qwt5-qt5 + REQUIRED + ) + message( STATUS "Found Qwt5: ${QWT_LIBRARY}, with include: ${QWT_INCLUDE_DIR}" ) +else() + # Build Qwt5 + message( STATUS "Qwt5: using own code" ) + set(QWT_DESIGNER off) + add_subdirectory( qwt5-qt5 ) +endif() + +# QwtPlot3D +option( BUILD_QWTPLOT3D "Build QwtPlot3D using own code" OFF ) + +if( NOT BUILD_QWTPLOT3D ) + find_library ( QWTPLOT3D_LIBRARY + NAMES qwtplot3d-qt5 + HINTS ${QT_LIBRARY_DIR} + ) + if( NOT QWTPLOT3D_LIBRARY ) + set( BUILD_QWTPLOT3D ON CACHE BOOL "Build QwtPlot3D using own code" FORCE ) + endif() +endif() + +if( NOT BUILD_QWTPLOT3D ) + find_path ( QWTPLOT3D_INCLUDE_DIR + NAMES qwt3d_plot.h + HINTS ${QT_INCLUDE_DIR} + PATH_SUFFIXES qwtplot3d qwtplot3d-qt5 + REQUIRED + ) + message( STATUS "Found QwtPlot3D: ${QWTPLOT3D_LIBRARY}, with include: ${QWTPLOT3D_INCLUDE_DIR}" ) +else() + # Build QwtPlot3D + message( STATUS "QwtPlot3D: using own code" ) + add_subdirectory( qwtplot3d ) +endif() + +# liborigin +if( ORIGIN_IMPORT ) + find_package( PkgConfig ) + if( PkgConfig_FOUND ) + pkg_search_module( LIBORIGIN liborigin>=3.0.0 IMPORTED_TARGET GLOBAL ) + endif() + if( NOT PkgConfig_FOUND OR NOT LIBORIGIN_FOUND ) + message( STATUS "liborigin: using own code" ) + add_subdirectory( liborigin ) + endif() +else() + message( STATUS "liborigin not enabled" ) +endif() diff --git a/3rdparty/config.h b/3rdparty/config.h new file mode 100644 index 000000000..dca5b8c74 --- /dev/null +++ b/3rdparty/config.h @@ -0,0 +1,40 @@ +/*************************************************************************** + File : config.h.in + -------------------------------------------------------------------- + Copyright : (C) 2010 Knut Franke + Email (use @ for *) : knut.franke*gmx.de + Description : compile-time configuration defines + + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 CONFIG_H +#define CONFIG_H + +#define LIBORIGIN_VERSION_MAJOR 3 +#define LIBORIGIN_VERSION_MINOR 0 +#define LIBORIGIN_VERSION_BUGFIX 0 +#define LIBORIGIN_VERSION ((LIBORIGIN_VERSION_MAJOR << 24) | \ + (LIBORIGIN_VERSION_MINOR << 16) | \ + (LIBORIGIN_VERSION_BUGFIX << 8) ) +#define LIBORIGIN_VERSION_STRING "3.0.0" + +#endif // ifndef CONFIG_H diff --git a/3rdparty/liborigin.pro b/3rdparty/liborigin.pro new file mode 100644 index 000000000..4636d827c --- /dev/null +++ b/3rdparty/liborigin.pro @@ -0,0 +1,36 @@ +# this file is not part of the liborigin library, which uses the cmake +# system, but must be maintained separately of liborigin + +include(../../config.pri) + +TEMPLATE = lib +CONFIG += staticlib +TARGET = origin +QMAKE_CLEAN+=${TARGET} + +LIBORIGIN_VERSION_MAJOR = 3 +LIBORIGIN_VERSION_MINOR = 0 +LIBORIGIN_VERSION_BUGFIX = 0 + +# logging of parse process is disabled by default +# to enable it uncomment following line +# DEFINES += GENERATE_CODE_FOR_LOG +QMAKE_CXXFLAGS += -std=c++11 + +HEADERS += \ + config.h \ + OriginObj.h\ + OriginFile.h\ + OriginParser.h\ + tree.hh + +SOURCES += \ + OriginFile.cpp\ + OriginParser.cpp\ + OriginAnyParser.cpp + +# for converage testing +gcov { + QMAKE_CXXFLAGS+=-fprofile-arcs -ftest-coverage +} + diff --git a/3rdparty/liborigin2/FORMAT b/3rdparty/liborigin2/FORMAT new file mode 100644 index 000000000..3a689232f --- /dev/null +++ b/3rdparty/liborigin2/FORMAT @@ -0,0 +1,77 @@ +Origin 7.5 column value display +############################### +Numeric, Text&Numeric: + Decimal:1000 = 0 + Scientific:1E3 = 1 + Engeneering: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) + 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/3rdparty/liborigin2/Origin410Parser.cpp b/3rdparty/liborigin2/Origin410Parser.cpp new file mode 100644 index 000000000..6eaa77204 --- /dev/null +++ b/3rdparty/liborigin2/Origin410Parser.cpp @@ -0,0 +1,1218 @@ +/*************************************************************************** + File : Origin410Parser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 4.1 file parser 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 "Origin410Parser.h" + +Origin410Parser::Origin410Parser(const string& fileName) +: Origin500Parser(fileName) +{} + +OriginParser* createOrigin410Parser(const string& fileName) +{ + return new Origin410Parser(fileName); +} + +bool Origin410Parser::parse() +{ + unsigned int dataIndex = 0; + +#ifndef NO_LOG_FILE + // append progress in log file + logfile = fopen("opjfile.log", "a"); +#endif + + /////////////////// find column /////////////////////////////////////////////////////////// + skipLine(); + unsigned int size; + file >> size; + file.seekg(1 + size + 1 + 5, ios_base::cur); + + file >> size; + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, " [column found = %d/0x%X @ 0x%X]\n", size, size, (unsigned int) file.tellg()); + + unsigned int colpos = file.tellg(); + unsigned int current_col = 1, nr = 0, nbytes = 0; + + while(size > 0 && size <= 0x8B){// should be 0x72, 0x73 or 0x83 ? + //////////////////////////////// COLUMN HEADER ///////////////////////////////////////////// + + short data_type; + char data_type_u; + unsigned int oldpos = (unsigned int)file.tellg(); + + file.seekg(oldpos + 0x16, ios_base::beg); + file >> data_type; + + file.seekg(oldpos + 0x3F, ios_base::beg); + file >> data_type_u; + + char valuesize; + file.seekg(oldpos + 0x3D, ios_base::beg); + file >> valuesize; + + LOG_PRINT(logfile, " [valuesize = %d @ 0x%X]\n", (int)valuesize, ((unsigned int) file.tellg()-1)); + if(valuesize <= 0) + { + LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize); + valuesize = 10; + } + + file.seekg(oldpos + 0x58, ios_base::beg); + LOG_PRINT(logfile, " [Spreadsheet @ 0x%X]\n", (unsigned int) file.tellg()); + + string name(25, 0); + file >> name; + + string::size_type pos = name.find_last_of("_"); + string columnname; + if(pos != string::npos){ + columnname = name.substr(pos + 1); + name.resize(pos); + } + + LOG_PRINT(logfile, " NAME: %s\n", name.c_str()); + + unsigned int spread = 0; + pos = name.find("DPk");//multipeak fits generate these tables + if(columnname.empty() && pos == string::npos){ + LOG_PRINT(logfile, "NO COLUMN NAME FOUND! Must be a Matrix or Function."); + ////////////////////////////// READ matrices or functions //////////////////////////////////// + LOG_PRINT(logfile, " [position @ 0x%X]\n", (unsigned int) file.tellg()); + + file.seekg(oldpos + 0x18, ios_base::beg); + short signature; + file >> signature; + LOG_PRINT(logfile, " SIGNATURE : %02X @ 0x%X\n", signature, (unsigned int) file.tellg()); + + file.seekg(oldpos + size + 1, ios_base::beg); + file >> size; + + file.seekg(1, ios_base::cur); + size /= valuesize; + LOG_PRINT(logfile, " SIZE = %d\n", size); + + if (size == 1){ + functions.push_back(Function(name, dataIndex)); + ++dataIndex; + readFunction(colpos, valuesize, &oldpos); + } else if (size > 1){ + if (signature == 1){ + matrices.push_back(Matrix(name)); + matrices.back().sheets.push_back(MatrixSheet(name, dataIndex)); + ++dataIndex; + readMatrixValues(data_type, data_type_u, valuesize, size); + } else { + LOG_PRINT(logfile, "UNKNOWN SIGNATURE, SKIP DATA\n"); + file.seekg(valuesize*size, ios_base::cur); + ++dataIndex; + + if(valuesize != 8 && valuesize <= 16) + file.seekg(2, ios_base::cur); + } + } + } + else + { // worksheet + if(speadSheets.size() == 0 || findSpreadByName(name) == -1) + { + LOG_PRINT(logfile, "NEW SPREADSHEET\n"); + current_col = 1; + speadSheets.push_back(SpreadSheet(name)); + spread = speadSheets.size() - 1; + speadSheets.back().maxRows = 0; + } + else + { + spread = findSpreadByName(name); + current_col = speadSheets[spread].columns.size(); + + if(!current_col) + current_col = 1; + ++current_col; + } + + LOG_PRINT(logfile, "SPREADSHEET = %s COLUMN NAME = %s (@0x%X)\n", name.c_str(), columnname.c_str(), (unsigned int)file.tellg()); + bool validColumn = (columnname.find(".PTL") == string::npos); + if (validColumn){ + speadSheets[spread].columns.push_back(SpreadColumn(columnname, dataIndex)); + string::size_type sheetpos = speadSheets[spread].columns.back().name.find_last_of("@"); + if (sheetpos != string::npos){ + unsigned int sheet = atoi(columnname.substr(sheetpos + 1).c_str()); + if (sheet > 1){ + speadSheets[spread].columns.back().name = columnname; + speadSheets[spread].columns.back().sheet = sheet - 1; + + if (speadSheets[spread].sheets < sheet) + speadSheets[spread].sheets = sheet; + } + } + ++dataIndex; + } else + current_col--; + + ////////////////////////////// SIZE of column ///////////////////////////////////////////// + file.seekg(oldpos + size + 1, ios_base::beg); + + file >> nbytes; + if (fmod(nbytes, (double)valuesize) > 0) + LOG_PRINT(logfile, "WARNING: data section could not be read correct"); + + nr = nbytes / valuesize; + LOG_PRINT(logfile, " [number of rows = %d (%d Bytes) @ 0x%X]\n", nr, nbytes, (unsigned int)file.tellg()); + + speadSheets[spread].maxRows < nr ? speadSheets[spread].maxRows = nr : 0; + readColumnValues(spread, current_col - 1, data_type, valuesize, nr, validColumn); + } + + if (nbytes > 0 || (columnname.empty() && size)) + file.seekg(1, ios_base::cur); + + file >> size; + file.seekg(1 + size + (size > 0 ? 1 : 0), ios_base::cur); + + file >> size; + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, "\n [column found = %d/0x%X (@ 0x%X)]\n", size, size, ((unsigned int) file.tellg()-5)); + colpos = file.tellg(); + } + + //////////////////////////////////////////////////////////////////////////// + ////////////////////// HEADER SECTION ////////////////////////////////////// + + unsigned int POS = (unsigned int)file.tellg()-11; + LOG_PRINT(logfile, "\nHEADER SECTION"); + LOG_PRINT(logfile, " [position @ 0x%X]\n", POS); + + POS += 0xB; + file.seekg(POS, ios_base::beg); + while(!file.eof()){ + POS = file.tellg(); + + file >> size; + if(size == 0) + break; + + file.seekg(POS + 0x7, ios_base::beg); + string name(25, 0); + file >> name; + + file.seekg(POS, ios_base::beg); + + if(findSpreadByName(name) != -1) + readSpreadInfo(); + else if(findMatrixByName(name) != -1) + readMatrixInfo(); + else if(findExcelByName(name) != -1) + readExcelInfo(); + else if (!readGraphInfo()){ + LOG_PRINT(logfile, " %s is NOT A GRAPH!\n", name.c_str()); + graphs.pop_back(); + } + } + + file.seekg(1, ios_base::cur); + readParameters(); + + LOG_PRINT(logfile, "Done parsing\n") +#ifndef NO_LOG_FILE + fclose(logfile); +#endif + + return true; +} + +bool Origin410Parser::readGraphInfo() +{ + bool error = false; + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + + POS += 5; + + string name(25, 0); + file.seekg(POS + 0x02, ios_base::beg); + file >> name; + LOG_PRINT(logfile, " GRAPH name: %s @ 0x%X\n", name.c_str(), (unsigned int)file.tellg()); + + graphs.push_back(Graph(name)); + file.seekg(POS, ios_base::beg); + readWindowProperties(graphs.back(), size); + + file.seekg(POS + 0x23, ios_base::beg); + file >> graphs.back().width; + file >> graphs.back().height; + + file.seekg(POS + 0x38, ios_base::beg); + unsigned char c; + file >> c; + graphs.back().connectMissingData = (c & 0x40); + + file.seekg(POS + 0x45, ios_base::beg); + string templateName(20, 0); + file >> templateName; + graphs.back().templateName = templateName; + LOG_PRINT(logfile, " TEMPLATE: %s pos: 0x%X\n", templateName.c_str(), (POS + 0x45)); + + unsigned int LAYER = POS; + LAYER += size + 0x1; + + while(!file.eof()){// multilayer loop + graphs.back().layers.push_back(GraphLayer()); + GraphLayer& layer(graphs.back().layers.back()); + + // LAYER section + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x05; + + file.seekg(LAYER + 0x0F, ios_base::beg); + file >> layer.xAxis.min; + file >> layer.xAxis.max; + file >> layer.xAxis.step; + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> layer.xAxis.majorTicks; + + unsigned char g; + file >> g; file >> g; + layer.xAxis.zeroLine = (g & 0x80); + layer.xAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x37, ios_base::beg); + file >> layer.xAxis.minorTicks; + file >> layer.xAxis.scale; + + file.seekg(LAYER + 0x3A, ios_base::beg); + file >> layer.yAxis.min; + file >> layer.yAxis.max; + file >> layer.yAxis.step; + + file.seekg(LAYER + 0x56, ios_base::beg); + file >> layer.yAxis.majorTicks; + + file >> g; file >> g; + layer.yAxis.zeroLine = (g & 0x80); + layer.yAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> layer.yAxis.minorTicks; + file >> layer.yAxis.scale; + + file.seekg(LAYER + 0x68, ios_base::beg); + file >> g; + layer.gridOnTop = (g & 0x04); + layer.exchangedAxes = (g & 0x40); + + file.seekg(LAYER + 0x71, ios_base::beg); + file.read(reinterpret_cast(&layer.clientRect), sizeof(Rect)); + + unsigned char border; + file.seekg(LAYER + 0x89, ios_base::beg); + file >> border; + layer.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + + unsigned char col; + file.seekg(LAYER + 0xA7, ios_base::beg); + file >> col; + layer.backgroundColor.type = (col & 0x01) ? Origin::Color::None : Origin::Color::Regular; + file >> col; + layer.backgroundColor.regular = col; + + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + + unsigned int sectionSize; + file >> size; + sectionSize = size; + + ColorMap colorMap; + + //now structure is next : section_header_size=0x6F(4 bytes) + '\n' + section_header(0x6F bytes) + section_body_1_size(4 bytes) + '\n' + section_body_1 + section_body_2_size(maybe=0)(4 bytes) + '\n' + section_body_2 + '\n' + //possible sections: axes, legend, __BC02, _202, _231, _232, etc + //section name starts with 0x46 position + while(size && !file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + + unsigned int sectionNamePos = LAYER + 0x46; + string sec_name(41, 0); + file.seekg(sectionNamePos, ios_base::beg); + file >> sec_name; + if (!sec_name.empty()) + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), sectionNamePos); + + Rect r; + file.seekg(LAYER + 0x03, ios_base::beg); + file.read(reinterpret_cast(&r), sizeof(Rect)); + + unsigned char attach; + file.seekg(LAYER + 0x28, ios_base::beg); + file >> attach; + + unsigned char border; + file >> border; + + Color color; + file.seekg(LAYER + 0x33, ios_base::beg); + file >> color; + + LAYER += size + 0x01; + file.seekg(LAYER, ios_base::beg); + + file >> size; + //LOG_PRINT(logfile, " osize = %d (@ 0x%X)\n", size, (unsigned int)file.tellg()); + + //section_body_1 + LAYER += 0x5; + unsigned int osize = size; + unsigned int SECTION_BODY1_POS = LAYER; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisPrefixSuffixInfo(sec_name, size, layer); + + unsigned char type; + file >> type; + + LineVertex begin, end; + if (size == 21 || size == 24){//Line/Arrow + unsigned short x1, x2, y1, y2; + if (type == 2){//straight line/arrow + file >> x1; + file >> x2; + file.seekg(4, ios_base::cur); + file >> y1; + file >> y2; + file.seekg(4, ios_base::cur); + } else if (type == 4){//curved line/arrow has 4 points + file >> x1; + file.seekg(4, ios_base::cur); + file >> x2; + file >> y1; + file.seekg(4, ios_base::cur); + file >> y2; + } + + double maxx = (x1 <= x2) ? x2 : x1; + if (!x1 && !x2) + maxx = 1.0; + double maxy = (y1 <= y2) ? y2 : y1; + if (!y1 && !y2) + maxy = 1.0; + + begin.x = r.left + (double)x1/maxx*r.width(); + begin.y = r.top + (double)y1/maxy*r.height(); + end.x = r.left + (double)x2/maxx*r.width(); + end.y = r.top + (double)y2/maxy*r.height(); + + unsigned char arrows; + file >> arrows; + 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; + } + + file.seekg(3, ios_base::cur); + unsigned char sw; + file >> sw; + end.shapeLength = (double)sw; + begin.shapeLength = (double)sw; + file >> sw; + end.shapeWidth = (double)sw; + begin.shapeWidth = (double)sw; + } + + //text properties + short rotation; + file.seekg(LAYER + 0x02, ios_base::beg); + file >> rotation; + + unsigned char fontSize; + file >> fontSize; + + unsigned char tab; + file.seekg(LAYER + 0x0A, ios_base::beg); + file >> tab; + + //line properties + unsigned char lineStyle = 0; + double width = 0.0; + + file.seekg(LAYER + 0x12, ios_base::beg); + file >> lineStyle; + + unsigned short w1; + file >> w1; + width = (double)w1/500.0; + + Figure figure; + file.seekg(LAYER + 0x05, ios_base::beg); + file >> w1; + figure.width = (double)w1/500.0; + + file.seekg(LAYER + 0x07, ios_base::beg); + unsigned char fillIndex, fillType; + file >> fillIndex; + file >> figure.style; + file >> fillType; + switch(fillType){ + case 0: + figure.useBorderColor = (fillIndex >= 5); + if (fillIndex < 5){ + figure.fillAreaPattern = Origin::NoFill; + figure.fillAreaColor.type = Origin::Color::Regular; + if (fillIndex == 0) + figure.fillAreaColor.regular = 0; + else if (fillIndex == 1) + figure.fillAreaColor.regular = 18; + else if (fillIndex == 2) + figure.fillAreaColor.regular = 23; + else if (fillIndex == 3) + figure.fillAreaColor.regular = 17; + else + figure.fillAreaColor.regular = 19; + } else { + figure.fillAreaColor.type = Origin::Color::None; + if (fillIndex == 0x05) + figure.fillAreaPattern = Origin::BDiagMedium; + else if (fillIndex == 0x06) + figure.fillAreaPattern = Origin::DiagCrossMedium; + else if (fillIndex == 0x07) + figure.fillAreaPattern = Origin::FDiagMedium; + else if (fillIndex == 0x08) + figure.fillAreaPattern = Origin::HorizontalMedium; + else if (fillIndex == 0x09) + figure.fillAreaPattern = Origin::VerticalMedium; + } + break; + case 1: + figure.fillAreaPattern = Origin::NoFill; + figure.fillAreaColor.regular = fillIndex; + figure.fillAreaColor.type = Origin::Color::Regular; + break; + case 2: + figure.fillAreaColor.type = Origin::Color::None; + figure.fillAreaPatternColor.type = Origin::Color::None; + figure.useBorderColor = false; + figure.fillAreaPattern = Origin::NoFill; + break; + } + + //section_body_2_size + LAYER += size + 0x1; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + //check if it is an axis or a legend + + file.seekg(1, ios_base::cur); + if(sec_name == "XB") + { + string text(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Bottom; + layer.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(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Top; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Left; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Right; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Front; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Back; + layer.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") + { + file >> layer.zAxis.min; + file >> layer.zAxis.max; + file >> layer.zAxis.step; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> layer.zAxis.majorTicks; + + file.seekg(LAYER + 0x28, ios_base::beg); + file >> layer.zAxis.minorTicks; + file >> layer.zAxis.scale; + + file.seekg(LAYER + 0x5A, ios_base::beg); + file >> layer.xAngle; + file >> layer.yAngle; + file >> layer.zAngle; + + file.seekg(LAYER + 0x218, ios_base::beg); + file >> layer.xLength; + file >> layer.yLength; + file >> layer.zLength; + + layer.xLength /= 23.0; + layer.yLength /= 23.0; + layer.zLength /= 23.0; + + file.seekg(LAYER + 0x240, ios_base::beg); + file >> layer.orthographic3D; + } + else if(sec_name == "Legend") + { + string text(size, 0); + file >> text; + + layer.legend = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); + } + else if(sec_name == "ZCOLORS") + { + layer.isXYY3D = true; + file.seekg(LAYER + 0xE, ios_base::beg); + readColorMap(colorMap); + } + else if(sec_name == "SPECTRUM1") + { + layer.isXYY3D = false; + layer.colorScale.visible = true; + + unsigned char h; + file.seekg(24, ios_base::cur); + file >> h; + layer.colorScale.reverseOrder = h; + file.seekg(7, ios_base::cur); + file >> layer.colorScale.colorBarThickness; + file >> layer.colorScale.labelGap; + file.seekg(56, ios_base::cur); + file >> layer.colorScale.labelsColor; + } + else if(sec_name == "&0") + { + layer.isWaterfall = true; + file.seekg(SECTION_BODY1_POS, ios_base::beg); + string text(osize, 0); + file >> text; + size_t commaPos = text.find_first_of(','); + layer.xOffset = atoi(text.substr(0, commaPos).c_str()); + layer.yOffset = atoi(text.substr(commaPos + 1).c_str()); + } + else if (osize == 22 || (size && !type)) + { + string text(size, 0); + file >> text; + + sec_name.resize(3); + if (sec_name == "PIE") + layer.pieTexts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + else + layer.texts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + } + else if(osize == 0xA) // rectangle & circle + { + switch(type){ + case 0: + case 1: + figure.type = Figure::Rectangle; + LOG_PRINT(logfile, " Rectangle\n"); + break; + case 2: + case 3: + figure.type = Figure::Circle; + LOG_PRINT(logfile, " Circle\n"); + break; + } + figure.clientRect = r; + figure.attach = (Attach)attach; + figure.color = color; + + layer.figures.push_back(figure); + } + else if (osize == 21 || osize == 24) // line + { + LOG_PRINT(logfile, " Line/Arrow\n"); + layer.lines.push_back(Line()); + Line& line(layer.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(osize == 38) // bitmap + { + if (type == 4){ + unsigned long filesize = size + 14; + layer.bitmaps.push_back(Bitmap()); + Bitmap& bitmap(layer.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; + file.read(reinterpret_cast(data), size); + } else if (type == 6){ + string gname(30, 0); + file >> gname; + layer.bitmaps.push_back(Bitmap(gname)); + Bitmap& bitmap(layer.bitmaps.back()); + bitmap.clientRect = r; + bitmap.attach = (Attach)attach; + bitmap.size = 0; + bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + } + } + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + //section_body_3_size + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_3 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + file.seekg(LAYER, ios_base::beg); + file >> size; + if (!size || size != sectionSize) + break; + } + + LAYER += 0x5; + unsigned char h; + short w; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size)//check layer is not empty + { + while(!file.eof()){ + LAYER += 0x5; + + layer.curves.push_back(GraphCurve()); + GraphCurve& curve(layer.curves.back()); + + file.seekg(LAYER + 0x26, ios_base::beg); + file >> h; + curve.hidden = (h == 33); + LOG_PRINT(logfile, " hidden curve: %d\n", curve.hidden); + + file.seekg(LAYER + 0x4C, ios_base::beg); + file >> curve.type; + if (!curve.type){ + LOG_PRINT(logfile, " Found unknown curve type (%d)!\n", (int)curve.type); + } else + LOG_PRINT(logfile, " graph %d layer %d curve %d type : %d\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), (int)curve.type); + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour) + layer.isXYY3D = false; + + file.seekg(LAYER + 0x04, ios_base::beg); + file >> w; + pair column = findDataByIndex(w-1); + short nColY = w; + if(column.first.size() > 0){ + curve.dataName = column.first; + if(layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Z : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.zColumnName = column.second; + } else { + if (column.second.empty()) + column.second = "1"; + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(),graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } + } + + file.seekg(LAYER + 0x23, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if (column.first.size() > 0){ + curve.xDataName = (curve.dataName != column.first) ? column.first : ""; + + if(layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } else if (layer.isXYY3D){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } + } + + file.seekg(LAYER + 0x4D, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if(column.first.size() > 0 && layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + if(curve.dataName != column.first) + LOG_PRINT(logfile, " graph %d X and Y from different tables\n", graphs.size()); + } + + if(layer.is3D() || layer.isXYY3D) + graphs.back().is3D = true; + + if (curve.type == GraphCurve::Contour){ + file.seekg(LAYER + 0x12, ios_base::beg); + file >> curve.lineColor.regular; + curve.lineColor.type = Origin::Color::Regular; + + file >> h; + curve.lineConnect = (h & 0x40) ? GraphCurve::Straight : GraphCurve::NoLine; + colorMap.fillEnabled = (h & 0x82); + if (h & 0x01) + curve.lineColor.type = Origin::Color::None;//use color map color; + + file.seekg(1, ios_base::cur); + file >> h; + curve.lineWidth = h/10.0; + } else { + file.seekg(LAYER + 0xf, ios_base::beg); + file >> curve.lineColor.regular; + curve.lineColor.type = Origin::Color::Regular; + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> curve.lineConnect; + file >> curve.lineStyle; + + file.seekg(1, ios_base::cur); + file >> curve.boxWidth; + + file >> w; + curve.lineWidth=(double)w/500.0; + } + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> w; + curve.symbolSize=(double)w/500.0; + + if (curve.type == GraphCurve::Box || + curve.type == Origin::GraphCurve::Column || curve.type == Origin::GraphCurve::ColumnStack || + curve.type == Origin::GraphCurve::Bar || curve.type == Origin::GraphCurve::BarStack){ + curve.fillAreaPatternBorderColor = curve.lineColor; + curve.fillAreaPatternBorderWidth = curve.lineWidth; + unsigned char fillIndex, fillType; + file.seekg(LAYER + 0x17, ios_base::beg); + file >> fillIndex; + file >> fillType; + switch(fillType){ + case 0: + if (fillIndex < 5){ + curve.fillAreaPattern = Origin::NoFill; + curve.fillAreaColor.type = Origin::Color::Regular; + if (fillIndex == 0) + curve.fillAreaColor.regular = 0; + else if (fillIndex == 1) + curve.fillAreaColor.regular = 18; + else if (fillIndex == 2) + curve.fillAreaColor.regular = 23; + else if (fillIndex == 3) + curve.fillAreaColor.regular = 17; + else + curve.fillAreaColor.regular = 19; + } else { + curve.fillAreaColor.type = Origin::Color::None; + curve.fillAreaPatternColor = curve.lineColor; + if (fillIndex == 0x05) + curve.fillAreaPattern = Origin::BDiagMedium; + else if (fillIndex == 0x06) + curve.fillAreaPattern = Origin::DiagCrossMedium; + else if (fillIndex == 0x07) + curve.fillAreaPattern = Origin::FDiagMedium; + else if (fillIndex == 0x08) + curve.fillAreaPattern = Origin::HorizontalMedium; + else if (fillIndex == 0x09) + curve.fillAreaPattern = Origin::VerticalMedium; + } + break; + case 1: + curve.fillAreaPattern = Origin::NoFill; + curve.fillAreaColor.regular = fillIndex; + curve.fillAreaColor.type = Origin::Color::Regular; + break; + case 2: + curve.fillAreaColor.type = Origin::Color::None; + curve.fillAreaPatternColor.type = Origin::Color::None; + curve.fillAreaPattern = Origin::NoFill; + break; + } + + if (curve.type == GraphCurve::Box){ + layer.percentile.symbolSize = 2; + layer.percentile.diamondBox = false; + layer.percentile.boxRange = 3; //BoxCurve::r25_75 + layer.percentile.whiskersRange = 2; //BoxCurve::r5_95 + layer.percentile.p1SymbolType = 7; + layer.percentile.p99SymbolType = 7; + layer.percentile.meanSymbolType = 1; + layer.percentile.maxSymbolType = 9; + layer.percentile.minSymbolType = 9; + layer.percentile.labels = false; + layer.percentile.symbolSize = 5; + layer.percentile.symbolColor = curve.lineColor; + layer.percentile.symbolFillColor.type = Origin::Color::None; + } + } else { + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + curve.fillArea = (h==2); + file >> curve.fillAreaColor.regular; + curve.fillAreaPattern = Origin::NoFill; + } + + //text + if(!curve.type || curve.type == GraphCurve::TextPlot){ + file.seekg(LAYER + 0xf, ios_base::beg); + file >> curve.text.color.regular; + curve.text.color.type = Origin::Color::Regular; + + file.seekg(LAYER + 0x13, ios_base::beg); + file >> curve.text.rotation; + curve.text.rotation /= 10; + + file >> curve.text.fontSize; + if (curve.text.fontSize < 250) + curve.type = GraphCurve::TextPlot; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> h; + 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; + } + + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + char offset; + file.seekg(LAYER + 0x37, ios_base::beg); + file >> offset; + curve.text.xOffset = offset * 5; + file >> offset; + curve.text.yOffset = offset * 5; + } + + if (curve.type == GraphCurve::Vector){ + curve.vector.multiplier = 1.0; + curve.vector.position = VectorProperties::Tail; + curve.vector.arrowLenght = 25; + curve.vector.arrowAngle = 40; + curve.vector.arrowClosed = true; + curve.vector.width = curve.lineWidth; + + file.seekg(LAYER + 0x18, ios_base::beg); + file >> h; + 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; + + file >> h; + if (h >= 0x64 && h < 0x1F4){ + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.magnitudeColumnName = column.second; + } else + curve.vector.constMagnitude = (int)curve.symbolSize; + } + + //pie + if (curve.type == GraphCurve::Pie){ + file.seekg(LAYER + 0x14, ios_base::beg); + file >> h; + + curve.pie.formatPercentages = (h & 0x08); + curve.pie.formatValues = !curve.pie.formatPercentages; + curve.pie.positionAssociate = (h & 0x80); + curve.pie.formatCategories = (h & 0x20); + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> h; + curve.pie.radius = 100 - h; + + file >> h; + curve.pie.distance = h; + curve.pie.formatAutomatic = true; + curve.pie.viewAngle = 90; + curve.pie.thickness = 33; + curve.pie.rotation = 0; + curve.pie.horizontalOffset = 0; + + /*file.seekg(LAYER + 0x9E, ios_base::beg); + file >> curve.pie.displacement; + file.seekg(LAYER + 0xA6, ios_base::beg); + file >> curve.pie.displacedSectionCount;*/ + } + + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour){ + if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) + layer.isXYY3D = false; + + if (curve.type == GraphCurve::Mesh3D) + curve.surface.colorMap = colorMap; + else + curve.colorMap = colorMap; + + /*if (curve.type == GraphCurve::Contour){ + file.seekg(102, ios_base::cur); + file >> curve.text.fontSize; + + file.seekg(7, ios_base::cur); + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + file.seekg(2, ios_base::cur); + file >> curve.text.color; + }*/ + } + + //surface + if (layer.isXYY3D || curve.type == GraphCurve::Mesh3D){ + file.seekg(LAYER + 0x15, ios_base::beg); + file >> w; + curve.surface.gridLineWidth = (double)w/500.0; + + file.seekg(8, ios_base::cur); + file >> curve.surface.gridColor; + + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.surface.type; + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + 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); + file >> curve.surface.frontColor; + + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + curve.surface.backColorEnabled = (h & 0x08); + file.seekg(LAYER + 0x15A, ios_base::beg); + file >> curve.surface.backColor; + file >> curve.surface.xSideWallColor; + file >> curve.surface.ySideWallColor; + + curve.surface.surface.fill = (h & 0x10); + curve.surface.surface.contour = (h & 0x40); + file.seekg(LAYER + 0x94, ios_base::beg); + file >> w; + curve.surface.surface.lineWidth = (double)w/500.0; + file >> curve.surface.surface.lineColor; + + curve.surface.topContour.fill = (h & 0x02); + curve.surface.topContour.contour = (h & 0x04); + file.seekg(LAYER + 0xB4, ios_base::beg); + file >> w; + curve.surface.topContour.lineWidth = (double)w/500.0; + file >> curve.surface.topContour.lineColor; + + curve.surface.bottomContour.fill = (h & 0x80); + curve.surface.bottomContour.contour = (h & 0x01); + file.seekg(LAYER + 0xA4, ios_base::beg); + file >> w; + curve.surface.bottomContour.lineWidth = (double)w/500.0; + file >> curve.surface.bottomContour.lineColor; + } + + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.symbolType; + + curve.symbolFillColor = curve.lineColor; + curve.symbolColor = curve.lineColor; + curve.vector.color = curve.symbolColor; + + file >> curve.pointOffset; + + file.seekg(LAYER + 0x143, ios_base::beg); + file >> h; + curve.connectSymbols = (h&0x8); + + LAYER += size + 0x1; + + unsigned int newSize; + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + LAYER += newSize + (newSize > 0 ? 0x1 : 0) + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + if(newSize != size) + break; + } + } + + LAYER += 0x5; + //read axis breaks + while(!file.eof()){ + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size == 0x2D){ + LAYER += 0x5; + file.seekg(LAYER + 2, ios_base::beg); + file >> h; + + if(h == 2) { + layer.xAxisBreak.minorTicksBefore = layer.xAxis.minorTicks; + layer.xAxisBreak.scaleIncrementBefore = layer.xAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.xAxisBreak); + } else if(h == 4){ + layer.yAxisBreak.minorTicksBefore = layer.yAxis.minorTicks; + layer.yAxisBreak.scaleIncrementBefore = layer.yAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.yAxisBreak); + } + LAYER += 0x2D + 0x1; + } else + break; + } + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + size = readGraphAxisInfo(layer.xAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.yAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.zAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0) + break; + } + + file.seekg(LAYER + 0x5, ios_base::beg); + + if (error) + return false; + return true; +} diff --git a/3rdparty/liborigin2/Origin410Parser.h b/3rdparty/liborigin2/Origin410Parser.h new file mode 100644 index 000000000..7e1baad15 --- /dev/null +++ b/3rdparty/liborigin2/Origin410Parser.h @@ -0,0 +1,44 @@ +/*************************************************************************** + File : Origin410Parser.h + -------------------------------------------------------------------- + Copyright : (C) 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 4.1 file parser 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_410_PARSER_H +#define ORIGIN_410_PARSER_H + +#include "Origin500Parser.h" + +class Origin410Parser : public Origin500Parser +{ +public: + Origin410Parser(const string& fileName); + bool parse(); + +protected: + bool readGraphInfo(); +}; + +#endif // ORIGIN_410_PARSER_H diff --git a/3rdparty/liborigin2/Origin500Parser.cpp b/3rdparty/liborigin2/Origin500Parser.cpp new file mode 100644 index 000000000..0cfcaee58 --- /dev/null +++ b/3rdparty/liborigin2/Origin500Parser.cpp @@ -0,0 +1,1366 @@ +/*************************************************************************** + File : Origin500Parser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 5.0 file parser 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 "Origin500Parser.h" + +Origin500Parser::Origin500Parser(const string& fileName) +: Origin610Parser(fileName) +{} + +OriginParser* createOrigin500Parser(const string& fileName) +{ + return new Origin500Parser(fileName); +} + +bool Origin500Parser::parse() +{ + unsigned int dataIndex = 0; + +#ifndef NO_LOG_FILE + // append progress in log file + logfile = fopen("opjfile.log", "a"); +#endif + + /////////////////// find column /////////////////////////////////////////////////////////// + skipLine(); + unsigned int size; + file >> size; + file.seekg(1 + size + 1 + 5, ios_base::cur); + + file >> size; + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, " [column found = %d/0x%X @ 0x%X]\n", size, size, (unsigned int) file.tellg()); + + unsigned int colpos = file.tellg(); + unsigned int current_col = 1, nr = 0, nbytes = 0; + + while(size > 0 && size <= 0x8B){// should be 0x72, 0x73 or 0x83 ? + //////////////////////////////// COLUMN HEADER ///////////////////////////////////////////// + + short data_type; + char data_type_u; + unsigned int oldpos = (unsigned int)file.tellg(); + + file.seekg(oldpos + 0x16, ios_base::beg); + file >> data_type; + + file.seekg(oldpos + 0x3F, ios_base::beg); + file >> data_type_u; + + char valuesize; + file.seekg(oldpos + 0x3D, ios_base::beg); + file >> valuesize; + + LOG_PRINT(logfile, " [valuesize = %d @ 0x%X]\n", (int)valuesize, ((unsigned int) file.tellg()-1)); + if(valuesize <= 0){ + LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize); + valuesize = 10; + } + + file.seekg(oldpos + 0x58, ios_base::beg); + LOG_PRINT(logfile, " [Spreadsheet @ 0x%X]\n", (unsigned int) file.tellg()); + + string name(25, 0); + file >> name; + + string::size_type pos = name.find_last_of("_"); + string columnname; + if(pos != string::npos){ + columnname = name.substr(pos + 1); + name.resize(pos); + } + + LOG_PRINT(logfile, " NAME: %s\n", name.c_str()); + + unsigned int spread = 0; + if(columnname.empty()){ + LOG_PRINT(logfile, "NO COLUMN NAME FOUND! Must be a Matrix or Function."); + ////////////////////////////// READ matrices or functions //////////////////////////////////// + + LOG_PRINT(logfile, " [position @ 0x%X]\n", (unsigned int) file.tellg()); + // TODO + short signature; + file >> signature; + LOG_PRINT(logfile, " SIGNATURE : %02X @ 0x%X\n", signature, (unsigned int) file.tellg()); + + file.seekg(oldpos + size + 1, ios_base::beg); + file >> size; + LOG_PRINT(logfile, " size : %d @ 0x%X\n", size, (unsigned int) file.tellg()); + + file.seekg(1, ios_base::cur); + size /= valuesize; + LOG_PRINT(logfile, " SIZE = %d\n", size); + + if (signature == 0xA00 && size == 1) + signature = 0xAC8; + + switch(signature){ + case 0x50CA: + case 0x70CA: + case 0x50F2: + case 0x50E2: + case 0x50E7: + case 0x50DB: + case 0x50DC: + case 0xA00: + case 0xAE2: + case 0xAF2: + case 0xACA: + if (size){ + matrices.push_back(Matrix(name)); + matrices.back().sheets.push_back(MatrixSheet(name, dataIndex)); + } + ++dataIndex; + readMatrixValues(data_type, data_type_u, valuesize, size); + break; + + case 0xAC8: + functions.push_back(Function(name, dataIndex)); + ++dataIndex; + readFunction(colpos, valuesize, &oldpos); + break; + + default: + LOG_PRINT(logfile, "UNKNOWN SIGNATURE: %.2X SKIP DATA\n", signature); + file.seekg(valuesize*size, ios_base::cur); + ++dataIndex; + + if(valuesize != 8 && valuesize <= 16) + file.seekg(2, ios_base::cur); + } + } + else + { // worksheet + if(speadSheets.size() == 0 || findSpreadByName(name) == -1) + { + LOG_PRINT(logfile, "NEW SPREADSHEET\n"); + current_col = 1; + speadSheets.push_back(SpreadSheet(name)); + spread = speadSheets.size() - 1; + speadSheets.back().maxRows = 0; + } + else + { + spread = findSpreadByName(name); + current_col = speadSheets[spread].columns.size(); + + if(!current_col) + current_col = 1; + ++current_col; + } + + LOG_PRINT(logfile, "SPREADSHEET = %s COLUMN NAME = %s (@0x%X)\n", name.c_str(), columnname.c_str(), (unsigned int)file.tellg()); + bool validColumn = (columnname.find(".PTL") == string::npos); + if (validColumn){ + speadSheets[spread].columns.push_back(SpreadColumn(columnname, dataIndex)); + string::size_type sheetpos = speadSheets[spread].columns.back().name.find_last_of("@"); + if (sheetpos != string::npos){ + unsigned int sheet = atoi(columnname.substr(sheetpos + 1).c_str()); + if (sheet > 1){ + speadSheets[spread].columns.back().name = columnname; + speadSheets[spread].columns.back().sheet = sheet - 1; + + if (speadSheets[spread].sheets < sheet) + speadSheets[spread].sheets = sheet; + } + } + ++dataIndex; + } else + current_col--; + + ////////////////////////////// SIZE of column ///////////////////////////////////////////// + file.seekg(oldpos + size + 1, ios_base::beg); + + file >> nbytes; + if (fmod(nbytes, (double)valuesize) > 0) + LOG_PRINT(logfile, "WARNING: data section could not be read correct"); + + nr = nbytes / valuesize; + LOG_PRINT(logfile, " [number of rows = %d (%d Bytes) @ 0x%X]\n", nr, nbytes, (unsigned int)file.tellg()); + + speadSheets[spread].maxRows < nr ? speadSheets[spread].maxRows = nr : 0; + readColumnValues(spread, current_col - 1, data_type, valuesize, nr, validColumn); + } + + if (nbytes > 0 || (columnname.empty() && size)) + file.seekg(1, ios_base::cur); + + file >> size; + file.seekg(1 + size + (size > 0 ? 1 : 0), ios_base::cur); + + file >> size; + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, "\n [column found = %d/0x%X (@ 0x%X)]\n", size, size, ((unsigned int) file.tellg()-5)); + colpos = file.tellg(); + } + + //////////////////////////////////////////////////////////////////////////// + ////////////////////// HEADER SECTION ////////////////////////////////////// + + unsigned int POS = (unsigned int)file.tellg()-11; + LOG_PRINT(logfile, "\nHEADER SECTION"); + LOG_PRINT(logfile, " [position @ 0x%X]\n", POS); + + POS += 0xB; + file.seekg(POS, ios_base::beg); + while(!file.eof()){ + POS = file.tellg(); + + file >> size; + if(size == 0) + break; + + file.seekg(POS + 0x7, ios_base::beg); + string name(25, 0); + file >> name; + + file.seekg(POS, ios_base::beg); + + if(findSpreadByName(name) != -1) + readSpreadInfo(); + else if(findMatrixByName(name) != -1) + readMatrixInfo(); + else if(findExcelByName(name) != -1) + readExcelInfo(); + else if (!readGraphInfo()){ + LOG_PRINT(logfile, " %s is NOT A GRAPH!\n", name.c_str()); + graphs.pop_back(); + } + } + + file.seekg(1, ios_base::cur); + readParameters(); + + file.seekg(1 + 5, ios_base::cur); + readNotes(); + + LOG_PRINT(logfile, "Done parsing\n") +#ifndef NO_LOG_FILE + fclose(logfile); +#endif + + return true; +} + +void Origin500Parser::readNotes() +{ + while(!file.eof()){ + unsigned int size; + file >> size; + if(size != 28) + break; + + file.seekg(1, ios_base::cur); + + Rect rect; + unsigned int coord; + file >> coord; + rect.left = coord; + file >> coord; + rect.top = coord; + file >> coord; + rect.right = coord; + file >> coord; + rect.bottom = coord; + + unsigned char state; + file.seekg(0x8, ios_base::cur); + file >> state; + + file.seekg(4, ios_base::cur); + file >> size; + + file.seekg(1, ios_base::cur); + + string name(size, 0); + file >> name; + + notes.push_back(Note(name)); + notes.back().objectID = objectIndex; + notes.back().frameRect = rect; + + if(state == 0x04) + notes.back().state = Window::Minimized; + else if(state == 0x0a) + notes.back().state = Window::Maximized; + + ++objectIndex; + + file.seekg(1, ios_base::cur); + file >> size; + + file.seekg(1, ios_base::cur); + file >> notes.back().text.assign(size, 0); + + LOG_PRINT(logfile, "NOTE %d NAME: %s\n", notes.size(), notes.back().name.c_str()); + + file.seekg(1, ios_base::cur); + } +} + +bool Origin500Parser::readGraphInfo() +{ + bool error = false; + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + + POS += 5; + + string name(25, 0); + file.seekg(POS + 0x02, ios_base::beg); + file >> name; + LOG_PRINT(logfile, " GRAPH name: %s @ 0x%X\n", name.c_str(), (unsigned int)file.tellg()); + + graphs.push_back(Graph(name)); + file.seekg(POS, ios_base::beg); + readWindowProperties(graphs.back(), size); + + file.seekg(POS + 0x23, ios_base::beg); + file >> graphs.back().width; + file >> graphs.back().height; + + file.seekg(POS + 0x38, ios_base::beg); + unsigned char c; + file >> c; + graphs.back().connectMissingData = (c & 0x40); + + file.seekg(POS + 0x45, ios_base::beg); + string templateName(20, 0); + file >> templateName; + graphs.back().templateName = templateName; + LOG_PRINT(logfile, " TEMPLATE: %s pos: 0x%X\n", templateName.c_str(), (POS + 0x45)); + + unsigned int LAYER = POS; + LAYER += size + 0x1; + + while(!file.eof()){// multilayer loop + graphs.back().layers.push_back(GraphLayer()); + GraphLayer& layer(graphs.back().layers.back()); + + // LAYER section + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x05; + + file.seekg(LAYER + 0x0F, ios_base::beg); + file >> layer.xAxis.min; + file >> layer.xAxis.max; + file >> layer.xAxis.step; + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> layer.xAxis.majorTicks; + + unsigned char g; + file >> g; file >> g; + layer.xAxis.zeroLine = (g & 0x80); + layer.xAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x37, ios_base::beg); + file >> layer.xAxis.minorTicks; + file >> layer.xAxis.scale; + + file.seekg(LAYER + 0x3A, ios_base::beg); + file >> layer.yAxis.min; + file >> layer.yAxis.max; + file >> layer.yAxis.step; + + file.seekg(LAYER + 0x56, ios_base::beg); + file >> layer.yAxis.majorTicks; + + file >> g; file >> g; + layer.yAxis.zeroLine = (g & 0x80); + layer.yAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> layer.yAxis.minorTicks; + file >> layer.yAxis.scale; + + file.seekg(LAYER + 0x68, ios_base::beg); + file >> g; + layer.gridOnTop = (g & 0x04); + layer.exchangedAxes = (g & 0x40); + + file.seekg(LAYER + 0x71, ios_base::beg); + file.read(reinterpret_cast(&layer.clientRect), sizeof(Rect)); + + unsigned char border; + file.seekg(LAYER + 0x89, ios_base::beg); + file >> border; + layer.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + + unsigned char col; + file.seekg(LAYER + 0xA7, ios_base::beg); + file >> col; + layer.backgroundColor.type = (col & 0x01) ? Origin::Color::None : Origin::Color::Regular; + file >> col; + layer.backgroundColor.regular = col; + + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + + unsigned int sectionSize; + file >> size; + sectionSize = size; + + ColorMap colorMap; + + //now structure is next : section_header_size=0x6F(4 bytes) + '\n' + section_header(0x6F bytes) + section_body_1_size(4 bytes) + '\n' + section_body_1 + section_body_2_size(maybe=0)(4 bytes) + '\n' + section_body_2 + '\n' + //possible sections: axes, legend, __BC02, _202, _231, _232, etc + //section name starts with 0x46 position + while(size && !file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + + unsigned int sectionNamePos = LAYER + 0x46; + string sec_name(41, 0); + file.seekg(sectionNamePos, ios_base::beg); + file >> sec_name; + if (!sec_name.empty()) + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), sectionNamePos); + + Rect r; + file.seekg(LAYER + 0x03, ios_base::beg); + file.read(reinterpret_cast(&r), sizeof(Rect)); + + unsigned char attach; + file.seekg(LAYER + 0x28, ios_base::beg); + file >> attach; + + unsigned char border; + file >> border; + + Color color; + file.seekg(LAYER + 0x33, ios_base::beg); + file >> color; + + LAYER += size + 0x01; + file.seekg(LAYER, ios_base::beg); + + file >> size; + //LOG_PRINT(logfile, " osize = %d (@ 0x%X)\n", size, (unsigned int)file.tellg()); + + //section_body_1 + LAYER += 0x5; + unsigned int osize = size; + unsigned int SECTION_BODY1_POS = LAYER; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisPrefixSuffixInfo(sec_name, size, layer); + + unsigned char type; + file >> type; + + LineVertex begin, end; + if (size == 24){//Line/Arrow + unsigned short x1, x2, y1, y2; + if (type == 2){//straight line/arrow + file >> x1; + file >> x2; + file.seekg(4, ios_base::cur); + file >> y1; + file >> y2; + file.seekg(4, ios_base::cur); + } else if (type == 4){//curved line/arrow has 4 points + file >> x1; + file.seekg(4, ios_base::cur); + file >> x2; + file >> y1; + file.seekg(4, ios_base::cur); + file >> y2; + } + + double maxx = (x1 <= x2) ? x2 : x1; + if (!x1 && !x2) + maxx = 1.0; + double maxy = (y1 <= y2) ? y2 : y1; + if (!y1 && !y2) + maxy = 1.0; + + begin.x = r.left + (double)x1/maxx*r.width(); + begin.y = r.top + (double)y1/maxy*r.height(); + end.x = r.left + (double)x2/maxx*r.width(); + end.y = r.top + (double)y2/maxy*r.height(); + + unsigned char arrows; + file >> arrows; + 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; + } + + file.seekg(3, ios_base::cur); + unsigned char sw; + file >> sw; + end.shapeLength = (double)sw; + begin.shapeLength = (double)sw; + file >> sw; + end.shapeWidth = (double)sw; + begin.shapeWidth = (double)sw; + } + + //text properties + short rotation; + file.seekg(LAYER + 0x02, ios_base::beg); + file >> rotation; + + unsigned char fontSize; + file >> fontSize; + + unsigned char tab; + file.seekg(LAYER + 0x0A, ios_base::beg); + file >> tab; + + //line properties + unsigned char lineStyle = 0; + double width = 0.0; + + file.seekg(LAYER + 0x12, ios_base::beg); + file >> lineStyle; + + unsigned short w1; + file >> w1; + width = (double)w1/500.0; + + Figure figure; + file.seekg(LAYER + 0x05, ios_base::beg); + file >> w1; + figure.width = (double)w1/500.0; + + file.seekg(LAYER + 0x07, ios_base::beg); + unsigned char fillIndex, fillType; + file >> fillIndex; + file >> figure.style; + file >> fillType; + switch(fillType){ + case 0: + figure.useBorderColor = (fillIndex >= 5); + if (fillIndex < 5){ + figure.fillAreaPattern = Origin::NoFill; + figure.fillAreaColor.type = Origin::Color::Regular; + if (fillIndex == 0) + figure.fillAreaColor.regular = 0; + else if (fillIndex == 1) + figure.fillAreaColor.regular = 18; + else if (fillIndex == 2) + figure.fillAreaColor.regular = 23; + else if (fillIndex == 3) + figure.fillAreaColor.regular = 17; + else + figure.fillAreaColor.regular = 19; + } else { + figure.fillAreaColor.type = Origin::Color::None; + if (fillIndex == 0x05) + figure.fillAreaPattern = Origin::BDiagMedium; + else if (fillIndex == 0x06) + figure.fillAreaPattern = Origin::DiagCrossMedium; + else if (fillIndex == 0x07) + figure.fillAreaPattern = Origin::FDiagMedium; + else if (fillIndex == 0x08) + figure.fillAreaPattern = Origin::HorizontalMedium; + else if (fillIndex == 0x09) + figure.fillAreaPattern = Origin::VerticalMedium; + } + break; + case 1: + figure.fillAreaPattern = Origin::NoFill; + figure.fillAreaColor.regular = fillIndex; + figure.fillAreaColor.type = Origin::Color::Regular; + break; + case 2: + figure.fillAreaColor.type = Origin::Color::None; + figure.fillAreaPatternColor.type = Origin::Color::None; + figure.useBorderColor = false; + figure.fillAreaPattern = Origin::NoFill; + break; + } + + //section_body_2_size + LAYER += size + 0x1; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + //check if it is an axis or a legend + + file.seekg(1, ios_base::cur); + if(sec_name == "XB") + { + string text(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Bottom; + layer.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(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Top; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Left; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Right; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Front; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Back; + layer.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") + { + file >> layer.zAxis.min; + file >> layer.zAxis.max; + file >> layer.zAxis.step; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> layer.zAxis.majorTicks; + + file.seekg(LAYER + 0x28, ios_base::beg); + file >> layer.zAxis.minorTicks; + file >> layer.zAxis.scale; + + file.seekg(LAYER + 0x5A, ios_base::beg); + file >> layer.xAngle; + file >> layer.yAngle; + file >> layer.zAngle; + + file.seekg(LAYER + 0x218, ios_base::beg); + file >> layer.xLength; + file >> layer.yLength; + file >> layer.zLength; + + layer.xLength /= 23.0; + layer.yLength /= 23.0; + layer.zLength /= 23.0; + + file.seekg(LAYER + 0x240, ios_base::beg); + file >> layer.orthographic3D; + } + else if(sec_name == "Legend") + { + string text(size, 0); + file >> text; + + layer.legend = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); + } + else if(sec_name == "ZCOLORS") + { + layer.isXYY3D = true; + file.seekg(LAYER + 0xE, ios_base::beg); + readColorMap(colorMap); + } + else if(sec_name == "SPECTRUM1") + { + layer.isXYY3D = false; + layer.colorScale.visible = true; + + unsigned char h; + file.seekg(24, ios_base::cur); + file >> h; + layer.colorScale.reverseOrder = h; + file.seekg(7, ios_base::cur); + file >> layer.colorScale.colorBarThickness; + file >> layer.colorScale.labelGap; + file.seekg(56, ios_base::cur); + file >> layer.colorScale.labelsColor; + } + else if(sec_name == "&0") + { + layer.isWaterfall = true; + file.seekg(SECTION_BODY1_POS, ios_base::beg); + string text(osize, 0); + file >> text; + size_t commaPos = text.find_first_of(','); + layer.xOffset = atoi(text.substr(0, commaPos).c_str()); + layer.yOffset = atoi(text.substr(commaPos + 1).c_str()); + } + else if (osize == 22 || (size && !type)) + { + string text(size, 0); + file >> text; + + sec_name.resize(3); + if (sec_name == "PIE") + layer.pieTexts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + else + layer.texts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + } + else if(osize == 0xA) // rectangle & circle + { + switch(type){ + case 0: + case 1: + figure.type = Figure::Rectangle; + LOG_PRINT(logfile, " Rectangle\n"); + break; + case 2: + case 3: + figure.type = Figure::Circle; + LOG_PRINT(logfile, " Circle\n"); + break; + } + figure.clientRect = r; + figure.attach = (Attach)attach; + figure.color = color; + + layer.figures.push_back(figure); + } + else if (osize == 24) // line + { + LOG_PRINT(logfile, " Line/Arrow\n"); + layer.lines.push_back(Line()); + Line& line(layer.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(osize == 40) // bitmap + { + if (type == 4){ + unsigned long filesize = size + 14; + layer.bitmaps.push_back(Bitmap()); + Bitmap& bitmap(layer.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; + file.read(reinterpret_cast(data), size); + } else if (type == 6){ + string gname(30, 0); + file >> gname; + layer.bitmaps.push_back(Bitmap(gname)); + Bitmap& bitmap(layer.bitmaps.back()); + bitmap.clientRect = r; + bitmap.attach = (Attach)attach; + bitmap.size = 0; + bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + } + } + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + //section_body_3_size + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_3 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + file.seekg(LAYER, ios_base::beg); + file >> size; + if (!size || size != sectionSize) + break; + } + + LAYER += 0x5; + unsigned char h; + short w; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size)//check layer is not empty + { + while(!file.eof()){ + LAYER += 0x5; + + layer.curves.push_back(GraphCurve()); + GraphCurve& curve(layer.curves.back()); + + file.seekg(LAYER + 0x26, ios_base::beg); + file >> h; + curve.hidden = (h == 33); + LOG_PRINT(logfile, " hidden curve: %d\n", curve.hidden); + + file.seekg(LAYER + 0x4C, ios_base::beg); + file >> curve.type; + if (!curve.type){ + LOG_PRINT(logfile, " Found unknown curve type (%d)!\n", (int)curve.type); + } else + LOG_PRINT(logfile, " graph %d layer %d curve %d type : %d\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), (int)curve.type); + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour) + layer.isXYY3D = false; + + file.seekg(LAYER + 0x04, ios_base::beg); + file >> w; + pair column = findDataByIndex(w-1); + short nColY = w; + if(column.first.size() > 0){ + curve.dataName = column.first; + if(layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Z : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.zColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(),graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } + } + + file.seekg(LAYER + 0x23, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if (column.first.size() > 0){ + curve.xDataName = (curve.dataName != column.first) ? column.first : ""; + + if(layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } else if (layer.isXYY3D){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } + } + + file.seekg(LAYER + 0x4D, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if(column.first.size() > 0 && layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + if(curve.dataName != column.first) + LOG_PRINT(logfile, " graph %d X and Y from different tables\n", graphs.size()); + } + + if(layer.is3D() || layer.isXYY3D) + graphs.back().is3D = true; + + if (curve.type == GraphCurve::Contour){ + file.seekg(LAYER + 0x12, ios_base::beg); + file >> curve.lineColor.regular; + curve.lineColor.type = Origin::Color::Regular; + + file >> h; + curve.lineConnect = (h & 0x40) ? GraphCurve::Straight : GraphCurve::NoLine; + colorMap.fillEnabled = (h & 0x82); + if (h & 0x01) + curve.lineColor.type = Origin::Color::None;//use color map color; + + file.seekg(1, ios_base::cur); + file >> h; + curve.lineWidth = h/10.0; + } else { + file.seekg(LAYER + 0xf, ios_base::beg); + file >> curve.lineColor.regular; + curve.lineColor.type = Origin::Color::Regular; + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> curve.lineConnect; + file >> curve.lineStyle; + + file.seekg(1, ios_base::cur); + file >> curve.boxWidth; + + file >> w; + curve.lineWidth=(double)w/500.0; + } + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> w; + curve.symbolSize=(double)w/500.0; + + if (curve.type == GraphCurve::Box || + curve.type == Origin::GraphCurve::Column || curve.type == Origin::GraphCurve::ColumnStack || + curve.type == Origin::GraphCurve::Bar || curve.type == Origin::GraphCurve::BarStack){ + curve.fillAreaPatternBorderColor = curve.lineColor; + curve.fillAreaPatternBorderWidth = curve.lineWidth; + unsigned char fillIndex, fillType; + file.seekg(LAYER + 0x17, ios_base::beg); + file >> fillIndex; + file >> fillType; + switch(fillType){ + case 0: + if (fillIndex < 5){ + curve.fillAreaPattern = Origin::NoFill; + curve.fillAreaColor.type = Origin::Color::Regular; + if (fillIndex == 0) + curve.fillAreaColor.regular = 0; + else if (fillIndex == 1) + curve.fillAreaColor.regular = 18; + else if (fillIndex == 2) + curve.fillAreaColor.regular = 23; + else if (fillIndex == 3) + curve.fillAreaColor.regular = 17; + else + curve.fillAreaColor.regular = 19; + } else { + curve.fillAreaColor.type = Origin::Color::None; + curve.fillAreaPatternColor = curve.lineColor; + if (fillIndex == 0x05) + curve.fillAreaPattern = Origin::BDiagMedium; + else if (fillIndex == 0x06) + curve.fillAreaPattern = Origin::DiagCrossMedium; + else if (fillIndex == 0x07) + curve.fillAreaPattern = Origin::FDiagMedium; + else if (fillIndex == 0x08) + curve.fillAreaPattern = Origin::HorizontalMedium; + else if (fillIndex == 0x09) + curve.fillAreaPattern = Origin::VerticalMedium; + } + break; + case 1: + curve.fillAreaPattern = Origin::NoFill; + curve.fillAreaColor.regular = fillIndex; + curve.fillAreaColor.type = Origin::Color::Regular; + break; + case 2: + curve.fillAreaColor.type = Origin::Color::None; + curve.fillAreaPatternColor.type = Origin::Color::None; + curve.fillAreaPattern = Origin::NoFill; + break; + } + + if (curve.type == GraphCurve::Box){ + layer.percentile.symbolSize = 2; + layer.percentile.diamondBox = false; + layer.percentile.boxRange = 3; //BoxCurve::r25_75 + layer.percentile.whiskersRange = 2; //BoxCurve::r5_95 + layer.percentile.p1SymbolType = 7; + layer.percentile.p99SymbolType = 7; + layer.percentile.meanSymbolType = 1; + layer.percentile.maxSymbolType = 9; + layer.percentile.minSymbolType = 9; + layer.percentile.labels = false; + layer.percentile.symbolSize = 5; + layer.percentile.symbolColor = curve.lineColor; + layer.percentile.symbolFillColor.type = Origin::Color::None; + } + } else { + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + curve.fillArea = (h==2); + file >> curve.fillAreaColor.regular; + curve.fillAreaPattern = Origin::NoFill; + } + + //text + if(!curve.type || curve.type == GraphCurve::TextPlot){ + file.seekg(LAYER + 0xf, ios_base::beg); + file >> curve.text.color.regular; + curve.text.color.type = Origin::Color::Regular; + + file.seekg(LAYER + 0x13, ios_base::beg); + file >> curve.text.rotation; + curve.text.rotation /= 10; + + file >> curve.text.fontSize; + if (curve.text.fontSize < 250) + curve.type = GraphCurve::TextPlot; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> h; + 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; + } + + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + char offset; + file.seekg(LAYER + 0x37, ios_base::beg); + file >> offset; + curve.text.xOffset = offset * 5; + file >> offset; + curve.text.yOffset = offset * 5; + } + + if (curve.type == GraphCurve::Vector){ + curve.vector.multiplier = 1.0; + curve.vector.position = VectorProperties::Tail; + curve.vector.arrowLenght = 25; + curve.vector.arrowAngle = 40; + curve.vector.arrowClosed = true; + curve.vector.width = curve.lineWidth; + + file.seekg(LAYER + 0x18, ios_base::beg); + file >> h; + 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; + + file >> h; + if (h >= 0x64 && h < 0x1F4){ + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.magnitudeColumnName = column.second; + } else + curve.vector.constMagnitude = (int)curve.symbolSize; + } + + //pie + if (curve.type == GraphCurve::Pie){ + file.seekg(LAYER + 0x14, ios_base::beg); + file >> h; + + curve.pie.formatPercentages = (h & 0x08); + curve.pie.formatValues = !curve.pie.formatPercentages; + curve.pie.positionAssociate = (h & 0x80); + curve.pie.formatCategories = (h & 0x20); + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> h; + curve.pie.radius = 100 - h; + + file >> h; + curve.pie.distance = h; + curve.pie.formatAutomatic = true; + curve.pie.viewAngle = 90; + curve.pie.thickness = 33; + curve.pie.rotation = 0; + curve.pie.horizontalOffset = 0; + + /*file.seekg(LAYER + 0x9E, ios_base::beg); + file >> curve.pie.displacement; + file.seekg(LAYER + 0xA6, ios_base::beg); + file >> curve.pie.displacedSectionCount;*/ + } + + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour){ + if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) + layer.isXYY3D = false; + + if (curve.type == GraphCurve::Mesh3D) + curve.surface.colorMap = colorMap; + else + curve.colorMap = colorMap; + + /*if (curve.type == GraphCurve::Contour){ + file.seekg(102, ios_base::cur); + file >> curve.text.fontSize; + + file.seekg(7, ios_base::cur); + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + file.seekg(2, ios_base::cur); + file >> curve.text.color; + }*/ + } + + //surface + if (layer.isXYY3D || curve.type == GraphCurve::Mesh3D){ + file.seekg(LAYER + 0x15, ios_base::beg); + file >> w; + curve.surface.gridLineWidth = (double)w/500.0; + + file.seekg(8, ios_base::cur); + file >> curve.surface.gridColor; + + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.surface.type; + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + 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); + file >> curve.surface.frontColor; + + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + curve.surface.backColorEnabled = (h & 0x08); + file.seekg(LAYER + 0x15A, ios_base::beg); + file >> curve.surface.backColor; + file >> curve.surface.xSideWallColor; + file >> curve.surface.ySideWallColor; + + curve.surface.surface.fill = (h & 0x10); + curve.surface.surface.contour = (h & 0x40); + file.seekg(LAYER + 0x94, ios_base::beg); + file >> w; + curve.surface.surface.lineWidth = (double)w/500.0; + file >> curve.surface.surface.lineColor; + + curve.surface.topContour.fill = (h & 0x02); + curve.surface.topContour.contour = (h & 0x04); + file.seekg(LAYER + 0xB4, ios_base::beg); + file >> w; + curve.surface.topContour.lineWidth = (double)w/500.0; + file >> curve.surface.topContour.lineColor; + + curve.surface.bottomContour.fill = (h & 0x80); + curve.surface.bottomContour.contour = (h & 0x01); + file.seekg(LAYER + 0xA4, ios_base::beg); + file >> w; + curve.surface.bottomContour.lineWidth = (double)w/500.0; + file >> curve.surface.bottomContour.lineColor; + } + + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.symbolType; + + curve.symbolFillColor = curve.lineColor; + curve.symbolColor = curve.lineColor; + curve.vector.color = curve.symbolColor; + + file >> curve.pointOffset; + + file.seekg(LAYER + 0x143, ios_base::beg); + file >> h; + curve.connectSymbols = (h&0x8); + + LAYER += size + 0x1; + + unsigned int newSize; + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + LAYER += newSize + (newSize > 0 ? 0x1 : 0) + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + if(newSize != size) + break; + } + } + + LAYER += 0x5; + //read axis breaks + while(!file.eof()){ + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size == 0x2D){ + LAYER += 0x5; + file.seekg(LAYER + 2, ios_base::beg); + file >> h; + + if(h == 2) { + layer.xAxisBreak.minorTicksBefore = layer.xAxis.minorTicks; + layer.xAxisBreak.scaleIncrementBefore = layer.xAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.xAxisBreak); + } else if(h == 4){ + layer.yAxisBreak.minorTicksBefore = layer.yAxis.minorTicks; + layer.yAxisBreak.scaleIncrementBefore = layer.yAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.yAxisBreak); + } + LAYER += 0x2D + 0x1; + } else + break; + } + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + size = readGraphAxisInfo(layer.xAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.yAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.zAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0) + break; + } + + file.seekg(LAYER + 0x5, ios_base::beg); + + if (error) + return false; + return true; +} + +void Origin500Parser::readColorMap(ColorMap& colorMap) +{ + Color lowColor;//color bellow + lowColor.type = Origin::Color::Custom; + file >> lowColor.custom[0]; + file >> lowColor.custom[1]; + file >> lowColor.custom[2]; + + unsigned char h; + file >> h; + + Color highColor;//color above + highColor.type = Origin::Color::Custom; + file >> highColor.custom[0]; + file >> highColor.custom[1]; + file >> highColor.custom[2]; + file >> h; + + unsigned short colorMapSize; + file >> colorMapSize; + + file.seekg(2, ios_base::cur); + + for(unsigned int i = 0; i < 4; ++i){//low, high, middle and missing data colors + Color color; + color.type = Origin::Color::Custom; + file >> color.custom[0]; + file >> color.custom[1]; + file >> color.custom[2]; + file >> h; + } + + double zmin; + file >> zmin; + + double zmax; + file >> zmax; + + file.seekg(0x40, ios_base::cur); + + short val; + for(unsigned int i = 0; i < 2; ++i){ + Color color; + color.type = Origin::Color::Custom; + file >> color.custom[0]; + file >> color.custom[1]; + file >> color.custom[2]; + file >> h; + file >> val; + file.seekg(4, ios_base::cur); + } + + ColorMapLevel level; + level.fillColor = lowColor; + colorMap.levels.push_back(make_pair(zmin, level)); + + for(unsigned short i = 0; i < colorMapSize + 1; ++i){ + Color color; + color.type = Origin::Color::Custom; + file >> color.custom[0]; + file >> color.custom[1]; + file >> color.custom[2]; + file >> h; + file >> val; + file.seekg(4, ios_base::cur); + + level.fillColor = color; + colorMap.levels.push_back(make_pair(val, level)); + } + + level.fillColor = highColor; + colorMap.levels.push_back(make_pair(zmax, level)); +} diff --git a/3rdparty/liborigin2/Origin500Parser.h b/3rdparty/liborigin2/Origin500Parser.h new file mode 100644 index 000000000..ea191c014 --- /dev/null +++ b/3rdparty/liborigin2/Origin500Parser.h @@ -0,0 +1,46 @@ +/*************************************************************************** + File : Origin500Parser.h + -------------------------------------------------------------------- + Copyright : (C) 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 5.0 file parser 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_500_PARSER_H +#define ORIGIN_500_PARSER_H + +#include "Origin610Parser.h" + +class Origin500Parser : public Origin610Parser +{ +public: + Origin500Parser(const string& fileName); + bool parse(); + +protected: + void readNotes(); + bool readGraphInfo(); + void readColorMap(ColorMap& colorMap); +}; + +#endif // ORIGIN_500_PARSER_H diff --git a/3rdparty/liborigin2/Origin610Parser.cpp b/3rdparty/liborigin2/Origin610Parser.cpp new file mode 100644 index 000000000..357fbfe2a --- /dev/null +++ b/3rdparty/liborigin2/Origin610Parser.cpp @@ -0,0 +1,1592 @@ +/*************************************************************************** + File : Origin610Parser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2010 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 6.1 file parser class (uses code from file + Origin750Parser.cpp written by Alex Kargovsky) + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "Origin610Parser.h" + +Origin610Parser::Origin610Parser(const string& fileName) +: Origin800Parser(fileName) +{ +} + +bool Origin610Parser::parse() +{ + unsigned int dataIndex = 0; + +#ifndef NO_LOG_FILE + // append progress in log file + logfile = fopen("opjfile.log", "a"); +#endif + + /////////////////// find column /////////////////////////////////////////////////////////// + skipLine(); + + unsigned int size; + file >> size; + + file.seekg(1 + size + 1 + 5, ios_base::cur); + file >> size; + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, " [column found = %d/0x%X @ 0x%X]\n", size, size, (unsigned int) file.tellg()); + + unsigned int colpos = file.tellg(); + unsigned int current_col = 1, nr = 0, nbytes = 0; + + bool binData = false; + vector binSpreadSheets, statGraphNames; + while(size > 0 && size <= 0x8C){// should be 0x72, 0x73 or 0x83 ? + //////////////////////////////// COLUMN HEADER ///////////////////////////////////////////// + + short data_type; + char data_type_u; + unsigned int oldpos = file.tellg(); + + file.seekg(oldpos + 0x16, ios_base::beg); + file >> data_type; + + file.seekg(oldpos + 0x3F, ios_base::beg); + file >> data_type_u; + + char valuesize; + file.seekg(oldpos + 0x3D, ios_base::beg); + file >> valuesize; + + LOG_PRINT(logfile, " [valuesize = %d @ 0x%X]\n", (int)valuesize, ((unsigned int) file.tellg()-1)); + if(valuesize <= 0) + { + LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize); + valuesize = 10; + } + + file.seekg(oldpos + 0x58, ios_base::beg); + LOG_PRINT(logfile, " [Spreadsheet @ 0x%X]\n", (unsigned int) file.tellg()); + + string name(25, 0); + file >> name; + + string::size_type pos = name.find_last_of("_"); + string columnname; + if(pos != string::npos){ + columnname = name.substr(pos + 1); + name.resize(pos); + } + + if (name.substr(0, 4) == "SBin"){ + binData = true; + binSpreadSheets.push_back(name.substr(1)); + LOG_PRINT(logfile, " FOLLOWS BIN DATA TABLE: %s\n", name.substr(1).c_str()); + } + + LOG_PRINT(logfile, " NAME: %s\n", name.c_str()); + + unsigned int spread = 0; + if(columnname.empty()){ + LOG_PRINT(logfile, "NO COLUMN NAME FOUND! Must be a Matrix or Function."); + ////////////////////////////// READ matrices or functions //////////////////////////////////// + + LOG_PRINT(logfile, " [position @ 0x%X]\n", (unsigned int) file.tellg()); + // TODO + short signature; + file >> signature; + LOG_PRINT(logfile, " SIGNATURE : %02X \n", signature); + + + file.seekg(oldpos + size + 1, ios_base::beg); + file >> size; + file.seekg(1, ios_base::cur); + size /= valuesize; + LOG_PRINT(logfile, " SIZE = %d\n", size); + + if (signature == 0xAC8 && size != 1) + signature = 0xA00;//unknown data to be skipped + + switch(signature) + { + case 0x50CA: + case 0x70CA: + case 0x50F2: + case 0x50E2: + case 0x50E7: + case 0x50DB: + case 0x50DC: + case 0xAE2: + case 0xAF2: + case 0xACA: + if (size){ + //matrices.push_back(Matrix(name, dataIndex)); + matrices.push_back(Matrix(name)); + matrices.back().sheets.push_back(MatrixSheet(name, dataIndex)); + } + ++dataIndex; + readMatrixValues(data_type, data_type_u, valuesize, size); + break; + + case 0x10C8: + case 0xAC8: + functions.push_back(Function(name, dataIndex)); + ++dataIndex; + readFunction(colpos, valuesize, &oldpos); + break; + + default: + LOG_PRINT(logfile, " UNKNOWN SIGNATURE: %.2X SKIP DATA\n", signature); + file.seekg(valuesize*size, ios_base::cur); + ++dataIndex; + + if(valuesize != 8 && valuesize <= 16) + file.seekg(2, ios_base::cur); + } + } + else + { // worksheet + if (speadSheets.size() == 0 || findSpreadByName(name) == -1){ + LOG_PRINT(logfile, "NEW SPREADSHEET\n"); + current_col = 1; + speadSheets.push_back(SpreadSheet(name)); + if (binData){ + statGraphNames.push_back(name); + binData = false; + } + spread = speadSheets.size() - 1; + speadSheets.back().maxRows = 0; + } else { + spread = findSpreadByName(name); + current_col = speadSheets[spread].columns.size(); + + if(!current_col) + current_col = 1; + ++current_col; + } + speadSheets[spread].columns.push_back(SpreadColumn(columnname, dataIndex)); + string::size_type sheetpos = speadSheets[spread].columns.back().name.find_last_of("@"); + if(sheetpos != string::npos){ + unsigned int sheet = atoi(columnname.substr(sheetpos + 1).c_str()); + if( sheet > 1){ + speadSheets[spread].columns.back().name = columnname; + speadSheets[spread].columns.back().sheet = sheet - 1; + + if (speadSheets[spread].sheets < sheet) + speadSheets[spread].sheets = sheet; + } + } + LOG_PRINT(logfile, "SPREADSHEET = %s SHEET = %d COLUMN NAME = %s (%d) (@0x%X)\n", name.c_str(), speadSheets[spread].columns.back().sheet, columnname.c_str(), current_col, (unsigned int)file.tellg()); + + ++dataIndex; + + ////////////////////////////// SIZE of column ///////////////////////////////////////////// + file.seekg(oldpos + size + 1, ios_base::beg); + + file >> nbytes; + if (fmod(nbytes, (double)valuesize) > 0) + LOG_PRINT(logfile, "WARNING: data section could not be read correct"); + + nr = nbytes / valuesize; + LOG_PRINT(logfile, " [number of rows = %d (%d Bytes) @ 0x%X]\n", nr, nbytes, (unsigned int)file.tellg()); + + speadSheets[spread].maxRows < nr ? speadSheets[spread].maxRows = nr : 0; + readColumnValues(spread, current_col - 1, data_type, valuesize, nr); + } + + if (nbytes > 0 || (columnname.empty() && size)) + file.seekg(1, ios_base::cur); + + file >> size; + file.seekg(1 + size + (size > 0 ? 1 : 0), ios_base::cur); + + file >> size; + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, "\n [column found = %d/0x%X (@ 0x%X)]\n", size, size, ((unsigned int) file.tellg()-5)); + colpos = file.tellg(); + } + //////////////////////////////////////////////////////////////////////////// + ////////////////////// HEADER SECTION ////////////////////////////////////// + + unsigned int POS = (unsigned int)file.tellg()-11; + LOG_PRINT(logfile, "\nHEADER SECTION"); + LOG_PRINT(logfile, " [position @ 0x%X]\n", POS); + + if (binSpreadSheets.size() && statGraphNames.size()){ + for (unsigned int i = 0; i < speadSheets.size(); i++){ + for (unsigned int j = 0; j < binSpreadSheets.size() && j < statGraphNames.size(); j++){ + if (speadSheets[i].name == statGraphNames[j]) + speadSheets[i].name = binSpreadSheets[j]; + } + } + } + + POS += 0xB; + file.seekg(POS, ios_base::beg); + while(!file.eof()){ + POS = file.tellg(); + + file >> size; + if(size == 0) + break; + + file.seekg(POS + 0x7, ios_base::beg); + string name(25, 0); + file >> name; + + file.seekg(POS, ios_base::beg); + + if(findSpreadByName(name) != -1) + readSpreadInfo(); + else if(findMatrixByName(name) != -1) + readMatrixInfo(); + else if(findExcelByName(name) != -1) + readExcelInfo(); + else if (!readGraphInfo()){ + LOG_PRINT(logfile, " %s is NOT A GRAPH!\n", name.c_str()); + graphs.pop_back(); + } + POS = file.tellg(); + } + + file.seekg(1, ios_base::cur); + readParameters(); + + file.seekg(1 + 5, ios_base::cur); + readNotes(); + // If file has no Note windows, last function will read to EOF, skipping the info for ResultsLog and ProjectTree. + // As we know there is always a ResultsLog window after the Note windows, we better rewind to the start of Notes. + file.seekg(POS, ios_base::beg); + readResultsLog(); + + file.seekg(1 + 4*5 + 0x10 + 1, ios_base::cur); + try { + readProjectTree(); + } catch(...) {} + + LOG_PRINT(logfile, "Done parsing\n") +#ifndef NO_LOG_FILE + fclose(logfile); +#endif + + return true; +} + +void Origin610Parser::readNotes() +{ + if (file.eof()) + return; + + unsigned int pos = findStringPos("@"); + file.seekg(pos, ios_base::beg); + + unsigned int sectionSize; + file >> sectionSize; + + while(!file.eof()){ + file.seekg(1, ios_base::cur); + + Rect rect; + unsigned int coord; + file >> coord; + rect.left = coord; + file >> coord; + rect.top = coord; + file >> coord; + rect.right = coord; + file >> coord; + rect.bottom = coord; + + if (!rect.bottom || !rect.right) + break; + + unsigned char state; + file.seekg(0x8, ios_base::cur); + file >> state; + + double creationDate, modificationDate; + file.seekg(0x7, ios_base::cur); + file >> creationDate; + file >> modificationDate; + + file.seekg(0x8, ios_base::cur); + unsigned char c; + file >> c; + + unsigned int labellen; + file.seekg(0x3, ios_base::cur); + file >> labellen; + + skipLine(); + + unsigned int size; + file >> size; + file.seekg(1, ios_base::cur); + + string name(size, 0); + file >> name; + + notes.push_back(Note(name)); + notes.back().objectID = objectIndex; + ++objectIndex; + + notes.back().frameRect = rect; + if (creationDate >= 1e10) + return; + notes.back().creationDate = doubleToPosixTime(creationDate); + if (modificationDate >= 1e10) + return; + 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 == 0x04) + notes.back().state = Window::Minimized; + + notes.back().hidden = (state & 0x40); + + file.seekg(1, ios_base::cur); + file >> size; + + file.seekg(1, ios_base::cur); + + if(labellen > 1){ + file >> notes.back().label.assign(labellen - 1, 0); + file.seekg(1, ios_base::cur); + } + + file >> notes.back().text.assign(size - labellen, 0); + + LOG_PRINT(logfile, "NOTE %d NAME: %s\n", (int)notes.size(), notes.back().name.c_str()); + LOG_PRINT(logfile, "NOTE %d LABEL: %s\n", (int)notes.size(), notes.back().label.c_str()); + LOG_PRINT(logfile, "NOTE %d TEXT: %s\n", (int)notes.size(), notes.back().text.c_str()); + + file.seekg(1, ios_base::cur); + + file >> size; + if(size != sectionSize) + break; + } +} + +void Origin610Parser::readResultsLog() +{ + int pos = findStringPos("ResultsLog"); + if (pos < 0) + return; + + file.seekg(pos + 12, ios_base::beg); + unsigned int size; + file >> size; + + file.seekg(1, ios_base::cur); + resultsLog.resize(size); + file >> resultsLog; + LOG_PRINT(logfile, "Results Log: %s\n", resultsLog.c_str()); +} + +void Origin610Parser::readMatrixInfo() +{ + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + + POS+=5; + + LOG_PRINT(logfile, " [Matrix SECTION (@ 0x%X)]\n", POS); + + string name(25, 0); + file.seekg(POS + 0x2, ios_base::beg); + file >> name; + LOG_PRINT(logfile, " MATRIX %s (@ 0x%X)]\n", name.c_str(), POS); + + int idx = findMatrixByName(name); + matrices[idx].name = name; + file.seekg(POS, ios_base::beg); + readWindowProperties(matrices[idx], size); + + unsigned int LAYER = POS; + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + // LAYER section + LAYER += 0x5; + + unsigned short width; + file.seekg(LAYER + 0x27, ios_base::beg); + file >> width; + if (width == 0) + width = 8; + + MatrixSheet sheet = matrices[idx].sheets.back(); + sheet.width = width; + LOG_PRINT(logfile, " Width: %d (@ 0x%X)\n", sheet.width, (LAYER + 0x27)); + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> sheet.columnCount; + LOG_PRINT(logfile, " Columns: %d (@ 0x%X)\n", sheet.columnCount, (LAYER + 0x2B)); + + file.seekg(LAYER + 0x52, ios_base::beg); + file >> sheet.rowCount; + LOG_PRINT(logfile, " Rows: %d (@ 0x%X)\n", sheet.rowCount, (LAYER + 0x52)); + + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + unsigned int sectionSize = size; + while(!file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + unsigned int sectionNamePos = LAYER + 0x46; + //string sec_name(30, 0); + string sec_name(LAYER + sectionSize - sectionNamePos + 1, 0); + file.seekg(sectionNamePos, ios_base::beg); + file >> sec_name; + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), sectionNamePos); + + //section_body_1_size + file >> size; + + //section_body_1 + LAYER = file.tellg(); + file.seekg(1, ios_base::cur); + + if (sec_name == "MV"){//check if it is a formula + file >> sheet.command.assign(size, 0); + LOG_PRINT(logfile, " FORMULA: %s\n", sheet.command.c_str()); + } else if (sec_name == "Y2"){ + string s(size, 0); + file >> s; + sheet.coordinates[0] = stringToDouble(s); + LOG_PRINT(logfile, " Y2: %g\n", sheet.coordinates[0]); + } else if (sec_name == "X2"){ + string s(size, 0); + file >> s; + sheet.coordinates[1] = stringToDouble(s); + LOG_PRINT(logfile, " X2: %g\n", sheet.coordinates[1]); + } else if (sec_name == "Y1"){ + string s(size, 0); + file >> s; + sheet.coordinates[2] = stringToDouble(s); + LOG_PRINT(logfile, " Y1: %g\n", sheet.coordinates[2]); + } else if (sec_name == "X1"){ + string s(size, 0); + file >> s; + sheet.coordinates[3] = stringToDouble(s); + LOG_PRINT(logfile, " X1: %g\n", sheet.coordinates[3]); + } + + //section_body_2_size + LAYER += size + 0x2; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0) + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size != sectionSize) + break; + } + file.seekg(1, ios_base::cur); + + LAYER = file.tellg(); + file >> size; + + unsigned char c1, c2; + file.seekg(LAYER + 0x23, ios_base::beg); + file >> c1; + file >> c2; + + 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; + } + + LAYER += size + 0x06; + file.seekg(LAYER, ios_base::beg); + + skipObjectInfo(); + + matrices[idx].sheets.back() = sheet; + LOG_PRINT(logfile, " Done with matrix %s (@ 0x%X)\n", name.c_str(), (unsigned int)file.tellg()); +} + +bool Origin610Parser::readGraphInfo() +{ + bool error = false; + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + + POS += 5; + + string name(25, 0); + file.seekg(POS + 0x02, ios_base::beg); + file >> name; + LOG_PRINT(logfile, " GRAPH name: %s @ 0x%X\n", name.c_str(), (unsigned int)file.tellg()); + + graphs.push_back(Graph(name)); + file.seekg(POS, ios_base::beg); + readWindowProperties(graphs.back(), size); + + file.seekg(POS + 0x23, ios_base::beg); + file >> graphs.back().width; + file >> graphs.back().height; + + file.seekg(POS + 0x38, ios_base::beg); + unsigned char c; + file >> c; + graphs.back().connectMissingData = (c & 0x40); + + file.seekg(POS + 0x45, ios_base::beg); + string templateName(20, 0); + file >> templateName; + graphs.back().templateName = templateName; + LOG_PRINT(logfile, " TEMPLATE: %s pos: 0x%X\n", templateName.c_str(), (POS + 0x45)); + + unsigned int LAYER = POS; + LAYER += size + 0x1; + + while(!file.eof()){// multilayer loop + graphs.back().layers.push_back(GraphLayer()); + GraphLayer& layer(graphs.back().layers.back()); + + // LAYER section + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x05; + + file.seekg(LAYER + 0x0F, ios_base::beg); + file >> layer.xAxis.min; + file >> layer.xAxis.max; + file >> layer.xAxis.step; + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> layer.xAxis.majorTicks; + + unsigned char g; + file >> g; file >> g; + layer.xAxis.zeroLine = (g & 0x80); + layer.xAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x37, ios_base::beg); + file >> layer.xAxis.minorTicks; + file >> layer.xAxis.scale; + + file.seekg(LAYER + 0x3A, ios_base::beg); + file >> layer.yAxis.min; + file >> layer.yAxis.max; + file >> layer.yAxis.step; + + file.seekg(LAYER + 0x56, ios_base::beg); + file >> layer.yAxis.majorTicks; + + file >> g; file >> g; + layer.yAxis.zeroLine = (g & 0x80); + layer.yAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> layer.yAxis.minorTicks; + file >> layer.yAxis.scale; + + file.seekg(LAYER + 0x68, ios_base::beg); + file >> g; + layer.gridOnTop = (g & 0x04); + layer.exchangedAxes = (g & 0x40); + + file.seekg(LAYER + 0x71, ios_base::beg); + file.read(reinterpret_cast(&layer.clientRect), sizeof(Rect)); + + unsigned char border; + file.seekg(LAYER + 0x89, ios_base::beg); + file >> border; + layer.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + + unsigned char col; + file.seekg(LAYER + 0xA7, ios_base::beg); + file >> col; + layer.backgroundColor.type = (col & 0x01) ? Origin::Color::None : Origin::Color::Regular; + file >> col; + layer.backgroundColor.regular = col; + + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + + unsigned int sectionSize; + file >> size; + sectionSize = size; + + //now structure is next : section_header_size=0x6F(4 bytes) + '\n' + section_header(0x6F bytes) + section_body_1_size(4 bytes) + '\n' + section_body_1 + section_body_2_size(maybe=0)(4 bytes) + '\n' + section_body_2 + '\n' + //possible sections: axes, legend, __BC02, _202, _231, _232, etc + //section name starts with 0x46 position + while(size && !file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + + unsigned int sectionNamePos = LAYER + 0x46; + string sec_name(41, 0); + file.seekg(sectionNamePos, ios_base::beg); + file >> sec_name; + if (!sec_name.empty()) + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), sectionNamePos); + + Rect r; + file.seekg(LAYER + 0x03, ios_base::beg); + file.read(reinterpret_cast(&r), sizeof(Rect)); + + unsigned char attach; + file.seekg(LAYER + 0x28, ios_base::beg); + file >> attach; + + unsigned char border; + file >> border; + + Color color; + file.seekg(LAYER + 0x33, ios_base::beg); + file >> color; + + LAYER += size + 0x01; + file.seekg(LAYER, ios_base::beg); + file >> size; + //LOG_PRINT(logfile, " osize = %d (@ 0x%X)\n", size, (unsigned int)file.tellg()); + + //section_body_1 + LAYER += 0x5; + unsigned int osize = size; + unsigned int SECTION_BODY1_POS = LAYER; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisPrefixSuffixInfo(sec_name, size, layer); + + unsigned char type; + file >> type; + + LineVertex begin, end; + if (size == 24 || size == 96){//Line/Arrow + if (attach == Origin::Scale){ + if (type == 2){ + file.seekg(LAYER + 0x20, ios_base::beg); + file >> begin.x; + file >> end.x; + file.seekg(LAYER + 0x40, ios_base::beg); + file >> begin.y; + file >> end.y; + } else if (type == 4){//curved arrow: start point, 2 middle points and end point + file.seekg(LAYER + 0x20, ios_base::beg); + file >> begin.x; + file >> end.x; + file >> end.x; + file >> end.x; + file >> begin.y; + file >> end.y; + file >> end.y; + file >> end.y; + } + } else { + unsigned short x1, x2, y1, y2; + if (type == 2){//straight line/arrow + file >> x1; + file >> x2; + file.seekg(4, ios_base::cur); + file >> y1; + file >> y2; + file.seekg(4, ios_base::cur); + } else if (type == 4){//curved line/arrow has 4 points + file >> x1; + file.seekg(4, ios_base::cur); + file >> x2; + file >> y1; + file.seekg(4, ios_base::cur); + file >> y2; + } + + double maxx = (x1 <= x2) ? x2 : x1; + if (!x1 && !x2) + maxx = 1.0; + double maxy = (y1 <= y2) ? y2 : y1; + if (!y1 && !y2) + maxy = 1.0; + + begin.x = r.left + (double)x1/maxx*r.width(); + begin.y = r.top + (double)y1/maxy*r.height(); + end.x = r.left + (double)x2/maxx*r.width(); + end.y = r.top + (double)y2/maxy*r.height(); + } + + file.seekg(LAYER + 0x11, ios_base::beg); + unsigned char arrows; + file >> arrows; + 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; + } + + file.seekg(3, ios_base::cur); + unsigned char sw; + file >> sw; + end.shapeLength = (double)sw; + begin.shapeLength = (double)sw; + file >> sw; + end.shapeWidth = (double)sw; + begin.shapeWidth = (double)sw; + } + + //text properties + short rotation; + file.seekg(LAYER + 0x02, ios_base::beg); + file >> rotation; + + unsigned char fontSize; + file >> fontSize; + + /* + unsigned char systemFont; + file.seekg(LAYER + 0x09, ios_base::beg); + file >> systemFont; + LOG_PRINT(logfile, " systemFont = %d (@ 0x%X)\n", systemFont, (unsigned int)file.tellg()); + */ + + unsigned char tab; + file.seekg(LAYER + 0x0A, ios_base::beg); + file >> tab; + + file.seekg(LAYER + 0x0E, ios_base::beg); + unsigned char familyIndex; + file >> familyIndex; + + //line properties + unsigned char lineStyle = 0; + double width = 0.0; + + file.seekg(LAYER + 0x12, ios_base::beg); + file >> lineStyle; + + unsigned short w1; + file >> w1; + width = (double)w1/500.0; + + Figure figure; + file.seekg(LAYER + 0x05, ios_base::beg); + file >> w1; + figure.width = (double)w1/500.0; + + file.seekg(LAYER + 0x08, ios_base::beg); + file >> figure.style; + + unsigned char fillIndex, fillType; + file.seekg(sectionNamePos + 42, ios_base::beg); + file >> fillIndex; + file.seekg(sectionNamePos + 44, ios_base::beg); + file >> fillType; + + switch(fillType){ + case 0: + figure.useBorderColor = (fillIndex >= 5); + if (fillIndex < 5){ + figure.fillAreaPattern = Origin::NoFill; + figure.fillAreaColor.type = Origin::Color::Regular; + if (fillIndex == 0) + figure.fillAreaColor.regular = 0; + else if (fillIndex == 1) + figure.fillAreaColor.regular = 18; + else if (fillIndex == 2) + figure.fillAreaColor.regular = 23; + else if (fillIndex == 3) + figure.fillAreaColor.regular = 17; + else + figure.fillAreaColor.regular = 19; + } else { + figure.fillAreaColor.type = Origin::Color::None; + if (fillIndex == 0x05) + figure.fillAreaPattern = Origin::BDiagMedium; + else if (fillIndex == 0x06) + figure.fillAreaPattern = Origin::DiagCrossMedium; + else if (fillIndex == 0x07) + figure.fillAreaPattern = Origin::FDiagMedium; + else if (fillIndex == 0x08) + figure.fillAreaPattern = Origin::HorizontalMedium; + else if (fillIndex == 0x09) + figure.fillAreaPattern = Origin::VerticalMedium; + } + break; + case 1: + figure.fillAreaPattern = Origin::NoFill; + figure.fillAreaColor.regular = fillIndex; + figure.fillAreaColor.type = Origin::Color::Regular; + break; + case 2: + figure.fillAreaColor.type = Origin::Color::None; + figure.fillAreaPatternColor.type = Origin::Color::None; + figure.useBorderColor = false; + figure.fillAreaPattern = Origin::NoFill; + break; + } + + //section_body_2_size + LAYER += size + 0x1; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + //check if it is an axis or a legend + + file.seekg(1, ios_base::cur); + if(sec_name == "XB") + { + string text(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Bottom; + layer.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(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Top; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Left; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Right; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Front; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Back; + layer.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") + { + file >> layer.zAxis.min; + file >> layer.zAxis.max; + file >> layer.zAxis.step; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> layer.zAxis.majorTicks; + + file.seekg(LAYER + 0x28, ios_base::beg); + file >> layer.zAxis.minorTicks; + file >> layer.zAxis.scale; + + file.seekg(LAYER + 0x5A, ios_base::beg); + file >> layer.xAngle; + file >> layer.yAngle; + file >> layer.zAngle; + + file.seekg(LAYER + 0x218, ios_base::beg); + file >> layer.xLength; + file >> layer.yLength; + file >> layer.zLength; + + layer.xLength /= 23.0; + layer.yLength /= 23.0; + layer.zLength /= 23.0; + + file.seekg(LAYER + 0x240, ios_base::beg); + file >> layer.orthographic3D; + } + else if(sec_name == "Legend") + { + string text(size, 0); + file >> text; + + layer.legend = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); + } + else if(sec_name == "__BCO2") // histogram + { + file.seekg(LAYER + 0x10, ios_base::beg); + file >> layer.histogramBin; + + file.seekg(LAYER + 0x20, ios_base::beg); + file >> layer.histogramEnd; + file >> layer.histogramBegin; + + unsigned int p = sectionNamePos + 81; + file.seekg(p, ios_base::beg); + + file >> layer.percentile.p1SymbolType; + file >> layer.percentile.p99SymbolType; + file >> layer.percentile.meanSymbolType; + file >> layer.percentile.maxSymbolType; + file >> layer.percentile.minSymbolType; + + file.seekg(p + 65, ios_base::beg); + file >> layer.percentile.labels; + + file.seekg(sectionNamePos + 94, ios_base::beg); + file >> layer.percentile.whiskersRange; + file >> layer.percentile.boxRange; + + file.seekg(sectionNamePos + 129, ios_base::beg); + file >> layer.percentile.whiskersCoeff; + file >> layer.percentile.boxCoeff; + + unsigned char h; + file >> h; + layer.percentile.diamondBox = (h == 0x82) ? true : false; + + p += 109; + file.seekg(p, ios_base::beg); + file >> layer.percentile.symbolSize; + layer.percentile.symbolSize = layer.percentile.symbolSize/2 + 1; + + p += 163; + file.seekg(p, ios_base::beg); + file >> layer.percentile.symbolColor; + file >> layer.percentile.symbolFillColor; + } + else if(sec_name == "ZCOLORS") + { + layer.isXYY3D = true; + } + else if(sec_name == "SPECTRUM1") + { + layer.isXYY3D = false; + layer.colorScale.visible = true; + + unsigned char h; + file.seekg(24, ios_base::cur); + file >> h; + layer.colorScale.reverseOrder = h; + file.seekg(7, ios_base::cur); + file >> layer.colorScale.colorBarThickness; + file >> layer.colorScale.labelGap; + file.seekg(56, ios_base::cur); + file >> layer.colorScale.labelsColor; + } + else if(sec_name == "&0") + { + layer.isWaterfall = true; + file.seekg(SECTION_BODY1_POS, ios_base::beg); + string text(osize, 0); + file >> text; + size_t commaPos = text.find_first_of(','); + layer.xOffset = atoi(text.substr(0, commaPos).c_str()); + layer.yOffset = atoi(text.substr(commaPos + 1).c_str()); + } + else if (osize == 22 || (size && !type)) + { + string text(size, 0); + file >> text; + + sec_name.resize(3); + if (sec_name == "PIE") + layer.pieTexts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + else + layer.texts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + } + else if(osize == 0xA) // rectangle & circle + { + switch(type){ + 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; + + layer.figures.push_back(figure); + } + else if (osize == 24 || osize == 96) // line + {//type == 2 ->straight line, type == 4 ->curved line + layer.lines.push_back(Line()); + Line& line(layer.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(osize == 0x28) // bitmap + { + if (type == 4){ + unsigned long filesize = size + 14; + layer.bitmaps.push_back(Bitmap()); + Bitmap& bitmap(layer.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; + file.read(reinterpret_cast(data), size); + } else if (type == 6){ + string gname(30, 0); + file.seekg(sectionNamePos + 81, ios_base::beg); + file >> gname; + layer.bitmaps.push_back(Bitmap(gname)); + Bitmap& bitmap(layer.bitmaps.back()); + bitmap.clientRect = r; + bitmap.attach = (Attach)attach; + bitmap.size = 0; + bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + } + } + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + //section_body_3_size + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_3 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + file.seekg(LAYER, ios_base::beg); + file >> size; + if (!size || size != sectionSize) + break; + } + + LAYER += 0x5; + unsigned char h; + short w; + + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size)//check layer is not empty + { + while(!file.eof()){ + LAYER += 0x5; + + layer.curves.push_back(GraphCurve()); + GraphCurve& curve(layer.curves.back()); + + file.seekg(LAYER + 0x26, ios_base::beg); + file >> h; + curve.hidden = (h == 33); + LOG_PRINT(logfile, " hidden curve: %d\n", curve.hidden); + + file.seekg(LAYER + 0x4C, ios_base::beg); + file >> curve.type; + if (!curve.type){ + LOG_PRINT(logfile, " Found unknown curve type (%d)! NOT A GRAPH!\n", (int)curve.type); + } else + LOG_PRINT(logfile, " graph %d layer %d curve %d type : %d\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), (int)curve.type); + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) + layer.isXYY3D = false; + + file.seekg(LAYER + 0x04, ios_base::beg); + file >> w; + pair column = findDataByIndex(w-1); + short nColY = w; + if(column.first.size() > 0){ + curve.dataName = column.first; + if(layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Z : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.zColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(),graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } + } + + file.seekg(LAYER + 0x23, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if(column.first.size() > 0){ + curve.xDataName = (curve.dataName != column.first) ? column.first : ""; + + if(layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } else if (layer.isXYY3D){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } + } + + file.seekg(LAYER + 0x4D, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if(column.first.size() > 0 && layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + if(curve.dataName != column.first) + LOG_PRINT(logfile, " graph %d X and Y from different tables\n", graphs.size()); + } + + if(layer.is3D() || layer.isXYY3D) + graphs.back().is3D = true; + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> curve.lineConnect; + file >> curve.lineStyle; + + file.seekg(1, ios_base::cur); + file >> curve.boxWidth; + + file >> w; + curve.lineWidth=(double)w/500.0; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> w; + curve.symbolSize=(double)w/500.0; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + curve.fillArea = (h==2); + + file.seekg(LAYER + 0x1E, ios_base::beg); + file >> curve.fillAreaType; + + //text + if(curve.type == GraphCurve::TextPlot){ + file.seekg(LAYER + 0x13, ios_base::beg); + file >> curve.text.rotation; + + curve.text.rotation /= 10; + file >> curve.text.fontSize; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> h; + 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; + } + + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + char offset; + file.seekg(LAYER + 0x37, ios_base::beg); + file >> offset; + curve.text.xOffset = offset * 5; + file >> offset; + curve.text.yOffset = offset * 5; + } + + //vector + if(curve.type == GraphCurve::FlowVector || curve.type == GraphCurve::Vector){ + file.seekg(LAYER + 0x56, ios_base::beg); + file >> curve.vector.multiplier; + + file.seekg(LAYER + 0x5E, ios_base::beg); + file >> h; + + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.endXColumnName = column.second; + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> h; + + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.endYColumnName = column.second; + + file.seekg(LAYER + 0x18, ios_base::beg); + file >> h; + + 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; + + file >> h; + + if(h >= 0x64 && h < 0x1F4){ + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.magnitudeColumnName = column.second; + } else + curve.vector.constMagnitude = (int)curve.symbolSize; + + file.seekg(LAYER + 0x66, ios_base::beg); + file >> curve.vector.arrowLenght; + file >> curve.vector.arrowAngle; + + file >> h; + curve.vector.arrowClosed = !(h & 0x1); + + file >> w; + curve.vector.width=(double)w/500.0; + + file.seekg(LAYER + 0x142, ios_base::beg); + file >> h; + 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){ + file.seekg(LAYER + 0x92, ios_base::beg); + file >> h; + + 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); + + file >> curve.pie.formatAutomatic; + file >> curve.pie.distance; + file >> curve.pie.viewAngle; + + file.seekg(LAYER + 0x98, ios_base::beg); + file >> curve.pie.thickness; + + file.seekg(LAYER + 0x9A, ios_base::beg); + file >> curve.pie.rotation; + + file.seekg(LAYER + 0x9E, ios_base::beg); + file >> curve.pie.displacement; + + file.seekg(LAYER + 0xA0, ios_base::beg); + file >> curve.pie.radius; + file >> curve.pie.horizontalOffset; + + file.seekg(LAYER + 0xA6, ios_base::beg); + file >> curve.pie.displacedSectionCount; + } + //surface + if (layer.isXYY3D || curve.type == GraphCurve::Mesh3D){ + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.surface.type; + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + 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); + file >> curve.surface.frontColor; + + file.seekg(LAYER + 0x14C, ios_base::beg); + file >> w; + curve.surface.gridLineWidth = (double)w/500.0; + file >> curve.surface.gridColor; + + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + curve.surface.backColorEnabled = (h & 0x08); + file.seekg(LAYER + 0x15A, ios_base::beg); + file >> curve.surface.backColor; + file >> curve.surface.xSideWallColor; + file >> curve.surface.ySideWallColor; + + curve.surface.surface.fill = (h & 0x10); + curve.surface.surface.contour = (h & 0x40); + file.seekg(LAYER + 0x94, ios_base::beg); + file >> w; + curve.surface.surface.lineWidth = (double)w/500.0; + file >> curve.surface.surface.lineColor; + + curve.surface.topContour.fill = (h & 0x02); + curve.surface.topContour.contour = (h & 0x04); + file.seekg(LAYER + 0xB4, ios_base::beg); + file >> w; + curve.surface.topContour.lineWidth = (double)w/500.0; + file >> curve.surface.topContour.lineColor; + + curve.surface.bottomContour.fill = (h & 0x80); + curve.surface.bottomContour.contour = (h & 0x01); + file.seekg(LAYER + 0xA4, ios_base::beg); + file >> w; + curve.surface.bottomContour.lineWidth = (double)w/500.0; + file >> curve.surface.bottomContour.lineColor; + } + + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour){ + if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) + layer.isXYY3D = false; + + ColorMap& colorMap = (curve.type == GraphCurve::Mesh3D ? curve.surface.colorMap : curve.colorMap); + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + colorMap.fillEnabled = (h & 0x82); + + if (curve.type == GraphCurve::Contour){ + file.seekg(102, ios_base::cur); + file >> curve.text.fontSize; + + file.seekg(7, ios_base::cur); + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + file.seekg(2, ios_base::cur); + file >> curve.text.color; + } + file.seekg(LAYER + 0x254, ios_base::beg); + readColorMap(colorMap); + } + + file.seekg(LAYER + 0xC2, ios_base::beg); + file >> curve.fillAreaColor; + + file >> w; + curve.fillAreaPatternWidth=(double)w/500.0; + + file.seekg(LAYER + 0xCA, ios_base::beg); + file >> curve.fillAreaPatternColor; + + file >> curve.fillAreaPattern; + file >> curve.fillAreaPatternBorderStyle; + file >> w; + curve.fillAreaPatternBorderWidth=(double)w/500.0; + file >> curve.fillAreaPatternBorderColor; + + file.seekg(LAYER + 0x16A, ios_base::beg); + file >> curve.lineColor; + if (curve.type != GraphCurve::Contour) + curve.text.color = curve.lineColor; + + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.symbolType; + + file.seekg(LAYER + 0x12E, ios_base::beg); + file >> curve.symbolFillColor; + file >> curve.symbolColor; + curve.vector.color = curve.symbolColor; + + file >> h; + curve.symbolThickness = (h == 255 ? 1 : h); + file >> curve.pointOffset; + + file.seekg(LAYER + 0x143, ios_base::beg); + file >> h; + curve.connectSymbols = (h&0x8); + + LAYER += size + 0x1; + + unsigned int newSize; + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + LAYER += newSize + (newSize > 0 ? 0x1 : 0) + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + if(newSize != size) + break; + } + } + + LAYER += 0x5; + //read axis breaks + while(!file.eof()){ + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size == 0x2D){ + LAYER += 0x5; + file.seekg(LAYER + 2, ios_base::beg); + file >> h; + + if(h == 2) { + layer.xAxisBreak.minorTicksBefore = layer.xAxis.minorTicks; + layer.xAxisBreak.scaleIncrementBefore = layer.xAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.xAxisBreak); + } else if(h == 4){ + layer.yAxisBreak.minorTicksBefore = layer.yAxis.minorTicks; + layer.yAxisBreak.scaleIncrementBefore = layer.yAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.yAxisBreak); + } + LAYER += 0x2D + 0x1; + } else + break; + } + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + size = readGraphAxisInfo(layer.xAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.yAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.zAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0) + break; + } + + file.seekg(LAYER + 0x5, ios_base::beg); + + if (error) + return false; + return true; +} + +OriginParser* createOrigin610Parser(const string& fileName) +{ + return new Origin610Parser(fileName); +} + +int Origin610Parser::findObjectInfoSectionByName(unsigned int start, const string& name) +{ + file.seekg(start, ios_base::beg); + char c = 0; + unsigned int pos = start; + while(pos != ios_base::end){ + file >> c; + if (c == name[0]){ + pos = file.tellg(); + file.seekg(pos - 0x2, ios_base::beg); + file >> c; + + string s = string(name.size(), 0); + file >> s; + + char end; + file >> end; + + if (!c && !end && name == s){ + pos -= 0x8; + file.seekg(pos, ios_base::beg); + //LOG_PRINT(logfile, " Object info section starts at: 0x%X\n", pos); + return pos; + } + } + } + return 0; +} diff --git a/3rdparty/liborigin2/Origin610Parser.h b/3rdparty/liborigin2/Origin610Parser.h new file mode 100644 index 000000000..8b4909415 --- /dev/null +++ b/3rdparty/liborigin2/Origin610Parser.h @@ -0,0 +1,49 @@ +/*************************************************************************** + File : Origin610Parser.h + -------------------------------------------------------------------- + Copyright : (C) 2010 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 6.1 file parser 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_610_PARSER_H +#define ORIGIN_610_PARSER_H + +#include "Origin800Parser.h" + +class Origin610Parser : public Origin800Parser +{ +public: + Origin610Parser(const string& fileName); + bool parse(); + +protected: + void readMatrixInfo(); + bool readGraphInfo(); + void readResultsLog(); + void readNotes(); + + int findObjectInfoSectionByName(unsigned int start, const string& name); +}; + +#endif // ORIGIN_610_PARSER_H diff --git a/3rdparty/liborigin2/Origin700Parser.cpp b/3rdparty/liborigin2/Origin700Parser.cpp new file mode 100644 index 000000000..f854bbacb --- /dev/null +++ b/3rdparty/liborigin2/Origin700Parser.cpp @@ -0,0 +1,1249 @@ +/*************************************************************************** + File : Origin700Parser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2010 - 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 7.0 file parser class (uses code from file + Origin750Parser.cpp written by Alex Kargovsky) + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "Origin700Parser.h" + +Origin700Parser::Origin700Parser(const string& fileName) +: Origin610Parser(fileName) +{} + +bool Origin700Parser::parse() +{ + unsigned int dataIndex = 0; + +#ifndef NO_LOG_FILE + // append progress in log file + logfile = fopen("opjfile.log", "a"); +#endif + + /////////////////// find column /////////////////////////////////////////////////////////// + skipLine(); + + unsigned int size; + file >> size; + file.seekg(1 + size + 1 + 5, ios_base::cur); + + file >> size; + + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, " [column found = %d/0x%X @ 0x%X]\n", size, size, (unsigned int) file.tellg()); + + unsigned int colpos = file.tellg(); + unsigned int current_col = 1, nr = 0, nbytes = 0; + + while(size > 0 && size < 0x84) { // should be 0x72, 0x73 or 0x83 + //////////////////////////////// COLUMN HEADER ///////////////////////////////////////////// + short data_type; + char data_type_u; + unsigned int oldpos = file.tellg(); + + file.seekg(oldpos + 0x16, ios_base::beg); + file >> data_type; + + file.seekg(oldpos + 0x3F, ios_base::beg); + file >> data_type_u; + + char valuesize; + file.seekg(oldpos + 0x3D, ios_base::beg); + file >> valuesize; + + LOG_PRINT(logfile, " [valuesize = %d @ 0x%X]\n", (int)valuesize, ((unsigned int) file.tellg()-1)); + if(valuesize <= 0) + { + LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize); + valuesize = 10; + } + + file.seekg(oldpos + 0x58, ios_base::beg); + LOG_PRINT(logfile, " [Spreadsheet @ 0x%X]\n", (unsigned int) file.tellg()); + + string name(25, 0); + file >> name; + + string::size_type pos = name.find_last_of("_"); + string columnname; + if(pos != string::npos) + { + columnname = name.substr(pos + 1); + name.resize(pos); + } + LOG_PRINT(logfile, " NAME: %s\n", name.c_str()); + + unsigned int spread = 0; + if(columnname.empty()) + { + LOG_PRINT(logfile, "NO COLUMN NAME FOUND! Must be a Matrix or Function."); + ////////////////////////////// READ matrices or functions //////////////////////////////////// + + LOG_PRINT(logfile, " [position @ 0x%X]\n", (unsigned int) file.tellg()); + // TODO + short signature; + file >> signature; + LOG_PRINT(logfile, " SIGNATURE : %02X \n", signature); + + + file.seekg(oldpos + size + 1, ios_base::beg); + file >> size; + file.seekg(1, ios_base::cur); + size /= valuesize; + LOG_PRINT(logfile, " SIZE = %d\n", size); + + if (signature == 0x50C8 && size != 1) + signature = 0x50CA;//is a matrix + + switch(signature) + { + case 0x50CA: + case 0x70CA: + case 0x50F2: + case 0x50E2: + case 0x50E7: + case 0x50DB: + case 0x50DC: + matrices.push_back(Matrix(name)); + matrices.back().sheets.push_back(MatrixSheet(name, dataIndex)); + ++dataIndex; + readMatrixValues(data_type, data_type_u, valuesize, size); + break; + case 0x10C8: + case 0x50C8: + functions.push_back(Function(name, dataIndex)); + ++dataIndex; + readFunction(colpos, valuesize, &oldpos); + break; + default: + LOG_PRINT(logfile, "UNKNOWN SIGNATURE: %.2X SKIP DATA\n", signature); + file.seekg(valuesize*size, ios_base::cur); + ++dataIndex; + + if(valuesize != 8 && valuesize <= 16) + { + file.seekg(2, ios_base::cur); + } + } + } + else + { // worksheet + if(speadSheets.size() == 0 || findSpreadByName(name) == -1) + { + LOG_PRINT(logfile, "NEW SPREADSHEET\n"); + current_col = 1; + speadSheets.push_back(SpreadSheet(name)); + spread = speadSheets.size() - 1; + speadSheets.back().maxRows = 0; + } + else + { + spread = findSpreadByName(name); + current_col = speadSheets[spread].columns.size(); + if(!current_col) + current_col = 1; + ++current_col; + } + LOG_PRINT(logfile, "SPREADSHEET = %s COLUMN NAME = %s (%d) (@0x%X)\n", name.c_str(), columnname.c_str(), current_col, (unsigned int)file.tellg()); + speadSheets[spread].columns.push_back(SpreadColumn(columnname, dataIndex)); + string::size_type sheetpos = speadSheets[spread].columns.back().name.find_last_of("@"); + if(sheetpos != string::npos){ + unsigned int sheet = atoi(columnname.substr(sheetpos + 1).c_str()); + if( sheet > 1){ + speadSheets[spread].columns.back().name = columnname; + speadSheets[spread].columns.back().sheet = sheet - 1; + + if (speadSheets[spread].sheets < sheet) + speadSheets[spread].sheets = sheet; + } + } + ++dataIndex; + + ////////////////////////////// SIZE of column ///////////////////////////////////////////// + file.seekg(oldpos + size + 1, ios_base::beg); + + file >> nbytes; + if (fmod(nbytes, (double)valuesize) > 0) + LOG_PRINT(logfile, "WARNING: data section could not be read correct"); + + nr = nbytes / valuesize; + LOG_PRINT(logfile, " [number of rows = %d (%d Bytes) @ 0x%X]\n", nr, nbytes, (unsigned int)file.tellg()); + + speadSheets[spread].maxRows < nr ? speadSheets[spread].maxRows = nr : 0; + readColumnValues(spread, current_col - 1, data_type, valuesize, nr); + } + + if (nbytes > 0 || columnname.empty()) + file.seekg(1, ios_base::cur); + + file >> size; + file.seekg(1 + size + (size > 0 ? 1 : 0), ios_base::cur); + + file >> size; + + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, "\n [column found = %d/0x%X (@ 0x%X)]\n", size, size, ((unsigned int) file.tellg()-5)); + colpos = file.tellg(); + } + + //////////////////////////////////////////////////////////////////////////// + ////////////////////// HEADER SECTION ////////////////////////////////////// + + unsigned int POS = (unsigned int)file.tellg()-11; + LOG_PRINT(logfile, "\nHEADER SECTION"); + LOG_PRINT(logfile, " nr_spreads = %d\n", speadSheets.size()); + LOG_PRINT(logfile, " [position @ 0x%X]\n", POS); + + //////////////////////// OBJECT INFOS ////////////////////////////////////// + POS += 0xB; + file.seekg(POS, ios_base::beg); + while(!file.eof()){ + POS = file.tellg(); + + file >> size; + if(size == 0) + break; + + file.seekg(POS + 0x7, ios_base::beg); + string name(25, 0); + file >> name; + + file.seekg(POS, ios_base::beg); + + if(findSpreadByName(name) != -1) + readSpreadInfo(); + else if(findMatrixByName(name) != -1) + readMatrixInfo(); + else if(findExcelByName(name) != -1) + readExcelInfo(); + else + readGraphInfo(); + + POS = file.tellg(); + } + + file.seekg(1, ios_base::cur); + readParameters(); + + file.seekg(1 + 5, ios_base::cur); + readNotes(); + // If file has no Note windows, last function will read to EOF, skipping the info for ResultsLog and ProjectTree. + // As we know there is always a ResultsLog window after the Note windows, we better rewind to the start of Notes. + file.seekg(POS, ios_base::beg); + readResultsLog(); + + file.seekg(1 + 4*5 + 0x10 + 1, ios_base::cur); + try { + readProjectTree(); + } catch(...){} + + LOG_PRINT(logfile, "Done parsing\n") +#ifndef NO_LOG_FILE + fclose(logfile); +#endif + + return true; +} + +void Origin700Parser::readMatrixInfo() +{ + return Origin750Parser::readMatrixInfo(); +} + +bool Origin700Parser::readGraphInfo() +{ + unsigned int POS = file.tellg(); + unsigned int size; + file >> size; + + POS += 5; + + string name(25, 0); + file.seekg(POS + 0x02, ios_base::beg); + file >> name; + //LOG_PRINT(logfile, " GRAPH name: %s cursor pos: 0x%X\n", name.c_str(), file.tellg()); + + graphs.push_back(Graph(name)); + file.seekg(POS, ios_base::beg); + readWindowProperties(graphs.back(), size); + + file.seekg(POS + 0x23, ios_base::beg); + file >> graphs.back().width; + file >> graphs.back().height; + + file.seekg(POS + 0x38, ios_base::beg); + unsigned char c; + file >> c; + graphs.back().connectMissingData = (c & 0x40); + + file.seekg(POS + 0x45, ios_base::beg); + string templateName(20, 0); + file >> templateName; + graphs.back().templateName = templateName; + LOG_PRINT(logfile, " TEMPLATE: %s pos: 0x%X\n", templateName.c_str(), (POS + 0x45)); + + unsigned int LAYER = POS; + LAYER += size + 0x1; + + while(!file.eof()){// multilayer loop + graphs.back().layers.push_back(GraphLayer()); + GraphLayer& layer(graphs.back().layers.back()); + + // LAYER section + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x05; + + file.seekg(LAYER + 0x0F, ios_base::beg); + file >> layer.xAxis.min; + file >> layer.xAxis.max; + file >> layer.xAxis.step; + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> layer.xAxis.majorTicks; + + unsigned char g; + file >> g; file >> g; + layer.xAxis.zeroLine = (g & 0x80); + layer.xAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x37, ios_base::beg); + file >> layer.xAxis.minorTicks; + file >> layer.xAxis.scale; + + file.seekg(LAYER + 0x3A, ios_base::beg); + file >> layer.yAxis.min; + file >> layer.yAxis.max; + file >> layer.yAxis.step; + + file.seekg(LAYER + 0x56, ios_base::beg); + file >> layer.yAxis.majorTicks; + + file >> g; file >> g; + layer.yAxis.zeroLine = (g & 0x80); + layer.yAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> layer.yAxis.minorTicks; + file >> layer.yAxis.scale; + + file.seekg(LAYER + 0x68, ios_base::beg); + file >> g; + layer.gridOnTop = (g & 0x04); + layer.exchangedAxes = (g & 0x40); + + file.seekg(LAYER + 0x71, ios_base::beg); + file.read(reinterpret_cast(&layer.clientRect), sizeof(Rect)); + + unsigned char border; + file.seekg(LAYER + 0x89, ios_base::beg); + file >> border; + layer.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + + unsigned char col; + file.seekg(LAYER + 0xA7, ios_base::beg); + file >> col; + layer.backgroundColor.type = (col & 0x01) ? Origin::Color::None : Origin::Color::Regular; + file >> col; + layer.backgroundColor.regular = col; + + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + + unsigned int sectionSize; + file >> size; + sectionSize = size; + while(!file.eof()){ + LAYER += 0x5; + + //section_header + + string sec_name(41, 0); + file.seekg(LAYER + 0x46, ios_base::beg); + file >> sec_name; + + unsigned int sectionNamePos = LAYER + 0x46; + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), (LAYER + 0x46)); + + Rect r; + file.seekg(LAYER + 0x03, ios_base::beg); + file.read(reinterpret_cast(&r), sizeof(Rect)); + + unsigned char attach; + file.seekg(LAYER + 0x28, ios_base::beg); + file >> attach; + + unsigned char border; + file >> border; + + Color color; + file.seekg(LAYER + 0x33, ios_base::beg); + file >> color; + + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_1 + LAYER += 0x5; + unsigned int osize = size; + //LOG_PRINT(logfile, " osize = %d (@ 0x%X)\n", size, (unsigned int)file.tellg()); + + file.seekg(LAYER, ios_base::beg); + readGraphAxisPrefixSuffixInfo(sec_name, size, layer); + + unsigned char type; + file >> type; + + LineVertex begin, end; + if (size == 120){//Line/Arrow + if (attach == Origin::Scale){ + if (type == 2){ + file.seekg(LAYER + 0x20, ios_base::beg); + file >> begin.x; + file >> end.x; + file.seekg(LAYER + 0x40, ios_base::beg); + file >> begin.y; + file >> end.y; + } else if (type == 4){//curved arrow: start point, 2 middle points and end point + file.seekg(LAYER + 0x20, ios_base::beg); + file >> begin.x; + file >> end.x; + file >> end.x; + file >> end.x; + file >> begin.y; + file >> end.y; + file >> end.y; + file >> end.y; + } + } else { + short x1, x2, y1, y2; + if (type == 2){//straight line/arrow + file >> x1; + file >> x2; + file.seekg(4, ios_base::cur); + file >> y1; + file >> y2; + file.seekg(4, ios_base::cur); + } else if (type == 4){//curved line/arrow has 4 points + file >> x1; + file.seekg(4, ios_base::cur); + file >> x2; + file >> y1; + file.seekg(4, ios_base::cur); + file >> 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(); + } + + file.seekg(LAYER + 0x11, ios_base::beg); + unsigned char arrows; + file >> arrows; + 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; + } + + file.seekg(LAYER + 0x60, ios_base::beg); + file >> begin.shapeType; + + file.seekg(LAYER + 0x64, ios_base::beg); + unsigned int w = 0; + file >> w; + begin.shapeWidth = (double)w/500.0; + + file >> w; + begin.shapeLength = (double)w/500.0; + + file.seekg(LAYER + 0x6C, ios_base::beg); + file >> end.shapeType; + + file.seekg(LAYER + 0x70, ios_base::beg); + file >> w; + end.shapeWidth = (double)w/500.0; + + file >> w; + end.shapeLength = (double)w/500.0; + } + + //text properties + short rotation; + file.seekg(LAYER + 0x02, ios_base::beg); + file >> rotation; + + unsigned char fontSize; + file >> fontSize; + + unsigned char tab; + file.seekg(LAYER + 0x0A, ios_base::beg); + file >> tab; + + //line properties + unsigned char lineStyle = 0; + double width = 0.0; + + file.seekg(LAYER + 0x12, ios_base::beg); + file >> lineStyle; + + unsigned short w1; + file >> w1; + width = (double)w1/500.0; + + Figure figure; + file.seekg(LAYER + 0x05, ios_base::beg); + file >> w1; + figure.width = (double)w1/500.0; + + file.seekg(LAYER + 0x08, ios_base::beg); + file >> figure.style; + + file.seekg(LAYER + 0x42, ios_base::beg); + file >> figure.fillAreaColor; + file >> w1; + figure.fillAreaPatternWidth = (double)w1/500.0; + + file.seekg(LAYER + 0x4A, ios_base::beg); + file >> figure.fillAreaPatternColor; + file >> figure.fillAreaPattern; + + unsigned char h; + file.seekg(LAYER + 0x57, ios_base::beg); + file >> h; + figure.useBorderColor = (h == 0x10); + + //section_body_2_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + + file.seekg(1, ios_base::cur); + if(sec_name == "XB") + { + string text(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Bottom; + layer.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(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Top; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Left; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Right; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Front; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Back; + layer.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") + { + file >> layer.zAxis.min; + file >> layer.zAxis.max; + file >> layer.zAxis.step; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> layer.zAxis.majorTicks; + + file.seekg(LAYER + 0x28, ios_base::beg); + file >> layer.zAxis.minorTicks; + file >> layer.zAxis.scale; + + file.seekg(LAYER + 0x5A, ios_base::beg); + file >> layer.xAngle; + file >> layer.yAngle; + file >> layer.zAngle; + + file.seekg(LAYER + 0x218, ios_base::beg); + file >> layer.xLength; + file >> layer.yLength; + file >> layer.zLength; + + layer.xLength /= 23.0; + layer.yLength /= 23.0; + layer.zLength /= 23.0; + + file.seekg(LAYER + 0x240, ios_base::beg); + file >> layer.orthographic3D; + } + else if(sec_name == "Legend") + { + string text(size, 0); + file >> text; + + layer.legend = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); + } + else if(sec_name == "__BCO2") // histogram + { + file.seekg(LAYER + 0x10, ios_base::beg); + file >> layer.histogramBin; + + file.seekg(LAYER + 0x20, ios_base::beg); + file >> layer.histogramEnd; + file >> layer.histogramBegin; + + unsigned int p = sectionNamePos + 81; + file.seekg(p, ios_base::beg); + + file >> layer.percentile.p1SymbolType; + file >> layer.percentile.p99SymbolType; + file >> layer.percentile.meanSymbolType; + file >> layer.percentile.maxSymbolType; + file >> layer.percentile.minSymbolType; + + file.seekg(p + 65, ios_base::beg); + file >> layer.percentile.labels; + + file.seekg(sectionNamePos + 94, ios_base::beg); + file >> layer.percentile.whiskersRange; + file >> layer.percentile.boxRange; + + file.seekg(sectionNamePos + 129, ios_base::beg); + file >> layer.percentile.whiskersCoeff; + file >> layer.percentile.boxCoeff; + + unsigned char h; + file >> h; + layer.percentile.diamondBox = (h == 0x82) ? true : false; + + p += 109; + file.seekg(p, ios_base::beg); + file >> layer.percentile.symbolSize; + layer.percentile.symbolSize = layer.percentile.symbolSize/2 + 1; + + p += 163; + file.seekg(p, ios_base::beg); + file >> layer.percentile.symbolColor; + file >> layer.percentile.symbolFillColor; + } + else if(sec_name == "vline") // Image profiles vertical cursor + { + file.seekg(sectionNamePos, ios_base::beg); + for (int i = 0; i < 2; i++) + skipLine(); + + file.seekg(0x20, ios_base::cur); + file >> layer.vLine; + LOG_PRINT(logfile, " vLine: %g\n", layer.vLine); + + layer.imageProfileTool = 1; + } + else if(sec_name == "hline") // Image profiles horizontal cursor + { + file.seekg(sectionNamePos, ios_base::beg); + for (int i = 0; i < 2; i++) + skipLine(); + + file.seekg(0x40, ios_base::cur); + file >> layer.hLine; + LOG_PRINT(logfile, " hLine: %g @ 0x%X\n", layer.hLine, (unsigned int)file.tellg()); + + layer.imageProfileTool = 1; + } + else if(sec_name == "ZCOLORS") + { + layer.isXYY3D = true; + } + else if(sec_name == "SPECTRUM1") + { + layer.isXYY3D = false; + layer.colorScale.visible = true; + + unsigned char h; + file.seekg(24, ios_base::cur); + file >> h; + layer.colorScale.reverseOrder = h; + file.seekg(7, ios_base::cur); + file >> layer.colorScale.colorBarThickness; + file >> layer.colorScale.labelGap; + file.seekg(56, ios_base::cur); + file >> layer.colorScale.labelsColor; + } + else if(size && type == 0xE9) // text + { + string text(size, 0); + file >> text; + + sec_name.resize(3); + if (sec_name == "PIE") + layer.pieTexts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + else + layer.texts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + } + else if(osize == 0x5E) // rectangle & circle + { + switch(type){ + 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; + + layer.figures.push_back(figure); + } + else if (osize == 120) // line/arrow + { + layer.lines.push_back(Line()); + Line& line(layer.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(osize == 0x28) // bitmap + { + if (type == 4){ + unsigned long filesize = size + 14; + layer.bitmaps.push_back(Bitmap()); + Bitmap& bitmap(layer.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; + file.read(reinterpret_cast(data), size); + } else if (type == 6){ + string gname(30, 0); + file.seekg(sectionNamePos + 93, ios_base::beg); + file >> gname; + layer.bitmaps.push_back(Bitmap(gname)); + Bitmap& bitmap(layer.bitmaps.back()); + bitmap.clientRect = r; + bitmap.attach = (Attach)attach; + bitmap.size = 0; + bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + } + } + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + //section_body_3_size + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_3 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + file.seekg(LAYER, ios_base::beg); + file >> size; + + if (!size || size != sectionSize) + break; + } + + LAYER += 0x5; + unsigned char h; + short w; + + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size){//check layer is not empty + while(!file.eof()){ + LAYER += 0x5; + + layer.curves.push_back(GraphCurve()); + GraphCurve& curve(layer.curves.back()); + + file.seekg(LAYER + 0x26, ios_base::beg); + file >> h; + curve.hidden = (h == 33); + LOG_PRINT(logfile, " hidden curve: %d\n", curve.hidden); + + file.seekg(LAYER + 0x4C, ios_base::beg); + file >> curve.type; + LOG_PRINT(logfile, " graph %d layer %d curve %d type : %d\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), (int)curve.type); + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour) + layer.isXYY3D = false; + + file.seekg(LAYER + 0x04, ios_base::beg); + file >> w; + pair column = findDataByIndex(w-1); + short nColY = w; + if(column.first.size() > 0){ + curve.dataName = column.first; + if(layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Z : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.zColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } + } + + file.seekg(LAYER + 0x23, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if (column.first.size() > 0){ + curve.xDataName = (curve.dataName != column.first) ? column.first : ""; + + if(layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } else if (layer.isXYY3D){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } + } + + file.seekg(LAYER + 0x4D, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if(column.first.size() > 0 && layer.is3D()){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + if(curve.dataName != column.first) + LOG_PRINT(logfile, " graph %d X and Y from different tables\n", graphs.size()); + } + + if(layer.is3D() || layer.isXYY3D) + graphs.back().is3D = true; + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> curve.lineConnect; + file >> curve.lineStyle; + + file.seekg(1, ios_base::cur); + file >> curve.boxWidth; + + file >> w; + curve.lineWidth=(double)w/500.0; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> w; + curve.symbolSize=(double)w/500.0; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + curve.fillArea = (h==2); + + file.seekg(LAYER + 0x1E, ios_base::beg); + file >> curve.fillAreaType; + + //text + if(curve.type == GraphCurve::TextPlot){ + file.seekg(LAYER + 0x13, ios_base::beg); + file >> curve.text.rotation; + + curve.text.rotation /= 10; + file >> curve.text.fontSize; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> h; + 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; + } + + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + char offset; + file.seekg(LAYER + 0x37, ios_base::beg); + file >> offset; + curve.text.xOffset = offset * 5; + file >> offset; + curve.text.yOffset = offset * 5; + } + + //vector + if(curve.type == GraphCurve::FlowVector || curve.type == GraphCurve::Vector){ + file.seekg(LAYER + 0x56, ios_base::beg); + file >> curve.vector.multiplier; + + file.seekg(LAYER + 0x5E, ios_base::beg); + file >> h; + + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.endXColumnName = column.second; + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> h; + + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.endYColumnName = column.second; + + file.seekg(LAYER + 0x18, ios_base::beg); + file >> h; + + 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; + + file >> h; + + if(h >= 0x64 && h < 0x1F4){ + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.magnitudeColumnName = column.second; + } else + curve.vector.constMagnitude = (int)curve.symbolSize; + + file.seekg(LAYER + 0x66, ios_base::beg); + file >> curve.vector.arrowLenght; + file >> curve.vector.arrowAngle; + + file >> h; + curve.vector.arrowClosed = !(h & 0x1); + + file >> w; + curve.vector.width=(double)w/500.0; + + file.seekg(LAYER + 0x142, ios_base::beg); + file >> h; + 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){ + file.seekg(LAYER + 0x92, ios_base::beg); + file >> h; + + 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); + + file >> curve.pie.formatAutomatic; + file >> curve.pie.distance; + file >> curve.pie.viewAngle; + + file.seekg(LAYER + 0x98, ios_base::beg); + file >> curve.pie.thickness; + + file.seekg(LAYER + 0x9A, ios_base::beg); + file >> curve.pie.rotation; + + file.seekg(LAYER + 0x9E, ios_base::beg); + file >> curve.pie.displacement; + + file.seekg(LAYER + 0xA0, ios_base::beg); + file >> curve.pie.radius; + file >> curve.pie.horizontalOffset; + + file.seekg(LAYER + 0xA6, ios_base::beg); + file >> curve.pie.displacedSectionCount; + } + //surface + if (layer.isXYY3D || curve.type == GraphCurve::Mesh3D){ + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.surface.type; + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + 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); + file >> curve.surface.frontColor; + + file.seekg(LAYER + 0x14C, ios_base::beg); + file >> w; + curve.surface.gridLineWidth = (double)w/500.0; + file >> curve.surface.gridColor; + + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + curve.surface.backColorEnabled = (h & 0x08); + file.seekg(LAYER + 0x15A, ios_base::beg); + file >> curve.surface.backColor; + file >> curve.surface.xSideWallColor; + file >> curve.surface.ySideWallColor; + + curve.surface.surface.fill = (h & 0x10); + curve.surface.surface.contour = (h & 0x40); + file.seekg(LAYER + 0x94, ios_base::beg); + file >> w; + curve.surface.surface.lineWidth = (double)w/500.0; + file >> curve.surface.surface.lineColor; + + curve.surface.topContour.fill = (h & 0x02); + curve.surface.topContour.contour = (h & 0x04); + file.seekg(LAYER + 0xB4, ios_base::beg); + file >> w; + curve.surface.topContour.lineWidth = (double)w/500.0; + file >> curve.surface.topContour.lineColor; + + curve.surface.bottomContour.fill = (h & 0x80); + curve.surface.bottomContour.contour = (h & 0x01); + file.seekg(LAYER + 0xA4, ios_base::beg); + file >> w; + curve.surface.bottomContour.lineWidth = (double)w/500.0; + file >> curve.surface.bottomContour.lineColor; + } + + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour){ + if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) + layer.isXYY3D = false; + + ColorMap& colorMap = (curve.type == GraphCurve::Mesh3D ? curve.surface.colorMap : curve.colorMap); + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + colorMap.fillEnabled = (h & 0x82); + + if (curve.type == GraphCurve::Contour){ + file.seekg(102, ios_base::cur); + file >> curve.text.fontSize; + + file.seekg(7, ios_base::cur); + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + file.seekg(2, ios_base::cur); + file >> curve.text.color; + } + file.seekg(LAYER + 0x258, ios_base::beg); + readColorMap(colorMap); + } + + file.seekg(LAYER + 0xC2, ios_base::beg); + file >> curve.fillAreaColor; + + file >> w; + curve.fillAreaPatternWidth=(double)w/500.0; + + file.seekg(LAYER + 0xCA, ios_base::beg); + file >> curve.fillAreaPatternColor; + + file >> curve.fillAreaPattern; + file >> curve.fillAreaPatternBorderStyle; + file >> w; + curve.fillAreaPatternBorderWidth=(double)w/500.0; + file >> curve.fillAreaPatternBorderColor; + + file.seekg(LAYER + 0x16A, ios_base::beg); + file >> curve.lineColor; + if (curve.type != GraphCurve::Contour) + curve.text.color = curve.lineColor; + + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.symbolType; + + file.seekg(LAYER + 0x12E, ios_base::beg); + file >> curve.symbolFillColor; + file >> curve.symbolColor; + curve.vector.color = curve.symbolColor; + + file >> h; + curve.symbolThickness = (h == 255 ? 1 : h); + file >> curve.pointOffset; + + file.seekg(LAYER + 0x143, ios_base::beg); + file >> h; + curve.connectSymbols = (h&0x8); + + LAYER += size + 0x1; + + unsigned int newSize; + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + LAYER += newSize + (newSize > 0 ? 0x1 : 0) + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + if(newSize != size) + break; + } + } + + LAYER += 0x5; + //read axis breaks + while(!file.eof()){ + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size == 0x2D){ + LAYER += 0x5; + file.seekg(LAYER + 2, ios_base::beg); + file >> h; + + if(h == 2) { + layer.xAxisBreak.minorTicksBefore = layer.xAxis.minorTicks; + layer.xAxisBreak.scaleIncrementBefore = layer.xAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.xAxisBreak); + } else if(h == 4){ + layer.yAxisBreak.minorTicksBefore = layer.yAxis.minorTicks; + layer.yAxisBreak.scaleIncrementBefore = layer.yAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.yAxisBreak); + } + LAYER += 0x2D + 0x1; + } else + break; + } + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + size = readGraphAxisInfo(layer.xAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.yAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.zAxis); + LAYER += size*0x6; + + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0) + break; + } + + file.seekg(LAYER + 0x5, ios_base::beg); + return true; +} + +OriginParser* createOrigin700Parser(const string& fileName) +{ + return new Origin700Parser(fileName); +} diff --git a/3rdparty/liborigin2/Origin700Parser.h b/3rdparty/liborigin2/Origin700Parser.h new file mode 100644 index 000000000..dcfccf628 --- /dev/null +++ b/3rdparty/liborigin2/Origin700Parser.h @@ -0,0 +1,45 @@ +/*************************************************************************** + File : Origin700Parser.h + -------------------------------------------------------------------- + Copyright : (C) 2010 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 7.0 file parser class (uses code from file + Origin750Parser.cpp written by Alex Kargovsky) + + ***************************************************************************/ + +/*************************************************************************** + * * + * 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_700_PARSER_H +#define ORIGIN_700_PARSER_H + +#include "Origin610Parser.h" + +class Origin700Parser : public Origin610Parser +{ +public: + Origin700Parser(const string& fileName); + bool parse(); + +protected: + void readMatrixInfo(); + bool readGraphInfo(); +}; + +#endif // ORIGIN_700_PARSER_H diff --git a/3rdparty/liborigin2/Origin750Parser.cpp b/3rdparty/liborigin2/Origin750Parser.cpp new file mode 100644 index 000000000..00df884cc --- /dev/null +++ b/3rdparty/liborigin2/Origin750Parser.cpp @@ -0,0 +1,2680 @@ +/*************************************************************************** + File : Origin750Parser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2007-2008 Alex Kargovsky + (C) 2010-2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 7.5 file parser 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 "Origin750Parser.h" + +const char* colTypeNames[] = {"X", "Y", "Z", "XErr", "YErr", "Label", "None"}; + +Origin750Parser::Origin750Parser(const string& fileName) +: file(fileName.c_str(), ios::binary) +{ + objectIndex = 0; + d_colormap_offset = 0x259; + windowsCount = 0; +} + +bool Origin750Parser::parse() +{ + unsigned int dataIndex = 0; + +#ifndef NO_LOG_FILE + // append progress in log file + logfile = fopen("opjfile.log", "a"); +#endif + + /////////////////// find column /////////////////////////////////////////////////////////// + skipLine(); + unsigned int size; + file >> size; + file.seekg(1 + size + 1 + 5, ios_base::cur); + + file >> size; + + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, " [column found = %d/0x%X @ 0x%X]\n", size, size, (unsigned int) file.tellg()); + + unsigned int colpos = file.tellg(); + unsigned int current_col = 1, nr = 0, nbytes = 0; + + while(size > 0 && size < 0x84) { // should be 0x72, 0x73 or 0x83 + //////////////////////////////// COLUMN HEADER ///////////////////////////////////////////// + short data_type; + char data_type_u; + unsigned int oldpos = file.tellg(); + + file.seekg(oldpos + 0x16, ios_base::beg); + file >> data_type; + + file.seekg(oldpos + 0x3F, ios_base::beg); + file >> data_type_u; + + char valuesize; + file.seekg(oldpos + 0x3D, ios_base::beg); + file >> valuesize; + + LOG_PRINT(logfile, " [valuesize = %d @ 0x%X]\n", (int)valuesize, ((unsigned int) file.tellg()-1)); + if(valuesize <= 0) + { + LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize); + valuesize = 10; + } + + file.seekg(oldpos + 0x58, ios_base::beg); + LOG_PRINT(logfile, " [Spreadsheet @ 0x%X]\n", (unsigned int) file.tellg()); + + string name(25, 0); + file >> name; + + string::size_type pos = name.find_last_of("_"); + string columnname; + if(pos != string::npos) + { + columnname = name.substr(pos + 1); + name.resize(pos); + } + LOG_PRINT(logfile, " NAME: %s\n", name.c_str()); + + unsigned int spread = 0; + if(columnname.empty()) + { + LOG_PRINT(logfile, "NO COLUMN NAME FOUND! Must be a Matrix or Function."); + ////////////////////////////// READ matrices or functions //////////////////////////////////// + + LOG_PRINT(logfile, " [position @ 0x%X]\n", (unsigned int) file.tellg()); + // TODO + short signature; + file >> signature; + LOG_PRINT(logfile, " SIGNATURE : %02X \n", signature); + + + file.seekg(oldpos + size + 1, ios_base::beg); + file >> size; + file.seekg(1, ios_base::cur); + size /= valuesize; + LOG_PRINT(logfile, " SIZE = %d\n", size); + + // catch exception + /*if(size>10000) + size=1000;*/ + + if (signature == 0x50C8 && size != 1) + signature = 0x50CA;//is a matrix + + switch(signature) + { + case 0x50CA: + case 0x70CA: + case 0x50F2: + case 0x50E2: + case 0x50E7: + case 0x50DB: + case 0x50DC: + case 0x70E2: + matrices.push_back(Matrix(name)); + matrices.back().sheets.push_back(MatrixSheet(name, dataIndex)); + ++dataIndex; + readMatrixValues(data_type, data_type_u, valuesize, size); + break; + case 0x10C8: + case 0x50C8: + functions.push_back(Function(name, dataIndex)); + ++dataIndex; + readFunction(colpos, valuesize, &oldpos); + break; + default: + LOG_PRINT(logfile, "UNKNOWN SIGNATURE: %.2X SKIP DATA\n", signature); + file.seekg(valuesize*size, ios_base::cur); + ++dataIndex; + + if(valuesize != 8 && valuesize <= 16) + { + file.seekg(2, ios_base::cur); + } + } + } + else + { // worksheet + if(speadSheets.size() == 0 || findSpreadByName(name) == -1) + { + LOG_PRINT(logfile, "NEW SPREADSHEET\n"); + current_col = 1; + speadSheets.push_back(SpreadSheet(name)); + spread = speadSheets.size() - 1; + speadSheets.back().maxRows = 0; + } + else + { + spread = findSpreadByName(/*sname*/name); + + current_col = speadSheets[spread].columns.size(); + + if(!current_col) + current_col = 1; + ++current_col; + } + LOG_PRINT(logfile, "SPREADSHEET = %s COLUMN NAME = %s (%d) (@0x%X)\n", name.c_str(), columnname.c_str(), current_col, (unsigned int)file.tellg()); + speadSheets[spread].columns.push_back(SpreadColumn(columnname, dataIndex)); + string::size_type sheetpos = speadSheets[spread].columns.back().name.find_last_of("@"); + if(sheetpos != string::npos){ + unsigned int sheet = atoi(columnname.substr(sheetpos + 1).c_str()); + if( sheet > 1){ + speadSheets[spread].columns.back().name = columnname; + speadSheets[spread].columns.back().sheet = sheet - 1; + + if (speadSheets[spread].sheets < sheet) + speadSheets[spread].sheets = sheet; + } + } + ++dataIndex; + + ////////////////////////////// SIZE of column ///////////////////////////////////////////// + file.seekg(oldpos + size + 1, ios_base::beg); + + file >> nbytes; + if (fmod(nbytes, (double)valuesize) > 0) + LOG_PRINT(logfile, "WARNING: data section could not be read correct"); + + nr = nbytes / valuesize; + LOG_PRINT(logfile, " [number of rows = %d (%d Bytes) @ 0x%X]\n", nr, nbytes, (unsigned int)file.tellg()); + + speadSheets[spread].maxRows < nr ? speadSheets[spread].maxRows = nr : 0; + readColumnValues(spread, current_col - 1, data_type, valuesize, nr); + } + + if(nbytes > 0 || columnname.empty()) + file.seekg(1, ios_base::cur); + + file >> size; + file.seekg(1 + size + (size > 0 ? 1 : 0), ios_base::cur); + + file >> size; + + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, "\n [column found = %d/0x%X (@ 0x%X)]\n", size, size, ((unsigned int) file.tellg() - 5)); + colpos = file.tellg(); + } + + //////////////////////////////////////////////////////////////////////////// + for(unsigned int i = 0; i < speadSheets.size(); ++i){ + if(speadSheets[i].sheets > 1){ + LOG_PRINT(logfile, " CONVERT SPREADSHEET \"%s\" to EXCEL\n", speadSheets[i].name.c_str()); + convertSpreadToExcel(i); + --i; + } + } + //////////////////////////////////////////////////////////////////////////// + ////////////////////// HEADER SECTION ////////////////////////////////////// + + unsigned int POS = (unsigned int)file.tellg()-11; + LOG_PRINT(logfile, "\nHEADER SECTION"); + LOG_PRINT(logfile, " nr_spreads = %d\n", speadSheets.size()); + LOG_PRINT(logfile, " [position @ 0x%X]\n", POS); + + //////////////////////// OBJECT INFOS ////////////////////////////////////// + POS += 0xB; + file.seekg(POS, ios_base::beg); + while(1){ + // HEADER + // check header + POS = file.tellg(); + + file >> size; + if(size == 0) + break; + + file.seekg(POS + 0x7, ios_base::beg); + string name(25, 0); + file >> name; + + file.seekg(POS, ios_base::beg); + + if(findSpreadByName(name) != -1) + readSpreadInfo(); + else if(findMatrixByName(name) != -1) + readMatrixInfo(); + else if(findExcelByName(name) != -1) + readExcelInfo(); + else + readGraphInfo(); + } + + file.seekg(1, ios_base::cur); + readParameters(); + + file.seekg(1 + 5, ios_base::cur); + while(!file.eof()){ + //fseek(f,5+0x40+1,SEEK_CUR); + int size; + file >> size; + if(size != 0x40) + break; + + file.seekg(1, ios_base::cur); + Rect rect; + unsigned int coord; + file >> coord; + rect.left = coord; + file >> coord; + rect.top = coord; + file >> coord; + rect.right = coord; + file >> coord; + rect.bottom = coord; + + unsigned char state; + file.seekg(0x8, ios_base::cur); + file >> state; + + double creationDate, modificationDate; + file.seekg(0x7, ios_base::cur); + file >> creationDate; + file >> modificationDate; + + file.seekg(0x8, ios_base::cur); + unsigned char c; + file >> c; + + unsigned char labellen; + file.seekg(0x3, ios_base::cur); + file >> labellen; + + file.seekg(4, ios_base::cur); + file >> size; + + file.seekg(1, ios_base::cur); + + string name(size, 0); + file >> name; + + if (name == "ResultsLog"){ + file.seekg(1, ios_base::cur); + file >> size; + + file.seekg(1, ios_base::cur); + resultsLog.resize(size); + file >> resultsLog; + + LOG_PRINT(logfile, "Results Log: %s\n", resultsLog.c_str()); + break; + } else { + name = name.substr(2); + name = name.substr(0, name.size() - 1); + notes.push_back(Note(name)); + notes.back().objectID = 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; + + notes.back().hidden = (state & 0x40); + + ++objectIndex; + + file.seekg(1, ios_base::cur); + file >> size; + + file.seekg(1, ios_base::cur); + + if(labellen > 1){ + file >> notes.back().label.assign(labellen-1, 0); + file.seekg(1, ios_base::cur); + } + + file >> notes.back().text.assign(size - labellen, 0); + + LOG_PRINT(logfile, "NOTE %d NAME: %s\n", notes.size(), notes.back().name.c_str()); + LOG_PRINT(logfile, "NOTE %d LABEL: %s\n", notes.size(), notes.back().label.c_str()); + LOG_PRINT(logfile, "NOTE %d TEXT: %s\n", notes.size(), notes.back().text.c_str()); + + file.seekg(1, ios_base::cur); + } + } + + file.seekg(1 + 4*5 + 0x10 + 1, ios_base::cur); + try + { + readProjectTree(); + } + catch(...) + {} + + LOG_PRINT(logfile, "Done parsing\n") +#ifndef NO_LOG_FILE + fclose(logfile); +#endif + + return true; +} + +void Origin750Parser::readParameters() +{ + if (file.eof()) + return; + + unsigned char c; + file >> c; + if (c != 0) + LOG_PRINT(logfile, "Some Origin params @ 0x%X:\n", (unsigned int)file.tellg()); + while(c != 0){ + LOG_PRINT(logfile, " "); + while(c != '\n'){ + LOG_PRINT(logfile, "%c", c) + file >> c; + } + double parvalue; + file >> parvalue; + LOG_PRINT(logfile, ": %g\n", parvalue); + + file.seekg(1, ios_base::cur); + file >> c; + } +} + +void Origin750Parser::readColumnValues(unsigned int spread, unsigned int col, short data_type, char valuesize, unsigned int nr, bool validColumn) +{ + if (spread >= speadSheets.size()) + return; + + file.seekg(1, ios_base::cur); + + LOG_PRINT(logfile, " [data @ 0x%X]\n", (unsigned int)file.tellg()); + for (unsigned int i = 0; i < nr; ++i){ + double value; + if(valuesize <= 8) // Numeric, Time, Date, Month, Day + { + file >> value; + LOG_PRINT(logfile, "%g ", value); + if (validColumn) + speadSheets[spread].columns[col].data.push_back(value); + } + else if((data_type & 0x100) == 0x100) // Text&Numeric + { + unsigned char c; + file >> c; + file.seekg(1, ios_base::cur); + if(c == 0) //value + { + file >> value; + LOG_PRINT(logfile, "%g ", value); + if (validColumn) + speadSheets[spread].columns[col].data.push_back(value); + file.seekg(valuesize - 10, ios_base::cur); + } + else //text + { + string stmp(valuesize - 2, 0); + file >> stmp; + if(stmp.find(0x0E) != string::npos) // try find non-printable symbol - garbage test + stmp = string(); + if (validColumn) + speadSheets[spread].columns[col].data.push_back(stmp); + LOG_PRINT(logfile, "%s ", stmp.c_str()); + } + } + else //text + { + string stmp(valuesize, 0); + file >> stmp; + if(stmp.find(0x0E) != string::npos) // try find non-printable symbol - garbage test + stmp = string(); + if (validColumn) + speadSheets[spread].columns[col].data.push_back(stmp); + LOG_PRINT(logfile, "%s ", stmp.c_str()); + } + } +} + +void Origin750Parser::readMatrixValues(short data_type, char data_type_u, char valuesize, unsigned int size, int mIndex) +{ + if (matrices.empty()) + return; + + if (mIndex < 0) + mIndex = matrices.size() - 1; + + bool logValues = true; + switch(data_type){ + case 0x6001://double + for(unsigned int i = 0; i < size; ++i){ + double value; + file >> value; + matrices[mIndex].sheets.back().data.push_back((double)value); + } + break; + case 0x6003://float + for(unsigned int i = 0; i < size; ++i){ + float value; + file >> value; + matrices[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; + file >> value; + matrices[mIndex].sheets.back().data.push_back((double)value); + } + } else { + for(unsigned int i = 0; i < size; ++i){ + int value; + file >> value; + matrices[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; + file >> value; + matrices[mIndex].sheets.back().data.push_back((double)value); + } + } else { + for(unsigned int i = 0; i < size; ++i){ + short value; + file >> value; + matrices[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; + file >> value; + matrices[mIndex].sheets.back().data.push_back((double)value); + } + } else { + for(unsigned int i = 0; i < size; ++i){ + char value; + file >> value; + matrices[mIndex].sheets.back().data.push_back((double)value); + } + } + break; + default: + LOG_PRINT(logfile, " UNKNOWN MATRIX DATATYPE: %02X SKIP DATA\n", data_type); + file.seekg(valuesize*size, ios_base::cur); + matrices.pop_back(); + logValues = false; + } + + if (logValues){ + LOG_PRINT(logfile, " FIRST 10 CELL VALUES: "); + for(unsigned int i = 0; i < 10 && i < matrices[mIndex].sheets.back().data.size(); ++i) + LOG_PRINT(logfile, "%g\t", matrices[mIndex].sheets.back().data[i]); + } +} + +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; +} + +void Origin750Parser::readFunction(unsigned int colpos, char valuesize, unsigned int *oldpos) +{ + Origin::Function &f = functions.back(); + file >> f.formula.assign(valuesize, 0); + f.formula = toLowerCase(f.formula); + *oldpos = file.tellg(); + + file.seekg(colpos + 0xA, ios_base::beg); + short t; + file >> t; + + if (t == 0x1194) + f.type = Function::Polar; + + file.seekg(colpos + 0x21, ios_base::beg); + file >> f.totalPoints; + + file >> f.begin; + double d; + file >> d; + f.end = f.begin + d*(f.totalPoints - 1); + + LOG_PRINT(logfile, "NEW FUNCTION: %s = %s\n", f.name.c_str(), f.formula.c_str()); + LOG_PRINT(logfile, " interval [%g : %g], number of points: %d\n", f.begin, f.end, f.totalPoints); + + file.seekg(*oldpos, ios_base::beg); +} + +void Origin750Parser::readSpreadInfo() +{ + unsigned int POS = file.tellg(); + unsigned int size; + file >> size; + + POS += 5; + + // check spreadsheet name + file.seekg(POS + 0x2, ios_base::beg); + string name(25, 0); + file >> name; + LOG_PRINT(logfile, " SPREADSHEET: %s (@ 0x%X)]\n", name.c_str(), (unsigned int)file.tellg()); + + unsigned int spread = findSpreadByName(name); + if (spread < 0 || spread >= speadSheets.size()) + return; + + speadSheets[spread].name = name; + file.seekg(POS, ios_base::beg); + readWindowProperties(speadSheets[spread], size); + speadSheets[spread].loose = false; + char c = 0; + + unsigned int LAYER = POS + size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += size + 0x6; + file.seekg(LAYER, ios_base::beg); + file >> size; + + // LAYER section + unsigned int sectionSize = size; + while(!file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + file.seekg(LAYER + 0x46, ios_base::beg); + string sec_name(41, 0); + file >> sec_name; + + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), (LAYER + 0x46)); + + //section_body_1_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_1 + LAYER += 0x5; + file.seekg(LAYER, ios_base::beg); + + int col_index = findColumnByName(spread, sec_name); + if(col_index != -1){//check if it is a formula + file >> speadSheets[spread].columns[col_index].command.assign(size, 0); + LOG_PRINT(logfile, " Column: %s has formula: %s\n", sec_name.c_str(), speadSheets[spread].columns[col_index].command.c_str()); + } + + //section_body_2_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0) + 0x5; + file.seekg(LAYER, ios_base::beg); + + file >> size; + if (sec_name == "statcbut" || sec_name == "Recalculate"){ + LAYER -= 0x5; + file.seekg(LAYER, ios_base::beg); + file >> size; + LAYER += size + (size > 0 ? 0x1 : 0) + 0x5; + file.seekg(LAYER, ios_base::beg); + file >> size; + } + + if(size != sectionSize) + break; + } + + file.seekg(1, ios_base::cur); + file >> size; + LAYER += 0x5; + sectionSize = size; + + vector header; + while(!file.eof()){ + LAYER += 0x5; + file.seekg(LAYER + 0x12, ios_base::beg); + + name.resize(12); + file >> name; + LOG_PRINT(logfile, " Column: %s (@ 0x%X)\n", name.c_str(), (LAYER + 0x12)); + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> c; + + short width = 0; + file.seekg(LAYER + 0x4A, ios_base::beg); + file >> width; + int col_index = findColumnByName(spread, name); + if(col_index != -1){ + if (speadSheets[spread].columns[col_index].name != name) + speadSheets[spread].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; + } + speadSheets[spread].columns[col_index].type = type; + + width/=0xA; + if(width == 0) + width = 8; + speadSheets[spread].columns[col_index].width = width; + + unsigned char c1,c2; + file.seekg(LAYER + 0x1E, ios_base::beg); + file >> c1; + file >> c2; + + switch(c1){ + case 0x00: // Numeric - Dec1000 + case 0x09: // Text&Numeric - Dec1000 + case 0x10: // Numeric - Scientific + case 0x19: // Text&Numeric - Scientific + case 0x20: // Numeric - Engeneering + case 0x29: // Text&Numeric - Engeneering + case 0x30: // Numeric - Dec1,000 + case 0x39: // Text&Numeric - Dec1,000 + speadSheets[spread].columns[col_index].valueType = (c1%0x10 == 0x9) ? TextNumeric : Numeric; + speadSheets[spread].columns[col_index].valueTypeSpecification = c1 / 0x10; + if(c2 >= 0x80){ + speadSheets[spread].columns[col_index].significantDigits = c2 - 0x80; + speadSheets[spread].columns[col_index].numericDisplayType = SignificantDigits; + } else if(c2 > 0) { + speadSheets[spread].columns[col_index].decimalPlaces = c2 - 0x03; + speadSheets[spread].columns[col_index].numericDisplayType = DecimalPlaces; + } + break; + case 0x02: // Time + speadSheets[spread].columns[col_index].valueType = Time; + speadSheets[spread].columns[col_index].valueTypeSpecification = c2 - 0x80; + break; + case 0x03: // Date + case 0x33: + speadSheets[spread].columns[col_index].valueType = Date; + speadSheets[spread].columns[col_index].valueTypeSpecification= c2 - 0x80; + break; + case 0x31: // Text + speadSheets[spread].columns[col_index].valueType = Text; + break; + case 0x4: // Month + case 0x34: + speadSheets[spread].columns[col_index].valueType = Month; + speadSheets[spread].columns[col_index].valueTypeSpecification = c2; + break; + case 0x5: // Day + case 0x35: + speadSheets[spread].columns[col_index].valueType = Day; + speadSheets[spread].columns[col_index].valueTypeSpecification = c2; + break; + default: // Text + speadSheets[spread].columns[col_index].valueType = Text; + break; + } + } + LAYER += sectionSize + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x5; + if(size > 0){ + if(col_index != -1){ + file.seekg(LAYER, ios_base::beg); + file >> speadSheets[spread].columns[col_index].comment.assign(size, 0); + } + LAYER += size + 0x1; + } + + if(col_index != -1) + header.push_back(speadSheets[spread].columns[col_index]); + + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size != sectionSize) + break; + } + + for (unsigned int i = 0; i < header.size(); i++) + speadSheets[spread].columns[i] = header[i]; + + file.seekg(1, ios_base::cur); + skipObjectInfo(); + LOG_PRINT(logfile, " Done with spreadsheet %d POS (@ 0x%X)\n", spread, (unsigned int)file.tellg()); +} + +void Origin750Parser::skipObjectInfo() +{ + unsigned int POS = file.tellg(); + unsigned int size; + file >> size; + while (!file.eof() && !size){ + skipLine(); + file >> size; + POS = file.tellg(); + } + + unsigned int nextSize = size; + while (!file.eof() && nextSize == size){ + POS += nextSize + 0x2; + file.seekg(POS, ios_base::beg); + + file >> nextSize; + POS += 0x4; + + if (!nextSize){ + POS += 0x1; + file.seekg(1, ios_base::cur); + file >> nextSize; + if (nextSize == size) + POS += 0x4; + } else if (nextSize > 1e6){ + file >> nextSize; + if (nextSize == size) + POS += 0x4; + } + } + file.seekg(1, ios_base::cur); +} + +void Origin750Parser::readExcelInfo() +{ + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + + POS += 5; + + LOG_PRINT(logfile, " [EXCEL SECTION (@ 0x%X)]\n", POS); + + // check spreadsheet name + string name(25, 0); + file.seekg(POS + 0x2, ios_base::beg); + file >> name; + + int iexcel = findExcelByName(name); + excels[iexcel].name = name; + file.seekg(POS, ios_base::beg); + readWindowProperties(excels[iexcel], size); + excels[iexcel].loose = false; + char c = 0; + + unsigned int LAYER = POS; + LAYER += size + 0x1; + int isheet = 0; + while(!file.eof()){// multisheet loop + // LAYER section + LAYER += 0x5/* length of block = 0x12D + '\n'*/ + 0x12D + 0x1; + //now structure is next : section_header_size=0x6F(4 bytes) + '\n' + section_header(0x6F bytes) + section_body_1_size(4 bytes) + '\n' + section_body_1 + section_body_2_size(maybe=0)(4 bytes) + '\n' + section_body_2 + '\n' + //possible sections: column formulas, __WIPR, __WIOTN, __LayerInfoStorage etc + //section name(column name in formula case) starts with 0x46 position + while(!file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + + string sec_name(41, 0); + file.seekg(LAYER + 0x46, ios_base::beg); + file >> sec_name; + + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), (LAYER + 0x46)); + + //section_body_1_size + LAYER += 0x6F + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_1 + LAYER += 0x5; + file.seekg(LAYER, ios_base::beg); + //check if it is a formula + int col_index = findExcelColumnByName(iexcel, isheet, sec_name); + if(col_index != -1) + file >> excels[iexcel].sheets[isheet].columns[col_index].command.assign(size, 0); + + //section_body_2_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0) + 0x5; + + + if(sec_name == "statcbut" || sec_name == "Recalculate" + || sec_name == "Text") // workaround: just skip this section + { + LAYER -= 0x5; + file.seekg(LAYER, ios_base::beg); + file >> size; + LAYER += size + (size > 0 ? 0x1 : 0) + 0x5; + file.seekg(LAYER, ios_base::beg); + } + + if(sec_name == "__LayerInfoStorage") + break; + + } + LAYER += 0x5; + + /////////////// COLUMN Types /////////////////////////////////////////// + LOG_PRINT(logfile, " Excel sheet %d has %d columns\n", isheet, excels[iexcel].sheets[isheet].columns.size()); + + while(!file.eof()){ + LAYER += 0x5; + file.seekg(LAYER + 0x12, ios_base::beg); + name.resize(12); + file >> name; + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> c; + + short width=0; + file.seekg(LAYER + 0x4A, ios_base::beg); + file >> width; + + 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,c2; + file.seekg(LAYER + 0x1E, ios_base::beg); + file >> c1; + file >> c2; + switch(c1){ + case 0x00: // Numeric - Dec1000 + case 0x09: // Text&Numeric - Dec1000 + case 0x10: // Numeric - Scientific + case 0x19: // Text&Numeric - Scientific + case 0x20: // Numeric - Engeneering + case 0x29: // Text&Numeric - Engeneering + 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 0x4: // Month + case 0x34: + excels[iexcel].sheets[isheet].columns[col_index].valueType = Month; + excels[iexcel].sheets[isheet].columns[col_index].valueTypeSpecification = c2; + break; + case 0x5: // 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; + } + LOG_PRINT(logfile, " COLUMN %s has type = %d(%d) (@ 0x%X)\n", excels[iexcel].sheets[isheet].columns[col_index].name.c_str(), type, (int)c, (LAYER + 0x11)); + } + LAYER += 0x1E7 + 0x1; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x5; + if(size > 0){ + if(col_index != -1){ + file.seekg(LAYER, ios_base::beg); + file >> excels[iexcel].sheets[isheet].columns[col_index].comment.assign(size, 0); + } + LAYER += size + 0x1; + } + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size != 0x1E7) + break; + } + LOG_PRINT(logfile, " Done with Excel %d\n", iexcel); + + //POS = LAYER+0x5*0x6+0x1ED*0x12; + LAYER += 0x5*0x5 + 0x1ED*0x12; + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0) + break; + + ++isheet; + } + + file.seekg(LAYER + 0x5, ios_base::beg); +} + +void Origin750Parser::readMatrixInfo() +{ + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + + POS += 5; + + string name(25, 0); + file.seekg(POS + 0x2, ios_base::beg); + file >> name; + LOG_PRINT(logfile, " MATRIX %s (@ 0x%X)]\n", name.c_str(), POS); + + int idx = findMatrixByName(name); + matrices[idx].name = name; + file.seekg(POS, ios_base::beg); + readWindowProperties(matrices[idx], size); + + MatrixSheet sheet = matrices[idx].sheets.back(); + + unsigned char h; + file.seekg(POS + 0x87, ios_base::beg); + file >> h; + switch(h){ + case 1: + sheet.view = MatrixSheet::ImageView; + break; + case 2: + matrices[idx].header = Matrix::XY; + break; + } + + unsigned int LAYER = POS; + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + // LAYER section + LAYER += 0x5; + + unsigned short width; + file.seekg(LAYER + 0x27, ios_base::beg); + file >> width; + if (width == 0) + width = 8; + sheet.width = width; + LOG_PRINT(logfile, " Width: %d (@ 0x%X)\n", sheet.width, (LAYER + 0x27)); + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> sheet.columnCount; + LOG_PRINT(logfile, " Columns: %d (@ 0x%X)\n", sheet.columnCount, (LAYER + 0x2B)); + + file.seekg(LAYER + 0x52, ios_base::beg); + file >> sheet.rowCount; + LOG_PRINT(logfile, " Rows: %d (@ 0x%X)\n", sheet.rowCount, (LAYER + 0x52)); + + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + unsigned int sectionSize = size; + while(!file.eof()){ + LAYER += 0x5; + + //section_header + string sec_name(41, 0); + file.seekg(LAYER + 0x46, ios_base::beg); + file >> sec_name; + //LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name, (LAYER + 0x46)); + + //section_body_1_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_1 + LAYER += 0x5; + //check if it is a formula + if(sec_name == "MV"){ + file.seekg(LAYER, ios_base::beg); + file >> sheet.command.assign(size, 0); + LOG_PRINT(logfile, " Formula: %s (@ 0x%X)\n", sheet.command.c_str(), LAYER); + } else if (sec_name == "Y2"){ + string s(size, 0); + file >> s; + sheet.coordinates[0] = stringToDouble(s); + LOG_PRINT(logfile, " Y2: %g\n", sheet.coordinates[0]); + } else if (sec_name == "X2"){ + string s(size, 0); + file >> s; + sheet.coordinates[1] = stringToDouble(s); + LOG_PRINT(logfile, " X2: %g\n", sheet.coordinates[1]); + } else if (sec_name == "Y1"){ + string s(size, 0); + file >> s; + sheet.coordinates[2] = stringToDouble(s); + LOG_PRINT(logfile, " Y1: %g\n", sheet.coordinates[2]); + } else if (sec_name == "X1"){ + string s(size, 0); + file >> s; + sheet.coordinates[3] = stringToDouble(s); + LOG_PRINT(logfile, " X1: %g\n", sheet.coordinates[3]); + } + + //section_body_2_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + if (sec_name == "COLORMAP"){ + file.seekg(LAYER + 0x14, ios_base::beg); + readColorMap(sheet.colorMap); + } + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0) + 0x5; + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size != sectionSize) + break; + } + file.seekg(1, ios_base::cur); + LAYER = file.tellg(); + file >> size; + + unsigned char c1, c2; + file.seekg(LAYER + 0x23, ios_base::beg); + file >> c1; + file >> c2; + + 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; + } + + LAYER += size + 0x06; + file.seekg(LAYER, ios_base::beg); + skipObjectInfo(); + + matrices[idx].sheets.back() = sheet; + LOG_PRINT(logfile, " Done with matrix %s (@ 0x%X)\n", name.c_str(), (unsigned int)file.tellg()); +} + +bool Origin750Parser::readGraphInfo() +{ + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + POS += 5; + + string name(25, 0); + file.seekg(POS + 0x02, ios_base::beg); + file >> name; + LOG_PRINT(logfile, " GRAPH name: %s @ 0x%X\n", name.c_str(), (unsigned int)file.tellg()); + + graphs.push_back(Graph(name)); + file.seekg(POS, ios_base::beg); + readWindowProperties(graphs.back(), size); + + file.seekg(POS + 0x23, ios_base::beg); + file >> graphs.back().width; + file >> graphs.back().height; + + file.seekg(POS + 0x38, ios_base::beg); + unsigned char c; + file >> c; + graphs.back().connectMissingData = (c & 0x40); + + file.seekg(POS + 0x45, ios_base::beg); + string templateName(20, 0); + file >> templateName; + graphs.back().templateName = templateName; + LOG_PRINT(logfile, " TEMPLATE: %s pos: 0x%X\n", templateName.c_str(), (POS + 0x45)); + if (templateName == "LAYOUT") + graphs.back().isLayout = true; + + unsigned int LAYER = POS; + LAYER += size + 0x1; + + while(!file.eof())// multilayer loop + { + graphs.back().layers.push_back(GraphLayer()); + GraphLayer& layer(graphs.back().layers.back()); + // LAYER section + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x05; + + file.seekg(LAYER + 0x0F, ios_base::beg); + file >> layer.xAxis.min; + file >> layer.xAxis.max; + file >> layer.xAxis.step; + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> layer.xAxis.majorTicks; + + unsigned char g; + file >> g; file >> g; + layer.xAxis.zeroLine = (g & 0x80); + layer.xAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x37, ios_base::beg); + file >> layer.xAxis.minorTicks; + file >> layer.xAxis.scale; + + file.seekg(LAYER + 0x3A, ios_base::beg); + file >> layer.yAxis.min; + file >> layer.yAxis.max; + file >> layer.yAxis.step; + + file.seekg(LAYER + 0x56, ios_base::beg); + file >> layer.yAxis.majorTicks; + + file >> g; file >> g; + layer.yAxis.zeroLine = (g & 0x80); + layer.yAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> layer.yAxis.minorTicks; + file >> layer.yAxis.scale; + + file.seekg(LAYER + 0x68, ios_base::beg); + file >> g; + layer.gridOnTop = (g & 0x04); + layer.exchangedAxes = (g & 0x40); + + file.seekg(LAYER + 0x71, ios_base::beg); + file.read(reinterpret_cast(&layer.clientRect), sizeof(Rect)); + + unsigned char border; + file.seekg(LAYER + 0x89, ios_base::beg); + file >> border; + layer.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + + file.seekg(LAYER + 0x105, ios_base::beg); + file >> layer.backgroundColor; + + LAYER += size + 0x1; + //now structure is next : section_header_size=0x6F(4 bytes) + '\n' + section_header(0x6F bytes) + section_body_1_size(4 bytes) + '\n' + section_body_1 + section_body_2_size(maybe=0)(4 bytes) + '\n' + section_body_2 + '\n' + //possible sections: axes, legend, __BC02, _202, _231, _232, __LayerInfoStorage etc + //section name starts with 0x46 position + while(!file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + + string sec_name(41, 0); + file.seekg(LAYER + 0x46, ios_base::beg); + file >> sec_name; + + unsigned int sectionNamePos = LAYER + 0x46; + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), (LAYER + 0x46)); + + Rect r; + file.seekg(LAYER + 0x03, ios_base::beg); + file.read(reinterpret_cast(&r), sizeof(Rect)); + + unsigned char attach; + file.seekg(LAYER + 0x28, ios_base::beg); + file >> attach; + + unsigned char border; + file >> border; + + Color color; + file.seekg(LAYER + 0x33, ios_base::beg); + file >> color; + + //section_body_1_size + LAYER += 0x6F + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_1 + LAYER += 0x5; + unsigned int osize = size; + unsigned int SECTION_BODY1_POS = LAYER; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisPrefixSuffixInfo(sec_name, size, layer); + + file.seekg(LAYER, ios_base::beg); + unsigned char type; + file >> type; + + LineVertex begin, end; + if (size == 120){//Line/Arrow + if (attach == Origin::Scale){ + if (type == 2){ + file.seekg(LAYER + 0x20, ios_base::beg); + file >> begin.x; + file >> end.x; + file.seekg(LAYER + 0x40, ios_base::beg); + file >> begin.y; + file >> end.y; + } else if (type == 4){//curved arrow: start point, 2 middle points and end point + file.seekg(LAYER + 0x20, ios_base::beg); + file >> begin.x; + file >> end.x; + file >> end.x; + file >> end.x; + file >> begin.y; + file >> end.y; + file >> end.y; + file >> end.y; + } + } else { + short x1, x2, y1, y2; + if (type == 2){//straight line/arrow + file >> x1; + file >> x2; + file.seekg(4, ios_base::cur); + file >> y1; + file >> y2; + file.seekg(4, ios_base::cur); + } else if (type == 4){//curved line/arrow has 4 points + file >> x1; + file.seekg(4, ios_base::cur); + file >> x2; + file >> y1; + file.seekg(4, ios_base::cur); + file >> 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(); + } + + file.seekg(LAYER + 0x11, ios_base::beg); + unsigned char arrows; + file >> arrows; + 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; + } + + file.seekg(LAYER + 0x60, ios_base::beg); + file >> begin.shapeType; + + file.seekg(LAYER + 0x64, ios_base::beg); + unsigned int w = 0; + file >> w; + begin.shapeWidth = (double)w/500.0; + + file >> w; + begin.shapeLength = (double)w/500.0; + + file.seekg(LAYER + 0x6C, ios_base::beg); + file >> end.shapeType; + + file.seekg(LAYER + 0x70, ios_base::beg); + file >> w; + end.shapeWidth = (double)w/500.0; + + file >> w; + end.shapeLength = (double)w/500.0; + } + + //text properties + short rotation; + file.seekg(LAYER + 0x02, ios_base::beg); + file >> rotation; + + unsigned char fontSize; + file >> fontSize; + + unsigned char tab; + file.seekg(LAYER + 0x0A, ios_base::beg); + file >> tab; + + //line properties + unsigned char lineStyle = 0; + double width = 0.0; + + file.seekg(LAYER + 0x12, ios_base::beg); + file >> lineStyle; + + unsigned short w1; + file >> w1; + width = (double)w1/500.0; + + Figure figure; + file.seekg(LAYER + 0x05, ios_base::beg); + file >> w1; + figure.width = (double)w1/500.0; + + file.seekg(LAYER + 0x08, ios_base::beg); + file >> figure.style; + + file.seekg(LAYER + 0x42, ios_base::beg); + file >> figure.fillAreaColor; + file >> w1; + figure.fillAreaPatternWidth = (double)w1/500.0; + + file.seekg(LAYER + 0x4A, ios_base::beg); + file >> figure.fillAreaPatternColor; + file >> figure.fillAreaPattern; + + unsigned char h; + file.seekg(LAYER + 0x57, ios_base::beg); + file >> h; + figure.useBorderColor = (h == 0x10); + + //section_body_2_size + LAYER += size + 0x1; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + //check if it is a axis or legend + + file.seekg(1, ios_base::cur); + if(sec_name == "XB") + { + string text(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Bottom; + layer.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(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Top; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Left; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Right; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Front; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Back; + layer.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") + { + file >> layer.zAxis.min; + file >> layer.zAxis.max; + file >> layer.zAxis.step; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> layer.zAxis.majorTicks; + + file.seekg(LAYER + 0x28, ios_base::beg); + file >> layer.zAxis.minorTicks; + file >> layer.zAxis.scale; + + file.seekg(LAYER + 0x5A, ios_base::beg); + file >> layer.xAngle; + file >> layer.yAngle; + file >> layer.zAngle; + + file.seekg(LAYER + 0x218, ios_base::beg); + file >> layer.xLength; + file >> layer.yLength; + file >> layer.zLength; + + layer.xLength /= 23.0; + layer.yLength /= 23.0; + layer.zLength /= 23.0; + + file.seekg(LAYER + 0x240, ios_base::beg); + file >> layer.orthographic3D; + } + else if(sec_name == "Legend") + { + string text(size, 0); + file >> text; + + layer.legend = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); + } + else if(sec_name == "__BCO2") // histogram + { + file.seekg(LAYER + 0x10, ios_base::beg); + file >> layer.histogramBin; + + file.seekg(LAYER + 0x20, ios_base::beg); + file >> layer.histogramEnd; + file >> layer.histogramBegin; + + unsigned int p = sectionNamePos + 93; + file.seekg(p, ios_base::beg); + + file >> layer.percentile.p1SymbolType; + file >> layer.percentile.p99SymbolType; + file >> layer.percentile.meanSymbolType; + file >> layer.percentile.maxSymbolType; + file >> layer.percentile.minSymbolType; + + file.seekg(p + 65, ios_base::beg); + file >> layer.percentile.labels; + + file.seekg(sectionNamePos + 106, ios_base::beg); + file >> layer.percentile.whiskersRange; + file >> layer.percentile.boxRange; + + file.seekg(sectionNamePos + 141, ios_base::beg); + file >> layer.percentile.whiskersCoeff; + file >> layer.percentile.boxCoeff; + + unsigned char h; + file >> h; + layer.percentile.diamondBox = (h == 0x82) ? true : false; + + p += 109; + file.seekg(p, ios_base::beg); + file >> layer.percentile.symbolSize; + layer.percentile.symbolSize = layer.percentile.symbolSize/2 + 1; + + p += 163; + file.seekg(p, ios_base::beg); + file >> layer.percentile.symbolColor; + file >> layer.percentile.symbolFillColor; + } + else if(sec_name == "_206") // box plot labels + { + file.seekg(sectionNamePos, ios_base::beg); + //LOG_PRINT(logfile, "box plot labels pos @ 0x%X\n", (unsigned int)file.tellg()); + + /*file >> curve.text.fontSize; + + file.seekg(7, ios_base::cur); + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + file.seekg(2, ios_base::cur);*/ + + file.seekg(33, ios_base::cur); + //LOG_PRINT(logfile, "box plot labels color @ 0x%X\n", (unsigned int)file.tellg()); + //file >> curve.text.color; + } + else if(sec_name == "vline") // Image profiles vertical cursor + { + file.seekg(sectionNamePos, ios_base::beg); + for (int i = 0; i < 2; i++) + skipLine(); + + file.seekg(0x20, ios_base::cur); + file >> layer.vLine; + LOG_PRINT(logfile, " vLine: %g\n", layer.vLine); + + layer.imageProfileTool = 1; + } + else if(sec_name == "hline") // Image profiles horizontal cursor + { + file.seekg(sectionNamePos, ios_base::beg); + for (int i = 0; i < 2; i++) + skipLine(); + + file.seekg(0x40, ios_base::cur); + file >> layer.hLine; + LOG_PRINT(logfile, " hLine: %g @ 0x%X\n", layer.hLine, (unsigned int)file.tellg()); + + layer.imageProfileTool = 1; + } + else if(sec_name == "ZCOLORS") + { + layer.isXYY3D = true; + } + else if(sec_name == "SPECTRUM1") + { + layer.isXYY3D = false; + layer.colorScale.visible = true; + + unsigned char h; + file.seekg(24, ios_base::cur); + file >> h; + layer.colorScale.reverseOrder = h; + file.seekg(7, ios_base::cur); + file >> layer.colorScale.colorBarThickness; + file >> layer.colorScale.labelGap; + file.seekg(56, ios_base::cur); + file >> layer.colorScale.labelsColor; + } + else if(sec_name == "&0") + { + layer.isWaterfall = true; + file.seekg(SECTION_BODY1_POS, ios_base::beg); + string text(osize, 0); + file >> text; + size_t commaPos = text.find_first_of(','); + layer.xOffset = atoi(text.substr(0, commaPos).c_str()); + layer.yOffset = atoi(text.substr(commaPos + 1).c_str()); + } + else if ((osize == 0x3E || (osize == 78 && type == 0)) && sec_name != "DelData") // text + { + string text(size, 0); + file >> text; + + sec_name.resize(3); + if (sec_name == "PIE") + layer.pieTexts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + else + layer.texts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + } + else if (osize == 0x5E) // rectangle & circle + { + switch(type) + { + 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; + + layer.figures.push_back(figure); + } + else if (osize == 0x78 && (type == 2 || type == 4) && sec_name != "sLine" && sec_name != "sline") // line/arrow + { + layer.lines.push_back(Line()); + Line& line(layer.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(osize == 0x28) // bitmap + { + if (type == 4){ + unsigned long filesize = size + 14; + layer.bitmaps.push_back(Bitmap()); + Bitmap& bitmap(layer.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; + file.read(reinterpret_cast(data), size); + } else if (type == 6){ + string gname(30, 0); + file.seekg(sectionNamePos + 93, ios_base::beg); + file >> gname; + layer.bitmaps.push_back(Bitmap(gname)); + Bitmap& bitmap(layer.bitmaps.back()); + bitmap.clientRect = r; + bitmap.attach = (Attach)attach; + bitmap.size = 0; + bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + } + } + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + //section_body_3_size + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_3 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + if(sec_name == "__LayerInfoStorage") + break; + } + LAYER += 0x5; + unsigned char h; + short w; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size)//check layer is not empty + { + while(!file.eof()){ + LAYER += 0x5; + + layer.curves.push_back(GraphCurve()); + GraphCurve& curve(layer.curves.back()); + + file.seekg(LAYER + 0x26, ios_base::beg); + file >> h; + curve.hidden = (h == 33); + LOG_PRINT(logfile, " hidden curve: %d\n", curve.hidden); + + file.seekg(LAYER + 0x4C, ios_base::beg); + file >> curve.type; + if (curve.type == GraphCurve::XYZContour || curve.type == GraphCurve::Contour) + layer.isXYY3D = false; + + LOG_PRINT(logfile, " graph %d layer %d curve %d type : %d\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), (int)curve.type); + + file.seekg(LAYER + 0x04, ios_base::beg); + file >> w; + pair column = findDataByIndex(w - 1); + short nColY = w; + if (column.first.size() > 0){ + curve.dataName = column.first; + if(layer.is3D() || (curve.type == GraphCurve::XYZContour)){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Z : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.zColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } + } + + file.seekg(LAYER + 0x23, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if (column.first.size() > 0){ + curve.xDataName = (curve.dataName != column.first) ? column.first : ""; + + if(layer.is3D() || (curve.type == GraphCurve::XYZContour)){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } else if (layer.isXYY3D){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } + } + + file.seekg(LAYER + 0x4D, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if (column.first.size() > 0 && (layer.is3D() || (curve.type == GraphCurve::XYZContour))){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + if(curve.dataName != column.first) + LOG_PRINT(logfile, " graph %d X and Y from different tables\n", graphs.size()); + } + + if(layer.is3D() || layer.isXYY3D) + graphs.back().is3D = true; + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> curve.lineConnect; + file >> curve.lineStyle; + + file.seekg(1, ios_base::cur); + file >> curve.boxWidth; + + file >> w; + curve.lineWidth=(double)w/500.0; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> w; + curve.symbolSize=(double)w/500.0; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + curve.fillArea = (h==2); + + file.seekg(LAYER + 0x1E, ios_base::beg); + file >> curve.fillAreaType; + + //text + if(curve.type == GraphCurve::TextPlot){ + file.seekg(LAYER + 0x13, ios_base::beg); + file >> curve.text.rotation; + curve.text.rotation /= 10; + file >> curve.text.fontSize; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> h; + 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; + } + + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + char offset; + file.seekg(LAYER + 0x37, ios_base::beg); + file >> offset; + curve.text.xOffset = offset * 5; + file >> offset; + curve.text.yOffset = offset * 5; + } + + //vector + if(curve.type == GraphCurve::FlowVector || curve.type == GraphCurve::Vector){ + file.seekg(LAYER + 0x56, ios_base::beg); + file >> curve.vector.multiplier; + + file.seekg(LAYER + 0x5E, ios_base::beg); + file >> h; + + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.endXColumnName = column.second; + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> h; + + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.endYColumnName = column.second; + + file.seekg(LAYER + 0x18, ios_base::beg); + file >> h; + + 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; + + file >> h; + + if(h >= 0x64 && h < 0x1F4){ + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.magnitudeColumnName = column.second; + } else + curve.vector.constMagnitude = (int)curve.symbolSize; + + file.seekg(LAYER + 0x66, ios_base::beg); + file >> curve.vector.arrowLenght; + file >> curve.vector.arrowAngle; + + file >> h; + curve.vector.arrowClosed = !(h & 0x1); + + file >> w; + curve.vector.width=(double)w/500.0; + + file.seekg(LAYER + 0x142, ios_base::beg); + file >> h; + 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){ + file.seekg(LAYER + 0x92, ios_base::beg); + file >> h; + + 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); + + file >> curve.pie.formatAutomatic; + file >> curve.pie.distance; + file >> curve.pie.viewAngle; + + file.seekg(LAYER + 0x98, ios_base::beg); + file >> curve.pie.thickness; + + file.seekg(LAYER + 0x9A, ios_base::beg); + file >> curve.pie.rotation; + + file.seekg(LAYER + 0x9E, ios_base::beg); + file >> curve.pie.displacement; + + file.seekg(LAYER + 0xA0, ios_base::beg); + file >> curve.pie.radius; + file >> curve.pie.horizontalOffset; + + file.seekg(LAYER + 0xA6, ios_base::beg); + file >> curve.pie.displacedSectionCount; + } + //surface + if (layer.isXYY3D || curve.type == GraphCurve::Mesh3D){ + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.surface.type; + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + 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); + file >> curve.surface.frontColor; + + file.seekg(LAYER + 0x14C, ios_base::beg); + file >> w; + curve.surface.gridLineWidth = (double)w/500.0; + file >> curve.surface.gridColor; + + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + curve.surface.backColorEnabled = (h & 0x08); + file.seekg(LAYER + 0x15A, ios_base::beg); + file >> curve.surface.backColor; + file >> curve.surface.xSideWallColor; + file >> curve.surface.ySideWallColor; + + curve.surface.surface.fill = (h & 0x10); + curve.surface.surface.contour = (h & 0x40); + file.seekg(LAYER + 0x94, ios_base::beg); + file >> w; + curve.surface.surface.lineWidth = (double)w/500.0; + file >> curve.surface.surface.lineColor; + + curve.surface.topContour.fill = (h & 0x02); + curve.surface.topContour.contour = (h & 0x04); + file.seekg(LAYER + 0xB4, ios_base::beg); + file >> w; + curve.surface.topContour.lineWidth = (double)w/500.0; + file >> curve.surface.topContour.lineColor; + + curve.surface.bottomContour.fill = (h & 0x80); + curve.surface.bottomContour.contour = (h & 0x01); + file.seekg(LAYER + 0xA4, ios_base::beg); + file >> w; + curve.surface.bottomContour.lineWidth = (double)w/500.0; + file >> curve.surface.bottomContour.lineColor; + } + + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour){ + if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) + layer.isXYY3D = false; + + ColorMap& colorMap = (curve.type == GraphCurve::Mesh3D ? curve.surface.colorMap : curve.colorMap); + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + colorMap.fillEnabled = (h & 0x82); + + if (curve.type == GraphCurve::Contour){ + file.seekg(102, ios_base::cur); + file >> curve.text.fontSize; + + file.seekg(7, ios_base::cur); + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + file.seekg(2, ios_base::cur); + file >> curve.text.color; + } + + file.seekg(LAYER + d_colormap_offset, ios_base::beg); + readColorMap(colorMap); + } + + file.seekg(LAYER + 0xC2, ios_base::beg); + file >> curve.fillAreaColor; + file >> w; + curve.fillAreaPatternWidth=(double)w/500.0; + + file.seekg(LAYER + 0xCA, ios_base::beg); + file >> curve.fillAreaPatternColor; + file >> curve.fillAreaPattern; + file >> curve.fillAreaPatternBorderStyle; + file >> w; + curve.fillAreaPatternBorderWidth=(double)w/500.0; + file >> curve.fillAreaPatternBorderColor; + + file.seekg(LAYER + 0x16A, ios_base::beg); + file >> curve.lineColor; + if (curve.type != GraphCurve::Contour) + curve.text.color = curve.lineColor; + + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.symbolType; + + file.seekg(LAYER + 0x12E, ios_base::beg); + file >> curve.symbolFillColor; + + file >> curve.symbolColor; + curve.vector.color = curve.symbolColor; + + file >> h; + curve.symbolThickness = (h == 255 ? 1 : h); + file >> curve.pointOffset; + + file.seekg(LAYER + 0x143, ios_base::beg); + file >> h; + curve.connectSymbols = (h&0x8); + + LAYER += size + 0x1; + + unsigned int newSize; + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + LAYER += newSize + (newSize > 0 ? 0x1 : 0) + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + if(newSize != size) + break; + } + } + + LAYER += 0x5; + //read axis breaks + while(!file.eof()){ + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0x2D){ + LAYER += 0x5; + file.seekg(LAYER + 2, ios_base::beg); + file >> h; + + if (h == 2) { + layer.xAxisBreak.minorTicksBefore = layer.xAxis.minorTicks; + layer.xAxisBreak.scaleIncrementBefore = layer.xAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.xAxisBreak); + } else if(h == 4){ + layer.yAxisBreak.minorTicksBefore = layer.yAxis.minorTicks; + layer.yAxisBreak.scaleIncrementBefore = layer.yAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.yAxisBreak); + } + LAYER += 0x2D + 0x1; + } + else + break; + } + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + size = readGraphAxisInfo(layer.xAxis); + LAYER += size*0x6 + 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.yAxis); + LAYER += size*0x6 + 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.zAxis); + LAYER += size*0x6 + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0) + break; + } + + file.seekg(LAYER + 0x5, ios_base::beg); + return true; +} + +void Origin750Parser::readGraphGridInfo(GraphGrid& grid) +{ + unsigned int POS = file.tellg(); + + unsigned char h; + short w; + + file.seekg(POS + 0x26, ios_base::beg); + file >> h; + grid.hidden = (h == 0); + + file.seekg(POS + 0x0F, ios_base::beg); + file >> grid.color; + + file.seekg(POS + 0x12, ios_base::beg); + file >> grid.style; + + file.seekg(POS + 0x15, ios_base::beg); + file >> w; + grid.width = (double)w/500.0; +} + +void Origin750Parser::readGraphAxisBreakInfo(GraphAxisBreak& axis_break) +{ + unsigned int POS = file.tellg(); + + axis_break.show = true; + + file.seekg(POS + 0x0B, ios_base::beg); + file >> axis_break.from; + + file >> axis_break.to; + + file >> axis_break.scaleIncrementAfter; + + file >> axis_break.position; + + unsigned char h; + file >> h; + axis_break.log10 = (h == 1); + + file >> axis_break.minorTicksAfter; +} + +void Origin750Parser::readGraphAxisFormatInfo(GraphAxisFormat& format) +{ + unsigned int POS = file.tellg(); + + unsigned char h; + short w; + + file.seekg(POS + 0x26, ios_base::beg); + file >> h; + format.hidden = (h == 0); + + file.seekg(POS + 0x0F, ios_base::beg); + file >> format.color; + + file.seekg(POS + 0x4A, ios_base::beg); + file >> w; + format.majorTickLength = (double)w/10.0; + + file.seekg(POS + 0x15, ios_base::beg); + file >> w; + format.thickness = (double)w/500.0; + + file.seekg(POS + 0x25, ios_base::beg); + file >> h; + + format.minorTicksType = (h>>6); + format.majorTicksType = ((h>>4) & 3); + format.axisPosition = (h & 0x0F); + switch(format.axisPosition) // need for testing + { + case 1: + file.seekg(POS + 0x37, ios_base::beg); + file >> h; + format.axisPositionValue = (double)h; + break; + case 2: + file.seekg(POS + 0x2F, ios_base::beg); + file >> format.axisPositionValue; + break; + } +} + +void Origin750Parser::readGraphAxisTickLabelsInfo(GraphAxisTick& tick) +{ + unsigned int POS = file.tellg(); + + unsigned char h; + unsigned char h1; + short w; + + file.seekg(POS + 0x26, ios_base::beg); + file >> h; + tick.showMajorLabels = (h & 0x40); + + file.seekg(POS + 0x0F, ios_base::beg); + file >> tick.color; + + file.seekg(POS + 0x13, ios_base::beg); + file >> w; + tick.rotation = w/10; + + file >> tick.fontSize; + + file.seekg(POS + 0x1A, ios_base::beg); + file >> h; + tick.fontBold = (h & 0x08); + + file.seekg(POS + 0x23, ios_base::beg); + file >> w; + file >> h; + file >> h1; + tick.valueType = (ValueType)(h & 0x0F); + + pair column; + switch(tick.valueType) + { + case Numeric: + + /*switch((h>>4)) + { + case 0x9: + tick.valueTypeSpecification=1; + break; + case 0xA: + tick.valueTypeSpecification=2; + break; + case 0xB: + tick.valueTypeSpecification=3; + break; + default: + tick.valueTypeSpecification=0; + }*/ + if((h>>4) > 7) + { + tick.valueTypeSpecification = (h>>4) - 8; + tick.decimalPlaces = h1 - 0x40; + } + else + { + tick.valueTypeSpecification = (h>>4); + tick.decimalPlaces = -1; + } + + break; + case Time: + case Date: + case Month: + case Day: + case ColumnHeading: + tick.valueTypeSpecification = h1 - 0x40; + break; + case Text: + case TickIndexedDataset: + case Categorical: + column = findDataByIndex(w-1); + if(column.first.size() > 0) + { + tick.dataName = column.first; + tick.columnName = column.second; + } + break; + default: // Numeric Decimal 1.000 + tick.valueType = Numeric; + tick.valueTypeSpecification = 0; + break; + } +} + +unsigned int Origin750Parser::readGraphAxisInfo(GraphAxis& axis) +{ + unsigned int POS = file.tellg(); + unsigned int size; + file >> size; + + POS += 0x5; + file.seekg(POS, ios_base::beg); + readGraphGridInfo(axis.minorGrid); + POS += size + 1; + + POS += 0x5; + file.seekg(POS, ios_base::beg); + readGraphGridInfo(axis.majorGrid); + POS += size + 1; + + POS += 0x5; + file.seekg(POS, ios_base::beg); + readGraphAxisTickLabelsInfo(axis.tickAxis[0]); + POS += size + 1; + + POS += 0x5; + file.seekg(POS, ios_base::beg); + readGraphAxisFormatInfo(axis.formatAxis[0]); + POS += size + 1; + + POS += 0x5; + file.seekg(POS, ios_base::beg); + readGraphAxisTickLabelsInfo(axis.tickAxis[1]); + POS += size + 1; + + POS += 0x5; + file.seekg(POS, ios_base::beg); + readGraphAxisFormatInfo(axis.formatAxis[1]); + + return (size + 1 + 0x5); +} + +void Origin750Parser::readProjectTree() +{ + if (file.eof()) + return; + + readProjectTreeFolder(projectTree.begin()); + LOG_PRINT(logfile, "Project has %d windows\n", windowsCount); + LOG_PRINT(logfile, "Origin project Tree:\n"); + + for(tree::iterator it = projectTree.begin(projectTree.begin()); it != projectTree.end(projectTree.begin()); ++it) + { + LOG_PRINT(logfile, "%s\n", (string(projectTree.depth(it) - 1, ' ') + (*it).name).c_str()); + } + + vector validMatrices; + for(unsigned int i = 0; i < matrices.size(); ++i){ + Matrix m = matrices[i]; + if (m.objectID >= 0) + validMatrices.push_back(m); + } + matrices.clear(); + matrices = validMatrices; +} + +void Origin750Parser::readProjectTreeFolder(tree::iterator parent) +{ + unsigned int POS = file.tellg(); + + double creationDate, modificationDate; + POS += 5; + + file.seekg(POS + 0x02, ios_base::beg); + unsigned char a; + file >> a; + bool activeFolder = (a == 1); + + file.seekg(POS + 0x10, ios_base::beg); + + file >> creationDate; + if (creationDate >= 1e10) + return; + + file >> modificationDate; + if (modificationDate >= 1e10) + return; + + POS += 0x20 + 1 + 5; + unsigned int size; + file.seekg(POS, ios_base::beg); + file >> size; + + POS += 5; + + // read folder name + string name(size, 0); + file.seekg(POS, ios_base::beg); + file >> name; + + tree::iterator current_folder = projectTree.append_child(parent, ProjectNode(name, ProjectNode::Folder, doubleToPosixTime(creationDate), doubleToPosixTime(modificationDate), activeFolder)); + POS += size + 1 + 5 + 5; + + unsigned int objectcount; + file.seekg(POS, ios_base::beg); + file >> objectcount; + + windowsCount += objectcount; + + POS += 5 + 5; + + for(unsigned int i = 0; i < objectcount; ++i){ + POS += 5; + char c; + file.seekg(POS + 0x2, ios_base::beg); + file >> c; + + unsigned int objectID; + file.seekg(POS + 0x4, ios_base::beg); + file >> objectID; + + if (c == 0x10) + projectTree.append_child(current_folder, ProjectNode(notes[objectID].name, ProjectNode::Note)); + else { + pair object = findObjectByIndex(objectID); + projectTree.append_child(current_folder, ProjectNode(object.second, object.first)); + } + + POS += 8 + 1 + 5 + 5; + } + + file.seekg(POS, ios_base::beg); + file >> objectcount; + + file.seekg(1, ios_base::cur); + for(unsigned int i = 0; i < objectcount; ++i) + readProjectTreeFolder(current_folder); +} + +void Origin750Parser::readWindowProperties(Window& window, unsigned int size) +{ + unsigned int POS = file.tellg(); + + window.objectID = objectIndex; + ++objectIndex; + + file.seekg(POS + 0x1B, ios_base::beg); + file.read(reinterpret_cast(&window.frameRect), sizeof(window.frameRect)); + + char c; + file.seekg(POS + 0x32, ios_base::beg); + file >> c; + + if(c & 0x01) + window.state = Window::Minimized; + else if(c & 0x02) + window.state = Window::Maximized; + + file.seekg(POS + 0x69, ios_base::beg); + file >> c; + + 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()); + + double creationDate, modificationDate; + file.seekg(POS + 0x73, ios_base::beg); + file >> creationDate; + if (creationDate > 1e4 && creationDate < 1e8) + window.creationDate = doubleToPosixTime(creationDate); + else + return; + + file >> modificationDate; + if (modificationDate > 1e4 && modificationDate < 1e8) + window.modificationDate = doubleToPosixTime(modificationDate); + else + return; + + if(size > 0xC3){ + unsigned int labellen = 0; + file.seekg(POS + 0xC3, ios_base::beg); + file >> c; + while(c != '@'){ + file >> c; + ++labellen; + } + if(labellen > 0){ + file.seekg(POS + 0xC3, ios_base::beg); + file >> window.label.assign(labellen, 0); + } + + LOG_PRINT(logfile, " WINDOW %d LABEL: %s\n", objectIndex, window.label.c_str()); + } +} + +void Origin750Parser::readColorMap(ColorMap& colorMap) +{ + unsigned int colorMapSize; + file >> colorMapSize; + + file.seekg(0x110, ios_base::cur); + for(unsigned int i = 0; i < colorMapSize + 3; ++i){ + ColorMapLevel level; + file >> level.fillPattern; + + file.seekg(0x03, ios_base::cur); + file >> level.fillPatternColor; + short w; + file >> w; + level.fillPatternLineWidth = (double)w/500.0; + + file.seekg(0x06, ios_base::cur); + file >> level.lineStyle; + + file.seekg(0x01, ios_base::cur); + file >> w; + level.lineWidth = (double)w/500.0; + file >> level.lineColor; + + file.seekg(0x02, ios_base::cur); + unsigned char h; + file >> h; + level.labelVisible = (h & 0x1); + level.lineVisible = !(h & 0x2); + + file.seekg(0x0D, ios_base::cur); + file >> level.fillColor; + file.seekg(0x04, ios_base::cur); + double value; + file >> value; + + colorMap.levels.push_back(make_pair(value, level)); + } +} + +void Origin750Parser::readGraphAxisPrefixSuffixInfo(const string& sec_name, unsigned int size, GraphLayer& layer) +{ + if(sec_name == "PL"){ + string text(size, 0); + file >> text; + layer.yAxis.formatAxis[0].prefix = text; + } else if(sec_name == "PR"){ + string text(size, 0); + file >> text; + layer.yAxis.formatAxis[1].prefix = text; + } else if(sec_name == "PB"){ + string text(size, 0); + file >> text; + layer.xAxis.formatAxis[0].prefix = text; + } else if(sec_name == "PT"){ + string text(size, 0); + file >> text; + layer.xAxis.formatAxis[1].prefix = text; + } if(sec_name == "SL"){ + string text(size, 0); + file >> text; + layer.yAxis.formatAxis[0].suffix = text; + } else if(sec_name == "SR"){ + string text(size, 0); + file >> text; + layer.yAxis.formatAxis[1].suffix = text; + } else if(sec_name == "SB"){ + string text(size, 0); + file >> text; + layer.xAxis.formatAxis[0].suffix = text; + } else if(sec_name == "ST"){ + string text(size, 0); + file >> text; + layer.xAxis.formatAxis[1].suffix = text; + } else if(sec_name == "OL"){ + string text(size, 0); + file >> text; + layer.yAxis.formatAxis[0].factor = text; + } else if(sec_name == "OR"){ + string text(size, 0); + file >> text; + layer.yAxis.formatAxis[1].factor = text; + } else if(sec_name == "OB"){ + string text(size, 0); + file >> text; + layer.xAxis.formatAxis[0].factor = text; + } else if(sec_name == "OT"){ + string text(size, 0); + file >> text; + layer.xAxis.formatAxis[1].factor = text; + } +} + +void Origin750Parser::skipLine() +{ + unsigned char c; + file >> c; + + while(c != '\n'){ + file >> c; + if (file.eof()) + break; + } +} + +OriginParser* createOrigin750Parser(const string& fileName) +{ + return new Origin750Parser(fileName); +} diff --git a/3rdparty/liborigin2/Origin750Parser.h b/3rdparty/liborigin2/Origin750Parser.h new file mode 100644 index 000000000..e71eac4eb --- /dev/null +++ b/3rdparty/liborigin2/Origin750Parser.h @@ -0,0 +1,90 @@ +/*************************************************************************** + File : Origin750Parser.h + -------------------------------------------------------------------- + Copyright : (C) 2007-2008 Alex Kargovsky, Ion Vasilief + Email (use @ for *) : kargovsky*yumr.phys.msu.su, ion_vasilief*yahoo.fr + Description : Origin 7.5 file parser 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_750_PARSER_H +#define ORIGIN_750_PARSER_H + +#include "OriginParser.h" +#include "endianfstream.hh" +#include +#include +using namespace std; +using namespace Origin; + +class Origin750Parser : public OriginParser +{ +public: + Origin750Parser(const string& fileName); + bool parse(); + +protected: + void skipObjectInfo(); + void readParameters(); + void readFunction(unsigned int colpos, char valuesize, unsigned int *oldpos); + void readSpreadInfo(); + void readExcelInfo(); + void readMatrixInfo(); + void readColumnValues(unsigned int spread, unsigned int col, short data_type, char valuesize, unsigned int nr, bool validColumn = true); + void readMatrixValues(short data_type, char data_type_u, char valuesize, unsigned int size, int mIndex = -1); + virtual bool readGraphInfo(); + unsigned int readGraphAxisInfo(GraphAxis& axis); + void readGraphGridInfo(GraphGrid& grid); + void readGraphAxisBreakInfo(GraphAxisBreak& axis_break); + void readGraphAxisFormatInfo(GraphAxisFormat& format); + void readGraphAxisTickLabelsInfo(GraphAxisTick& tick); + void readGraphAxisPrefixSuffixInfo(const string& sec_name, unsigned int size, GraphLayer& layer); + void readProjectTree(); + virtual void readProjectTreeFolder(tree::iterator parent); + void readWindowProperties(Window& window, unsigned int size); + virtual void readColorMap(ColorMap& colorMap); + void skipLine(); + + inline double stringToDouble(const string& s) + { + string s1 = s; + size_t pos = s.find(","); + if (pos != string::npos) + s1.replace(pos, 1, "."); + return strtod(s1.c_str(), NULL); + } + + inline time_t doubleToPosixTime(double jdt) + { + /* 2440587.5 is julian date for the unixtime epoch */ + return (time_t) floor((jdt - 2440587) * 86400. + 0.5); + } + + unsigned int objectIndex; + iendianfstream file; + FILE *logfile; + + unsigned int d_colormap_offset; +}; + +#endif // ORIGIN_750_PARSER_H diff --git a/3rdparty/liborigin2/Origin800Parser.cpp b/3rdparty/liborigin2/Origin800Parser.cpp new file mode 100644 index 000000000..d81111f4b --- /dev/null +++ b/3rdparty/liborigin2/Origin800Parser.cpp @@ -0,0 +1,951 @@ +/*************************************************************************** + File : Origin800Parser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2010 - 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 8.0 file parser class (uses code from file + Origin750Parser.cpp written by Alex Kargovsky) + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "Origin800Parser.h" + +Origin800Parser::Origin800Parser(const string& fileName) +: Origin750Parser(fileName) +{ + d_colormap_offset = 0x25B; + notes_pos_mark = "H"; +} + +bool Origin800Parser::parse() +{ + if (fileVersion >= 2881) + d_colormap_offset = 0x25F; + + unsigned int dataIndex = 0; + +#ifndef NO_LOG_FILE + // append progress in log file + logfile = fopen("opjfile.log", "a"); +#endif + + /////////////////// find column /////////////////////////////////////////////////////////// + skipLine(); + + unsigned int size; + file >> size; + + file.seekg(1 + size + 1 + 5, ios_base::cur); + file >> size; + + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, " [column found = %d/0x%X @ 0x%X]\n", size, size, (unsigned int) file.tellg()); + + unsigned int colpos = file.tellg(); + unsigned int current_col = 1, nr = 0, nbytes = 0; + unsigned int col_index = 0; + unsigned int current_sheet = 0; + + while(size > 0 && size <= 0x8C){// should be 0x72, 0x73 or 0x83 ? + //////////////////////////////// COLUMN HEADER ///////////////////////////////////////////// + + short data_type; + char data_type_u; + unsigned int oldpos = file.tellg(); + + file.seekg(oldpos + 0x16, ios_base::beg); + file >> data_type; + + file.seekg(oldpos + 0x3F, ios_base::beg); + file >> data_type_u; + + char valuesize; + file.seekg(oldpos + 0x3D, ios_base::beg); + file >> valuesize; + + LOG_PRINT(logfile, " [valuesize = %d @ 0x%X]\n", (int)valuesize, ((unsigned int) file.tellg()-1)); + if(valuesize <= 0){ + LOG_PRINT(logfile, " WARNING : found strange valuesize of %d\n", (int)valuesize); + valuesize = 10; + } + + file.seekg(oldpos + 0x58, ios_base::beg); + LOG_PRINT(logfile, " [Spreadsheet @ 0x%X]\n", (unsigned int) file.tellg()); + + string name(25, 0); + file >> name; + + string::size_type pos = name.find_last_of("_"); + string columnname; + if(pos != string::npos){ + columnname = name.substr(pos + 1); + name.resize(pos); + } + + LOG_PRINT(logfile, "NAME: %s\n", name.c_str()); + + unsigned int spread = 0; + if(columnname.empty()){ + LOG_PRINT(logfile, " NO COLUMN NAME FOUND! Must be a Matrix or Function."); + ////////////////////////////// READ matrices or functions //////////////////////////////////// + + LOG_PRINT(logfile, " [position @ 0x%X]\n", (unsigned int) file.tellg()); + // TODO + short signature; + file >> signature; + LOG_PRINT(logfile, " SIGNATURE : %02X \n", signature); + + + file.seekg(oldpos + size + 1, ios_base::beg); + file >> size; + file.seekg(1, ios_base::cur); + size /= valuesize; + LOG_PRINT(logfile, " SIZE = %d\n", size); + + if (signature == 0x50C8 && size != 1) + signature = 0x50CA;//is a matrix + + switch(signature) + { + case 0x50CA: + case 0x51CA: + case 0x70CA: + case 0x50F2: + case 0x51E2: + case 0x51F2: + case 0x51DC: + case 0x50E2: + case 0x50E7: + case 0x50DB: + case 0x50DC: + case 0x70E2: + { + int mIndex = -1; + pos = name.find_first_of("@"); + if (pos != string::npos){ + string sheetName = name; + name.resize(pos); + mIndex = findMatrixByName(name); + if (mIndex != -1){ + LOG_PRINT(logfile, " NEW MATRIX SHEET\n"); + matrices[mIndex].sheets.push_back(MatrixSheet(sheetName, dataIndex)); + } + } else { + LOG_PRINT(logfile, " NEW MATRIX\n"); + matrices.push_back(Matrix(name)); + matrices.back().sheets.push_back(MatrixSheet(name, dataIndex)); + } + + ++dataIndex; + readMatrixValues(data_type, data_type_u, valuesize, size, mIndex); + break; + } + + case 0x10C8: + case 0x50C8: + functions.push_back(Function(name, dataIndex)); + ++dataIndex; + readFunction(colpos, valuesize, &oldpos); + break; + + default: + LOG_PRINT(logfile, " UNKNOWN SIGNATURE: %.2X SKIP DATA\n", signature); + file.seekg(valuesize*size, ios_base::cur); + ++dataIndex; + + if(valuesize != 8 && valuesize <= 16) + { + file.seekg(2, ios_base::cur); + } + } + } + else + { // worksheet + if(speadSheets.size() == 0 || findSpreadByName(name) == -1) + { + LOG_PRINT(logfile, " NEW SPREADSHEET\n"); + current_col = 1; + speadSheets.push_back(SpreadSheet(name)); + spread = speadSheets.size() - 1; + speadSheets.back().maxRows = 0; + current_sheet = 0; + } + else + { + spread = findSpreadByName(name); + current_col = speadSheets[spread].columns.size(); + if(!current_col) + current_col = 1; + ++current_col; + } + speadSheets[spread].columns.push_back(SpreadColumn(columnname, dataIndex)); + speadSheets[spread].columns.back().colIndex = ++col_index; + + string::size_type sheetpos = speadSheets[spread].columns.back().name.find_last_of("@"); + if(sheetpos != string::npos){ + unsigned int sheet = atoi(columnname.substr(sheetpos + 1).c_str()); + if( sheet > 1){ + speadSheets[spread].columns.back().name = columnname; + + if (current_sheet != (sheet - 1)) + current_sheet = sheet - 1; + + speadSheets[spread].columns.back().sheet = current_sheet; + if (speadSheets[spread].sheets < sheet) + speadSheets[spread].sheets = sheet; + } + } + LOG_PRINT(logfile, " SPREADSHEET = %s SHEET = %d COLUMN NAME = %s (%d) INDEX = %d (@0x%X)\n", name.c_str(), speadSheets[spread].columns.back().sheet, columnname.c_str(), current_col, speadSheets[spread].columns.back().colIndex, (unsigned int)file.tellg()); + + ++dataIndex; + + ////////////////////////////// SIZE of column ///////////////////////////////////////////// + file.seekg(oldpos + size + 1, ios_base::beg); + + file >> nbytes; + if(fmod(nbytes, (double)valuesize)>0){ + LOG_PRINT(logfile, "WARNING: data section could not be read correctly"); + } + nr = nbytes / valuesize; + LOG_PRINT(logfile, " [number of rows = %d (%d Bytes) @ 0x%X]\n", nr, nbytes, (unsigned int)file.tellg()); + + speadSheets[spread].maxRows> value; + LOG_PRINT(logfile, "%g ", value); + speadSheets[spread].columns[current_col - 1].data.push_back(value); + } + else if((data_type & 0x100) == 0x100) // Text&Numeric + { + unsigned char c; + file >> c; + file.seekg(1, ios_base::cur); + if(c == 0) //value + { + file >> value; + LOG_PRINT(logfile, "%g ", value); + speadSheets[spread].columns[current_col - 1].data.push_back(value); + file.seekg(valuesize - 10, ios_base::cur); + } + else //text + { + string stmp(valuesize - 2, 0); + file >> stmp; + if(stmp.find(0x0E) != string::npos) // try find non-printable symbol - garbage test + stmp = string(); + speadSheets[spread].columns[current_col - 1].data.push_back(stmp); + LOG_PRINT(logfile, "%s ", stmp.c_str()); + } + } + else //text + { + string stmp(valuesize, 0); + file >> stmp; + if(stmp.find(0x0E) != string::npos) // try find non-printable symbol - garbage test + stmp = string(); + speadSheets[spread].columns[current_col - 1].data.push_back(stmp); + LOG_PRINT(logfile, "%s ", stmp.c_str()); + } + } + } + + if(nbytes > 0 || columnname.empty()) + { + file.seekg(1, ios_base::cur); + } + + file >> size; + file.seekg(1 + size + (size > 0 ? 1 : 0), ios_base::cur); + + file >> size; + + file.seekg(1, ios_base::cur); + LOG_PRINT(logfile, "\n [column found = %d/0x%X (@ 0x%X)]\n", size, size, ((unsigned int) file.tellg()-5)); + colpos = file.tellg(); + } + + //////////////////////////////////////////////////////////////////////////// + ////////////////////// HEADER SECTION ////////////////////////////////////// + + unsigned int POS = (unsigned int)file.tellg()-11; + LOG_PRINT(logfile, "\nHEADER SECTION"); + LOG_PRINT(logfile, " nr_spreads = %d\n", speadSheets.size()); + LOG_PRINT(logfile, " [position @ 0x%X]\n", POS); + + POS += 0xB; + file.seekg(POS, ios_base::beg); + while(!file.eof()){ + POS = file.tellg(); + + file >> size; + if(size == 0) + break; + + file.seekg(POS + 0x7, ios_base::beg); + string name(25, 0); + file >> name; + + file.seekg(POS, ios_base::beg); + + if(findSpreadByName(name) != -1) + readSpreadInfo(); + else if(findMatrixByName(name) != -1) + readMatrixInfo(); + else if(findExcelByName(name) != -1) + readExcelInfo(); + else + readGraphInfo(); + + POS = file.tellg(); + } + + file.seekg(1, ios_base::cur); + readParameters(); + + file.seekg(1 + 5, ios_base::cur); + readNotes(); + // If file has no Note windows, last function will read to EOF, skipping the info for ResultsLog and ProjectTree. + // As we know there is always a ResultsLog window after the Note windows, we better rewind to the start of Notes. + file.seekg(POS, ios_base::beg); + readResultsLog(); + + file.seekg(1 + 4*5 + 0x10 + 1, ios_base::cur); + try { + readProjectTree(); + } catch(...) {} + + LOG_PRINT(logfile, "Done parsing\n") +#ifndef NO_LOG_FILE + fclose(logfile); +#endif + + return true; +} + +void Origin800Parser::readNotes() +{ + if (file.eof()) + return; + + unsigned int pos = findStringPos(notes_pos_mark); + file.seekg(pos, ios_base::beg); + + unsigned int sectionSize; + file >> sectionSize; + while(!file.eof()){ + file.seekg(1, ios_base::cur); + + Rect rect; + unsigned int coord; + file >> coord; + rect.left = coord; + file >> coord; + rect.top = coord; + file >> coord; + rect.right = coord; + file >> coord; + rect.bottom = coord; + + if (!rect.bottom || !rect.right) + break; + + unsigned char state; + file.seekg(0x8, ios_base::cur); + file >> state; + + double creationDate, modificationDate; + file.seekg(0x7, ios_base::cur); + file >> creationDate; + file >> modificationDate; + + file.seekg(0x8, ios_base::cur); + unsigned char c; + file >> c; + + unsigned int labellen; + file.seekg(0x3, ios_base::cur); + file >> labellen; + + skipLine(); + + unsigned int size; + file >> size; + file.seekg(1, ios_base::cur); + + string name(size, 0); + file >> name; + + notes.push_back(Note(name)); + notes.back().objectID = objectIndex; + ++objectIndex; + + notes.back().frameRect = rect; + if (creationDate >= 1e10) + return; + notes.back().creationDate = doubleToPosixTime(creationDate); + if (modificationDate >= 1e10) + return; + 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); + + file.seekg(1, ios_base::cur); + file >> size; + + file.seekg(1, ios_base::cur); + + if(labellen > 1){ + file >> notes.back().label.assign(labellen - 1, 0); + file.seekg(1, ios_base::cur); + } + + file >> notes.back().text.assign(size - labellen, 0); + + LOG_PRINT(logfile, "NOTE %d NAME: %s\n", notes.size(), notes.back().name.c_str()); + LOG_PRINT(logfile, "NOTE %d LABEL: %s\n", notes.size(), notes.back().label.c_str()); + LOG_PRINT(logfile, "NOTE %d TEXT: %s\n", notes.size(), notes.back().text.c_str()); + + file.seekg(1, ios_base::cur); + + file >> size; + if(size != sectionSize) + break; + } +} + +void Origin800Parser::readResultsLog() +{ + int pos = findStringPos("ResultsLog"); + if (pos < 0) + return; + + file.seekg(pos + 12, ios_base::beg); + unsigned int size; + file >> size; + + file.seekg(1, ios_base::cur); + resultsLog.resize(size); + file >> resultsLog; + LOG_PRINT(logfile, "Results Log: %s\n", resultsLog.c_str()); +} + +void Origin800Parser::readSpreadInfo() +{ + unsigned int POS = file.tellg(); + unsigned int size; + file >> size; + + POS += 5; + + // check spreadsheet name + file.seekg(POS + 0x2, ios_base::beg); + string name(25, 0); + file >> name; + LOG_PRINT(logfile, " SPREADSHEET: %s (@ 0x%X)]\n", name.c_str(), (unsigned int)file.tellg()); + + int spread = findSpreadByName(name); + speadSheets[spread].name = name; + file.seekg(POS, ios_base::beg); + readWindowProperties(speadSheets[spread], size); + speadSheets[spread].loose = false; + char c = 0; + + unsigned int LAYER = POS + size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + vector header; + int sheets = speadSheets[spread].sheets; + for (int i = 0; i < sheets; i++){ + LAYER += size + 0x6; + file.seekg(LAYER, ios_base::beg); + file >> size; + LOG_PRINT(logfile, " SHEET: %d (@ 0x%X)\n", (i + 1), (unsigned int)file.tellg()); + + // LAYER section + unsigned int sectionSize = size; + while(size && !file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + file.seekg(LAYER + 0x46, ios_base::beg); + string sec_name(41, 0); + file >> sec_name; + + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), (LAYER + 0x46)); + + //section_body_1_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_1 + LAYER += 0x5; + file.seekg(LAYER, ios_base::beg); + + int col_index = findColumnByName(spread, sec_name); + if(col_index != -1){//check if it is a formula + file >> speadSheets[spread].columns[col_index].command.assign(size, 0); + LOG_PRINT(logfile, " Column: %s has formula: %s\n", sec_name.c_str(), speadSheets[spread].columns[col_index].command.c_str()); + } + + //section_body_2_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0);// + 0x5; + file.seekg(LAYER, ios_base::beg); + file >> size; + + if (!size){ + LAYER += 0x5; + file.seekg(LAYER, ios_base::beg); + file >> size; + } + + if(size && size != sectionSize){ + LAYER += size + 0x6; + file.seekg(LAYER, ios_base::beg); + file >> size; + } + } + + file.seekg(1, ios_base::cur); + file >> size; + LAYER += 0x5; + sectionSize = size; + + LOG_PRINT(logfile, " POS (@ 0x%X)\n", (unsigned int)file.tellg()); + + while(!file.eof()){ + LAYER += 0x5; + file.seekg(LAYER + 0x4, ios_base::beg); + + short index; + file >> index; + LOG_PRINT(logfile, " Index: %d (@ 0x%X)\n", index, (unsigned int)file.tellg()); + if (index < 0) + break; + + file.seekg(LAYER + 0x12, ios_base::beg); + name.resize(12); + file >> name; + LOG_PRINT(logfile, " Column: %s (@ 0x%X)\n", name.c_str(), (LAYER + 0x12)); + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> c; + + short width = 0; + file.seekg(LAYER + 0x4A, ios_base::beg); + file >> width; + + int col_index = findColumnByIndexAndName(spread, index, 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; + } + speadSheets[spread].columns[col_index].type = type; + + width/=0xA; + if(width == 0) + width = 8; + speadSheets[spread].columns[col_index].width = width; + + unsigned char c1,c2; + file.seekg(LAYER + 0x1E, ios_base::beg); + file >> c1; + file >> c2; + + switch(c1){ + case 0x00: // Numeric - Dec1000 + case 0x09: // Text&Numeric - Dec1000 + case 0x10: // Numeric - Scientific + case 0x19: // Text&Numeric - Scientific + case 0x20: // Numeric - Engeneering + case 0x29: // Text&Numeric - Engeneering + case 0x30: // Numeric - Dec1,000 + case 0x39: // Text&Numeric - Dec1,000 + speadSheets[spread].columns[col_index].valueType = (c1%0x10 == 0x9) ? TextNumeric : Numeric; + speadSheets[spread].columns[col_index].valueTypeSpecification = c1 / 0x10; + if(c2 >= 0x80){ + speadSheets[spread].columns[col_index].significantDigits = c2 - 0x80; + speadSheets[spread].columns[col_index].numericDisplayType = SignificantDigits; + } else if(c2 > 0) { + speadSheets[spread].columns[col_index].decimalPlaces = c2 - 0x03; + speadSheets[spread].columns[col_index].numericDisplayType = DecimalPlaces; + } + break; + case 0x02: // Time + speadSheets[spread].columns[col_index].valueType = Time; + speadSheets[spread].columns[col_index].valueTypeSpecification = c2 - 0x80; + break; + case 0x03: // Date + speadSheets[spread].columns[col_index].valueType = Date; + speadSheets[spread].columns[col_index].valueTypeSpecification= c2 - 0x80; + break; + case 0x31: // Text + speadSheets[spread].columns[col_index].valueType = Text; + break; + case 0x4: // Month + case 0x34: + speadSheets[spread].columns[col_index].valueType = Month; + speadSheets[spread].columns[col_index].valueTypeSpecification = c2; + break; + case 0x5: // Day + case 0x35: + speadSheets[spread].columns[col_index].valueType = Day; + speadSheets[spread].columns[col_index].valueTypeSpecification = c2; + break; + default: // Text + speadSheets[spread].columns[col_index].valueType = Text; + break; + } + } + LAYER += sectionSize + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x5; + if(size > 0){ + if(col_index != -1){ + file.seekg(LAYER, ios_base::beg); + file >> speadSheets[spread].columns[col_index].comment.assign(size, 0); + + string comment = speadSheets[spread].columns[col_index].comment; + string::size_type pos = comment.find_first_of("@"); + if (pos != string::npos){ + comment.resize(pos); + speadSheets[spread].columns[col_index].comment = comment; + } + + LOG_PRINT(logfile, " comment: %s (@ 0x%X)\n", comment.c_str(), LAYER); + } + LAYER += size + 0x1; + } + + if (sheets == 1 && col_index != -1) + header.push_back(speadSheets[spread].columns[col_index]); + + file.seekg(LAYER, ios_base::beg); + file >> size; + if(size != sectionSize) + break; + } + + file.seekg(0x6, ios_base::cur); + LAYER += 0x6; + + skipObjectInfo();//go to layer end position + + if (sheets > 1){ + file.seekg(-5, ios_base::cur); + LAYER = file.tellg(); + file >> size; + if(!size){ + file.seekg(1, ios_base::cur); + break; + } + } + } + + for (unsigned int i = 0; i < header.size(); i++) + speadSheets[spread].columns[i] = header[i]; + + LOG_PRINT(logfile, " Done with spreadsheet %d POS (@ 0x%X)\n", spread, (unsigned int)file.tellg()); +} + +void Origin800Parser::readMatrixInfo() +{ + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + + POS += 5; + + LOG_PRINT(logfile, " [Matrix SECTION (@ 0x%X)]\n", POS); + + string name(25, 0); + file.seekg(POS + 0x2, ios_base::beg); + file >> name; + + int idx = findMatrixByName(name); + matrices[idx].name = name; + file.seekg(POS, ios_base::beg); + readWindowProperties(matrices[idx], size); + + unsigned int LAYER = POS; + LAYER += size + 0x1; + + unsigned char h; + file.seekg(POS + 0x29, ios_base::beg); + file >> h; + matrices[idx].activeSheet = h; + LOG_PRINT(logfile, " Active sheet: %d (@ 0x%X)\n", matrices[idx].activeSheet, (POS + 0x29)); + + file.seekg(POS + 0x87, ios_base::beg); + file >> h; + LOG_PRINT(logfile, " Header: %d (@ 0x%X)\n", h, (POS + 0x87)); + matrices[idx].header = (h == 194) ? Matrix::XY : Matrix::ColumnRow; + + int sheets = matrices[idx].sheets.size(); + LOG_PRINT(logfile, " Sheets: %d\n", sheets); + for (int i = 0; i < sheets; i++){ + MatrixSheet sheet = matrices[idx].sheets[i]; + LOG_PRINT(logfile, " Parsing sheet %d ...\n", i + 1); + + file.seekg(LAYER, ios_base::beg); + file >> size; + + // LAYER section + LAYER += 0x5; + + unsigned short width = 8; + file.seekg(LAYER + 0x27, ios_base::beg); + file >> width; + if (width == 0) + width = 8; + sheet.width = width; + LOG_PRINT(logfile, " Width: %d (@ 0x%X)\n", sheet.width, (LAYER + 0x27)); + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> sheet.columnCount; + LOG_PRINT(logfile, " Columns: %d (@ 0x%X)\n", sheet.columnCount, (LAYER + 0x2B)); + + file.seekg(LAYER + 0x52, ios_base::beg); + file >> sheet.rowCount; + LOG_PRINT(logfile, " Rows: %d (@ 0x%X)\n", sheet.rowCount, (LAYER + 0x52)); + + file.seekg(LAYER + 0x71, ios_base::beg); + unsigned char view; + file >> view; + if (view != 0x32 && view != 0x28){ + sheet.view = MatrixSheet::ImageView; + LOG_PRINT(logfile, " View: Image (%d @ 0x%X)\n", view, (LAYER + 0x71)); + } else + LOG_PRINT(logfile, " View: Data (%d @ 0x%X)\n", view, (LAYER + 0x71)); + + for (int j = 0; j < 4; j++) + skipLine(); + file.seekg(9, ios_base::cur); + file >> sheet.name.assign(32, 0); + LOG_PRINT(logfile, " Name: %s (@ 0x%X)\n", sheet.name.c_str(), (unsigned int)file.tellg() - 32); + + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + unsigned int sectionSize = size; + while(!file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + string sec_name(41, 0); + file.seekg(LAYER + 0x46, ios_base::beg); + file >> sec_name; + + //section_body_1_size + LAYER += sectionSize + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_1 + LAYER += 0x5; + if (sec_name == "1"){//check if it is a formula + file.seekg(LAYER, ios_base::beg); + file >> sheet.command.assign(size, 0); + LOG_PRINT(logfile, " Formula: %s @ 0x%X\n", sheet.command.c_str(), (unsigned int)file.tellg()); + } else if (sec_name == "Y2"){ + string s(size, 0); + file >> s; + sheet.coordinates[0] = stringToDouble(s); + LOG_PRINT(logfile, " Y2: %g\n", sheet.coordinates[0]); + } else if (sec_name == "X2"){ + string s(size, 0); + file >> s; + sheet.coordinates[1] = stringToDouble(s); + LOG_PRINT(logfile, " X2: %g\n", sheet.coordinates[1]); + } else if (sec_name == "Y1"){ + string s(size, 0); + file >> s; + sheet.coordinates[2] = stringToDouble(s); + LOG_PRINT(logfile, " Y1: %g\n", sheet.coordinates[2]); + } else if (sec_name == "X1"){ + string s(size, 0); + file >> s; + sheet.coordinates[3] = stringToDouble(s); + LOG_PRINT(logfile, " X1: %g\n", sheet.coordinates[3]); + } + + //section_body_2_size + LAYER += size + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + if(sec_name == "COLORMAP"){ + file.seekg(LAYER + 0x14, ios_base::beg); + readColorMap(sheet.colorMap); + } + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0) + 0x5; + + if(sec_name == "__LayerInfoStorage") + break; + + } + LAYER += 0x5; + file.seekg(LAYER, ios_base::beg); + file >> size; + sectionSize = size; + + while(!file.eof()){ + LAYER += 0x5; + + unsigned char c1,c2; + file.seekg(LAYER + 0x1E, ios_base::beg); + file >> c1; + file >> c2; + + 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; + } + + LAYER += sectionSize + 0x1; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += size + (size > 0 ? 0x1 : 0) + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size != sectionSize) + break; + } + + file.seekg(1, ios_base::cur); + skipObjectInfo(); + + file.seekg(-5, ios_base::cur); + POS = file.tellg(); + LAYER = POS; + + matrices[idx].sheets[i] = sheet; + } + + file.seekg(5, ios_base::cur); + LOG_PRINT(logfile, " Done with matrix %s (@ 0x%X)\n", name.c_str(), (unsigned int)file.tellg()); +} + +OriginParser* createOrigin800Parser(const string& fileName) +{ + return new Origin800Parser(fileName); +} + +unsigned int Origin800Parser::findStringPos(const string& name) +{ + char c = 0; + unsigned int startPos = file.tellg(); + unsigned int pos = startPos; + while(!file.eof()){ + file >> c; + + if (c == name[0]){ + pos = file.tellg(); + + file.seekg(pos - 0x3, ios_base::beg); + file >> c; + + file.seekg(pos - 0x1, ios_base::beg); + string s = string(name.size(), 0); + file >> s; + + char end; + file >> end; + + if (!c && !end && name == s){ + pos -= 0x1; + file.seekg(startPos, ios_base::beg); + //LOG_PRINT(logfile, "Found string: %s (@ 0x%X)\n", name, pos); + return pos; + } + } + pos++; + } + return pos; +} diff --git a/3rdparty/liborigin2/Origin800Parser.h b/3rdparty/liborigin2/Origin800Parser.h new file mode 100644 index 000000000..7c924ff74 --- /dev/null +++ b/3rdparty/liborigin2/Origin800Parser.h @@ -0,0 +1,51 @@ +/*************************************************************************** + File : Origin800Parser.h + -------------------------------------------------------------------- + Copyright : (C) 2010 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 8.0 file parser 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_800_PARSER_H +#define ORIGIN_800_PARSER_H + +#include "Origin750Parser.h" + +class Origin800Parser : public Origin750Parser +{ +public: + Origin800Parser(const string& fileName); + bool parse(); + +protected: + void readSpreadInfo(); + void readMatrixInfo(); + void readResultsLog(); + virtual void readNotes(); + + unsigned int findStringPos(const string& name); + + string notes_pos_mark; +}; + +#endif // ORIGIN_800_PARSER_H diff --git a/3rdparty/liborigin2/Origin810Parser.cpp b/3rdparty/liborigin2/Origin810Parser.cpp new file mode 100644 index 000000000..f24bb4792 --- /dev/null +++ b/3rdparty/liborigin2/Origin810Parser.cpp @@ -0,0 +1,160 @@ +/*************************************************************************** + File : Origin810Parser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2010 - 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 8.1 file parser class (uses code from file + Origin750Parser.cpp written by Alex Kargovsky) + ***************************************************************************/ + +/*************************************************************************** + * * + * 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 "Origin810Parser.h" +#include + +Origin810Parser::Origin810Parser(const string& fileName) + : Origin800Parser(fileName) +{ + d_colormap_offset = 0x25F; + notes_pos_mark = "P"; +} + +void Origin810Parser::readProjectTreeFolder(tree::iterator parent) +{ + unsigned int POS = file.tellg(); + + double creationDate, modificationDate; + POS += 5; + + file.seekg(POS + 0x02, ios_base::beg); + unsigned char a; + file >> a; + bool activeFolder = (a == 1); + + file.seekg(POS + 0x10, ios_base::beg); + file >> creationDate; + if (creationDate >= 1e10) + return; + + file >> modificationDate; + if (modificationDate >= 1e10) + return; + + POS += 0x20 + 1 + 5; + unsigned int size; + file.seekg(POS, ios_base::beg); + file >> size; + + POS += 5; + + // read folder name + string name(size, 0); + file.seekg(POS, ios_base::beg); + file >> name; + + tree::iterator current_folder = projectTree.append_child(parent, ProjectNode(name, ProjectNode::Folder, doubleToPosixTime(creationDate), doubleToPosixTime(modificationDate), activeFolder)); + + file.seekg(1, ios_base::cur); + for (int i = 0; i < 6; i++) + skipLine(); + + POS = file.tellg(); + + unsigned int objectcount; + file >> objectcount; + + windowsCount += objectcount; + + POS += 5 + 5; + + for (unsigned int i = 0; i < objectcount; ++i){ + POS += 5; + char c; + file.seekg(POS + 0x2, ios_base::beg); + file >> c; + + unsigned int objectID; + file.seekg(POS + 0x4, ios_base::beg); + file >> objectID; + + if(c == 0x10){ + projectTree.append_child(current_folder, ProjectNode(notes[objectID].name, ProjectNode::Note)); + } else { + pair object = findObjectByIndex(objectID); + projectTree.append_child(current_folder, ProjectNode(object.second, object.first)); + } + + POS += 8 + 1 + 5 + 5; + } + + file.seekg(POS, ios_base::beg); + file >> objectcount; + + file.seekg(1, ios_base::cur); + for(unsigned int i = 0; i < objectcount; ++i) + readProjectTreeFolder(current_folder); +} + +void Origin810Parser::readColorMap(ColorMap& colorMap) +{ + unsigned int colorMapSize; + file >> colorMapSize; + + file.seekg(0x140, ios_base::cur); + for(unsigned int i = 0; i < colorMapSize + 3; ++i){ + ColorMapLevel level; + file >> level.fillPattern; + + file.seekg(0x03, ios_base::cur); + file >> level.fillPatternColor; + + short w; + file >> w; + level.fillPatternLineWidth = (double)w/500.0; + + file.seekg(0x06, ios_base::cur); + file >> level.lineStyle; + + file.seekg(0x01, ios_base::cur); + file >> w; + level.lineWidth = (double)w/500.0; + file >> level.lineColor; + + file.seekg(0x02, ios_base::cur); + unsigned char h; + file >> h; + level.labelVisible = (h & 0x1); + level.lineVisible = !(h & 0x2); + + file.seekg(0x0D, ios_base::cur); + file >> level.fillColor; + + file.seekg(0x04, ios_base::cur); + double value; + file >> value; + + colorMap.levels.push_back(make_pair(value, level)); + } +} + +OriginParser* createOrigin810Parser(const string& fileName) +{ + return new Origin810Parser(fileName); +} diff --git a/3rdparty/liborigin2/Origin810Parser.h b/3rdparty/liborigin2/Origin810Parser.h new file mode 100644 index 000000000..797265bda --- /dev/null +++ b/3rdparty/liborigin2/Origin810Parser.h @@ -0,0 +1,44 @@ +/*************************************************************************** + File : Origin810Parser.h + -------------------------------------------------------------------- + Copyright : (C) 2010 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 8.1 file parser 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_810_PARSER_H +#define ORIGIN_810_PARSER_H + +#include "Origin800Parser.h" + +class Origin810Parser : public Origin800Parser +{ +public: + Origin810Parser(const string& fileName); + +protected: + void readProjectTreeFolder(tree::iterator parent); + void readColorMap(ColorMap& colorMap); +}; + +#endif // ORIGIN_810_PARSER_H diff --git a/3rdparty/liborigin2/Origin850Parser.cpp b/3rdparty/liborigin2/Origin850Parser.cpp new file mode 100644 index 000000000..60f37817c --- /dev/null +++ b/3rdparty/liborigin2/Origin850Parser.cpp @@ -0,0 +1,1075 @@ +/*************************************************************************** + File : Origin850Parser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 8.5 file parser 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 "Origin850Parser.h" + +Origin850Parser::Origin850Parser(const string& fileName) +: Origin810Parser(fileName) +{ +} + +OriginParser* createOrigin850Parser(const string& fileName) +{ + return new Origin850Parser(fileName); +} + +bool Origin850Parser::readGraphInfo() +{ + unsigned int POS = file.tellg(); + + unsigned int size; + file >> size; + POS += 5; + + string name(25, 0); + file.seekg(POS + 0x02, ios_base::beg); + file >> name; + LOG_PRINT(logfile, " GRAPH name: %s @ 0x%X\n", name.c_str(), (unsigned int)file.tellg()); + + graphs.push_back(Graph(name)); + file.seekg(POS, ios_base::beg); + readWindowProperties(graphs.back(), size); + + file.seekg(POS + 0x23, ios_base::beg); + file >> graphs.back().width; + file >> graphs.back().height; + + file.seekg(POS + 0x38, ios_base::beg); + unsigned char c; + file >> c; + graphs.back().connectMissingData = (c & 0x40); + + file.seekg(POS + 0x45, ios_base::beg); + string templateName(20, 0); + file >> templateName; + graphs.back().templateName = templateName; + LOG_PRINT(logfile, " TEMPLATE: %s pos: 0x%X\n", templateName.c_str(), (POS + 0x45)); + if (templateName == "LAYOUT") + graphs.back().isLayout = true; + + unsigned int LAYER = POS; + LAYER += size + 0x1; + + while(!file.eof())// multilayer loop + { + graphs.back().layers.push_back(GraphLayer()); + GraphLayer& layer(graphs.back().layers.back()); + // LAYER section + file.seekg(LAYER, ios_base::beg); + file >> size; + + LAYER += 0x05; + + file.seekg(LAYER + 0x0F, ios_base::beg); + file >> layer.xAxis.min; + file >> layer.xAxis.max; + file >> layer.xAxis.step; + + file.seekg(LAYER + 0x2B, ios_base::beg); + file >> layer.xAxis.majorTicks; + + unsigned char g; + file >> g; file >> g; + layer.xAxis.zeroLine = (g & 0x80); + layer.xAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x37, ios_base::beg); + file >> layer.xAxis.minorTicks; + file >> layer.xAxis.scale; + + file.seekg(LAYER + 0x3A, ios_base::beg); + file >> layer.yAxis.min; + file >> layer.yAxis.max; + file >> layer.yAxis.step; + + file.seekg(LAYER + 0x56, ios_base::beg); + file >> layer.yAxis.majorTicks; + + file >> g; file >> g; + layer.yAxis.zeroLine = (g & 0x80); + layer.yAxis.oppositeLine = (g & 0x40); + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> layer.yAxis.minorTicks; + file >> layer.yAxis.scale; + + file.seekg(LAYER + 0x68, ios_base::beg); + file >> g; + layer.gridOnTop = (g & 0x04); + layer.exchangedAxes = (g & 0x40); + + file.seekg(LAYER + 0x71, ios_base::beg); + file.read(reinterpret_cast(&layer.clientRect), sizeof(Rect)); + + unsigned char border; + file.seekg(LAYER + 0x89, ios_base::beg); + file >> border; + layer.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + + file.seekg(LAYER + 0x105, ios_base::beg); + file >> layer.backgroundColor; + + LAYER += size + 0x1; + //now structure is next : section_header_size=0x6F(4 bytes) + '\n' + section_header(0x6F bytes) + section_body_1_size(4 bytes) + '\n' + section_body_1 + section_body_2_size(maybe=0)(4 bytes) + '\n' + section_body_2 + '\n' + //possible sections: axes, legend, __BC02, _202, _231, _232, __LayerInfoStorage etc + //section name starts with 0x46 position + while(!file.eof()){ + //section_header_size=0x6F(4 bytes) + '\n' + LAYER += 0x5; + + //section_header + + string sec_name(41, 0); + file.seekg(LAYER + 0x46, ios_base::beg); + file >> sec_name; + + unsigned int sectionNamePos = LAYER + 0x46; + LOG_PRINT(logfile, " SECTION NAME: %s (@ 0x%X)\n", sec_name.c_str(), (LAYER + 0x46)); + + Rect r; + file.seekg(LAYER + 0x03, ios_base::beg); + file.read(reinterpret_cast(&r), sizeof(Rect)); + + unsigned char attach; + file.seekg(LAYER + 0x28, ios_base::beg); + file >> attach; + + unsigned char border; + file >> border; + + Color color; + file.seekg(LAYER + 0x33, ios_base::beg); + file >> color; + + //section_body_1_size + LAYER += 0x6F + 0x1; + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_1 + LAYER += 0x5; + unsigned int osize = size; + unsigned int SECTION_BODY1_POS = LAYER; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisPrefixSuffixInfo(sec_name, size, layer); + + file.seekg(LAYER, ios_base::beg); + unsigned char type; + file >> type; + + LineVertex begin, end; + if (size == 120){//Line/Arrow + if (attach == Origin::Scale){ + if (type == 2){ + file.seekg(LAYER + 0x20, ios_base::beg); + file >> begin.x; + file >> end.x; + file.seekg(LAYER + 0x40, ios_base::beg); + file >> begin.y; + file >> end.y; + } else if (type == 4){//curved arrow: start point, 2 middle points and end point + file.seekg(LAYER + 0x20, ios_base::beg); + file >> begin.x; + file >> end.x; + file >> end.x; + file >> end.x; + file >> begin.y; + file >> end.y; + file >> end.y; + file >> end.y; + } + } else { + short x1, x2, y1, y2; + if (type == 2){//straight line/arrow + file >> x1; + file >> x2; + file.seekg(4, ios_base::cur); + file >> y1; + file >> y2; + file.seekg(4, ios_base::cur); + } else if (type == 4){//curved line/arrow has 4 points + file >> x1; + file.seekg(4, ios_base::cur); + file >> x2; + file >> y1; + file.seekg(4, ios_base::cur); + file >> 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(); + } + + file.seekg(LAYER + 0x11, ios_base::beg); + unsigned char arrows; + file >> arrows; + 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; + } + + file.seekg(LAYER + 0x60, ios_base::beg); + file >> begin.shapeType; + + file.seekg(LAYER + 0x64, ios_base::beg); + unsigned int w = 0; + file >> w; + begin.shapeWidth = (double)w/500.0; + + file >> w; + begin.shapeLength = (double)w/500.0; + + file.seekg(LAYER + 0x6C, ios_base::beg); + file >> end.shapeType; + + file.seekg(LAYER + 0x70, ios_base::beg); + file >> w; + end.shapeWidth = (double)w/500.0; + + file >> w; + end.shapeLength = (double)w/500.0; + } + + //text properties + short rotation; + file.seekg(LAYER + 0x02, ios_base::beg); + file >> rotation; + + unsigned char fontSize; + file >> fontSize; + + unsigned char tab; + file.seekg(LAYER + 0x0A, ios_base::beg); + file >> tab; + + //line properties + unsigned char lineStyle = 0; + double width = 0.0; + + file.seekg(LAYER + 0x12, ios_base::beg); + file >> lineStyle; + + unsigned short w1; + file >> w1; + width = (double)w1/500.0; + + Figure figure; + file.seekg(LAYER + 0x05, ios_base::beg); + file >> w1; + figure.width = (double)w1/500.0; + + file.seekg(LAYER + 0x08, ios_base::beg); + file >> figure.style; + + file.seekg(LAYER + 0x42, ios_base::beg); + file >> figure.fillAreaColor; + file >> w1; + figure.fillAreaPatternWidth = (double)w1/500.0; + + file.seekg(LAYER + 0x4A, ios_base::beg); + file >> figure.fillAreaPatternColor; + file >> figure.fillAreaPattern; + + unsigned char h; + file.seekg(LAYER + 0x57, ios_base::beg); + file >> h; + figure.useBorderColor = (h == 0x10); + + //section_body_2_size + LAYER += size + 0x1; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_2 + LAYER += 0x5; + //check if it is a axis or legend + + file.seekg(1, ios_base::cur); + if(sec_name == "XB") + { + string text(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Bottom; + layer.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(size, 0); + file >> text; + + layer.xAxis.position = GraphAxis::Top; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Left; + layer.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(size, 0); + file >> text; + + layer.yAxis.position = GraphAxis::Right; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Front; + layer.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(size, 0); + file >> text; + + layer.zAxis.position = GraphAxis::Back; + layer.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") + { + file >> layer.zAxis.min; + file >> layer.zAxis.max; + file >> layer.zAxis.step; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> layer.zAxis.majorTicks; + + file.seekg(LAYER + 0x28, ios_base::beg); + file >> layer.zAxis.minorTicks; + file >> layer.zAxis.scale; + + file.seekg(LAYER + 0x5A, ios_base::beg); + file >> layer.xAngle; + file >> layer.yAngle; + file >> layer.zAngle; + + file.seekg(LAYER + 0x218, ios_base::beg); + file >> layer.xLength; + file >> layer.yLength; + file >> layer.zLength; + + layer.xLength /= 23.0; + layer.yLength /= 23.0; + layer.zLength /= 23.0; + + file.seekg(LAYER + 0x240, ios_base::beg); + file >> layer.orthographic3D; + } + else if(sec_name == "Legend") + { + string text(size, 0); + file >> text; + + layer.legend = TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach); + } + else if(sec_name == "__BCO2") // histogram + { + file.seekg(LAYER + 0x10, ios_base::beg); + file >> layer.histogramBin; + + file.seekg(LAYER + 0x20, ios_base::beg); + file >> layer.histogramEnd; + file >> layer.histogramBegin; + + unsigned int p = sectionNamePos + 93; + file.seekg(p, ios_base::beg); + + file >> layer.percentile.p1SymbolType; + file >> layer.percentile.p99SymbolType; + file >> layer.percentile.meanSymbolType; + file >> layer.percentile.maxSymbolType; + file >> layer.percentile.minSymbolType; + + file.seekg(p + 65, ios_base::beg); + file >> layer.percentile.labels; + + file.seekg(sectionNamePos + 106, ios_base::beg); + file >> layer.percentile.whiskersRange; + file >> layer.percentile.boxRange; + + file.seekg(sectionNamePos + 141, ios_base::beg); + file >> layer.percentile.whiskersCoeff; + file >> layer.percentile.boxCoeff; + + unsigned char h; + file >> h; + layer.percentile.diamondBox = (h == 0x82) ? true : false; + + p += 109; + file.seekg(p, ios_base::beg); + file >> layer.percentile.symbolSize; + layer.percentile.symbolSize = layer.percentile.symbolSize/2 + 1; + + p += 163; + file.seekg(p, ios_base::beg); + file >> layer.percentile.symbolColor; + file >> layer.percentile.symbolFillColor; + } + else if(sec_name == "_206") // box plot labels + { + file.seekg(sectionNamePos, ios_base::beg); + //LOG_PRINT(logfile, "box plot labels pos @ 0x%X\n", (unsigned int)file.tellg()); + + /*file >> curve.text.fontSize; + + file.seekg(7, ios_base::cur); + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + file.seekg(2, ios_base::cur);*/ + + file.seekg(33, ios_base::cur); + //LOG_PRINT(logfile, "box plot labels color @ 0x%X\n", (unsigned int)file.tellg()); + //file >> curve.text.color; + } + else if(sec_name == "VLine") // Image profiles vertical cursor + { + file.seekg(SECTION_BODY1_POS + 0x0A, ios_base::beg); + double start; + file >> start; + + file.seekg(SECTION_BODY1_POS + 0x1A, ios_base::beg); + double width; + file >> width; + + layer.vLine = start + 0.5*width; + layer.imageProfileTool = 2; + } + else if(sec_name == "HLine") // Image profiles horizontal cursor + { + file.seekg(SECTION_BODY1_POS + 0x12, ios_base::beg); + double start; + file >> start; + + file.seekg(SECTION_BODY1_POS + 0x22, ios_base::beg); + double width; + file >> width; + + layer.hLine = start + 0.5*width; + layer.imageProfileTool = 2; + } + else if(sec_name == "vline") // Image profiles vertical cursor + { + file.seekg(sectionNamePos, ios_base::beg); + for (int i = 0; i < 2; i++) + skipLine(); + + file.seekg(0x20, ios_base::cur); + file >> layer.vLine; + LOG_PRINT(logfile, " vLine: %g\n", layer.vLine); + + layer.imageProfileTool = 1; + } + else if(sec_name == "hline") // Image profiles horizontal cursor + { + file.seekg(sectionNamePos, ios_base::beg); + for (int i = 0; i < 2; i++) + skipLine(); + + file.seekg(0x40, ios_base::cur); + file >> layer.hLine; + LOG_PRINT(logfile, " hLine: %g @ 0x%X\n", layer.hLine, (unsigned int)file.tellg()); + + layer.imageProfileTool = 1; + } + else if(sec_name == "ZCOLORS") + { + layer.isXYY3D = true; + } + else if(sec_name == "SPECTRUM1") + { + layer.isXYY3D = false; + layer.colorScale.visible = true; + + unsigned char h; + file.seekg(24, ios_base::cur); + file >> h; + layer.colorScale.reverseOrder = h; + file.seekg(7, ios_base::cur); + file >> layer.colorScale.colorBarThickness; + file >> layer.colorScale.labelGap; + file.seekg(56, ios_base::cur); + file >> layer.colorScale.labelsColor; + } + else if(sec_name == "&0") + { + layer.isWaterfall = true; + file.seekg(SECTION_BODY1_POS, ios_base::beg); + string text(osize, 0); + file >> text; + size_t commaPos = text.find_first_of(','); + layer.xOffset = atoi(text.substr(0, commaPos).c_str()); + layer.yOffset = atoi(text.substr(commaPos + 1).c_str()); + } + else if ((osize == 0x3E || (osize == 78 && type == 0)) && sec_name != "DelData") // text + { + string text(size, 0); + file >> text; + + sec_name.resize(3); + if (sec_name == "PIE") + layer.pieTexts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + else + layer.texts.push_back(TextBox(text, r, color, fontSize, rotation/10, tab, (BorderType)(border >= 0x80 ? border-0x80 : None), (Attach)attach)); + } + else if (osize == 0x5E) // rectangle & circle + { + switch(type) + { + 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; + + layer.figures.push_back(figure); + } + else if (osize == 0x78 && (type == 2 || type == 4) && sec_name != "sLine" && sec_name != "sline") // line/arrow + { + layer.lines.push_back(Line()); + Line& line(layer.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(osize == 0x28) // bitmap + { + if (type == 4){ + unsigned long filesize = size + 14; + layer.bitmaps.push_back(Bitmap()); + Bitmap& bitmap(layer.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; + file.read(reinterpret_cast(data), size); + } else if (type == 6){ + string gname(30, 0); + file.seekg(sectionNamePos + 93, ios_base::beg); + file >> gname; + layer.bitmaps.push_back(Bitmap(gname)); + Bitmap& bitmap(layer.bitmaps.back()); + bitmap.clientRect = r; + bitmap.attach = (Attach)attach; + bitmap.size = 0; + bitmap.borderType = (BorderType)(border >= 0x80 ? border-0x80 : None); + } + } + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + //section_body_3_size + file.seekg(LAYER, ios_base::beg); + file >> size; + + //section_body_3 + LAYER += 0x5; + + //close section 00 00 00 00 0A + LAYER += size + (size > 0 ? 0x1 : 0); + + if(sec_name == "__LayerInfoStorage") + break; + } + LAYER += 0x5; + unsigned char h; + short w; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size)//check layer is not empty + { + while(!file.eof()){ + LAYER += 0x5; + + layer.curves.push_back(GraphCurve()); + GraphCurve& curve(layer.curves.back()); + + file.seekg(LAYER + 0x26, ios_base::beg); + file >> h; + curve.hidden = (h == 33); + LOG_PRINT(logfile, " hidden curve: %d\n", curve.hidden); + + file.seekg(LAYER + 0x4C, ios_base::beg); + file >> curve.type; + if (curve.type == GraphCurve::XYZContour || curve.type == GraphCurve::Contour) + layer.isXYY3D = false; + + LOG_PRINT(logfile, " graph %d layer %d curve %d type : %d\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), (int)curve.type); + + file.seekg(LAYER + 0x04, ios_base::beg); + file >> w; + pair column = findDataByIndex(w-1); + short nColY = w; + if (column.first.size() > 0){ + curve.dataName = column.first; + if(layer.is3D() || (curve.type == GraphCurve::XYZContour)){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Z : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.zColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } + } + + file.seekg(LAYER + 0x23, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if (column.first.size() > 0){ + curve.xDataName = (curve.dataName != column.first) ? column.first : ""; + + if(layer.is3D() || (curve.type == GraphCurve::XYZContour)){ + LOG_PRINT(logfile, " graph %d layer %d curve %d Y : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.yColumnName = column.second; + } else if (layer.isXYY3D){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } else { + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + } + } + + file.seekg(LAYER + 0x4D, ios_base::beg); + file >> w; + column = findDataByIndex(w-1); + if (column.first.size() > 0 && (layer.is3D() || (curve.type == GraphCurve::XYZContour))){ + LOG_PRINT(logfile, " graph %d layer %d curve %d X : %s.%s\n", graphs.size(), graphs.back().layers.size(), layer.curves.size(), column.first.c_str(), column.second.c_str()); + curve.xColumnName = column.second; + if(curve.dataName != column.first) + LOG_PRINT(logfile, " graph %d X and Y from different tables\n", graphs.size()); + } + + if(layer.is3D() || layer.isXYY3D) + graphs.back().is3D = true; + + file.seekg(LAYER + 0x11, ios_base::beg); + file >> curve.lineConnect; + file >> curve.lineStyle; + + file.seekg(1, ios_base::cur); + file >> curve.boxWidth; + + file >> w; + curve.lineWidth=(double)w/500.0; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> w; + curve.symbolSize=(double)w/500.0; + + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + curve.fillArea = (h==2); + + file.seekg(LAYER + 0x9C, ios_base::beg); + file >> curve.lineTransparency; + + file >> h; + curve.fillAreaWithLineTransparency = !h; + + file.seekg(LAYER + 0x1E, ios_base::beg); + file >> curve.fillAreaType; + + //text + if(curve.type == GraphCurve::TextPlot){ + file.seekg(LAYER + 0x13, ios_base::beg); + file >> curve.text.rotation; + curve.text.rotation /= 10; + file >> curve.text.fontSize; + + file.seekg(LAYER + 0x19, ios_base::beg); + file >> h; + 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; + } + + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + char offset; + file.seekg(LAYER + 0x37, ios_base::beg); + file >> offset; + curve.text.xOffset = offset * 5; + file >> offset; + curve.text.yOffset = offset * 5; + } + + //vector + if(curve.type == GraphCurve::FlowVector || curve.type == GraphCurve::Vector){ + file.seekg(LAYER + 0x56, ios_base::beg); + file >> curve.vector.multiplier; + + file.seekg(LAYER + 0x5E, ios_base::beg); + file >> h; + + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.endXColumnName = column.second; + + file.seekg(LAYER + 0x62, ios_base::beg); + file >> h; + + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.endYColumnName = column.second; + + file.seekg(LAYER + 0x18, ios_base::beg); + file >> h; + + 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; + + file >> h; + + if(h >= 0x64 && h < 0x1F4){ + column = findDataByIndex(nColY - 1 + h - 0x64); + if(column.first.size() > 0) + curve.vector.magnitudeColumnName = column.second; + } else + curve.vector.constMagnitude = (int)curve.symbolSize; + + file.seekg(LAYER + 0x66, ios_base::beg); + file >> curve.vector.arrowLenght; + file >> curve.vector.arrowAngle; + + file >> h; + curve.vector.arrowClosed = !(h & 0x1); + + file >> w; + curve.vector.width=(double)w/500.0; + + file.seekg(LAYER + 0x142, ios_base::beg); + file >> h; + 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){ + file.seekg(LAYER + 0x92, ios_base::beg); + file >> h; + + 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); + + file >> curve.pie.formatAutomatic; + file >> curve.pie.distance; + file >> curve.pie.viewAngle; + + file.seekg(LAYER + 0x98, ios_base::beg); + file >> curve.pie.thickness; + + file.seekg(LAYER + 0x9A, ios_base::beg); + file >> curve.pie.rotation; + + file.seekg(LAYER + 0x9E, ios_base::beg); + file >> curve.pie.displacement; + + file.seekg(LAYER + 0xA0, ios_base::beg); + file >> curve.pie.radius; + file >> curve.pie.horizontalOffset; + + file.seekg(LAYER + 0xA6, ios_base::beg); + file >> curve.pie.displacedSectionCount; + } + //surface + if (layer.isXYY3D || curve.type == GraphCurve::Mesh3D){ + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.surface.type; + file.seekg(LAYER + 0x1C, ios_base::beg); + file >> h; + 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); + file >> curve.surface.frontColor; + + file.seekg(LAYER + 0x14C, ios_base::beg); + file >> w; + curve.surface.gridLineWidth = (double)w/500.0; + file >> curve.surface.gridColor; + + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + curve.surface.backColorEnabled = (h & 0x08); + file.seekg(LAYER + 0x15A, ios_base::beg); + file >> curve.surface.backColor; + file >> curve.surface.xSideWallColor; + file >> curve.surface.ySideWallColor; + + curve.surface.surface.fill = (h & 0x10); + curve.surface.surface.contour = (h & 0x40); + file.seekg(LAYER + 0x94, ios_base::beg); + file >> w; + curve.surface.surface.lineWidth = (double)w/500.0; + file >> curve.surface.surface.lineColor; + + curve.surface.topContour.fill = (h & 0x02); + curve.surface.topContour.contour = (h & 0x04); + file.seekg(LAYER + 0xB4, ios_base::beg); + file >> w; + curve.surface.topContour.lineWidth = (double)w/500.0; + file >> curve.surface.topContour.lineColor; + + curve.surface.bottomContour.fill = (h & 0x80); + curve.surface.bottomContour.contour = (h & 0x01); + file.seekg(LAYER + 0xA4, ios_base::beg); + file >> w; + curve.surface.bottomContour.lineWidth = (double)w/500.0; + file >> curve.surface.bottomContour.lineColor; + } + + if (curve.type == GraphCurve::Mesh3D || curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour){ + if (curve.type == GraphCurve::Contour || curve.type == GraphCurve::XYZContour) + layer.isXYY3D = false; + + ColorMap& colorMap = (curve.type == GraphCurve::Mesh3D ? curve.surface.colorMap : curve.colorMap); + file.seekg(LAYER + 0x13, ios_base::beg); + file >> h; + colorMap.fillEnabled = (h & 0x82); + + if (curve.type == GraphCurve::Contour){ + file.seekg(102, ios_base::cur); + file >> curve.text.fontSize; + + file.seekg(7, ios_base::cur); + file >> h; + curve.text.fontUnderline = (h & 0x1); + curve.text.fontItalic = (h & 0x2); + curve.text.fontBold = (h & 0x8); + curve.text.whiteOut = (h & 0x20); + + file.seekg(2, ios_base::cur); + file >> curve.text.color; + } + + file.seekg(LAYER + d_colormap_offset, ios_base::beg); + readColorMap(colorMap); + } + + file.seekg(LAYER + 0xC2, ios_base::beg); + file >> curve.fillAreaColor; + + file >> w; + curve.fillAreaPatternWidth=(double)w/500.0; + + file.seekg(LAYER + 0xCA, ios_base::beg); + file >> curve.fillAreaPatternColor; + file >> curve.fillAreaPattern; + file >> curve.fillAreaPatternBorderStyle; + file >> w; + curve.fillAreaPatternBorderWidth=(double)w/500.0; + file >> curve.fillAreaPatternBorderColor; + + file.seekg(LAYER + 0x11E, ios_base::beg); + file >> curve.fillAreaTransparency; + + file.seekg(LAYER + 0x16A, ios_base::beg); + file >> curve.lineColor; + + if (curve.type != GraphCurve::Contour) + curve.text.color = curve.lineColor; + + file.seekg(LAYER + 0x17, ios_base::beg); + file >> curve.symbolType; + + file.seekg(LAYER + 0x12E, ios_base::beg); + file >> curve.symbolFillColor; + + file >> curve.symbolColor; + curve.vector.color = curve.symbolColor; + + file >> h; + curve.symbolThickness = (h == 255 ? 1 : h); + file >> curve.pointOffset; + file >> h; + file >> curve.symbolFillTransparency; + + file.seekg(LAYER + 0x143, ios_base::beg); + file >> h; + curve.connectSymbols = (h&0x8); + + LAYER += size + 0x1; + + unsigned int newSize; + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + LAYER += newSize + (newSize > 0 ? 0x1 : 0) + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> newSize; + + if(newSize != size) + break; + } + } + + LAYER += 0x5; + //read axis breaks + while(!file.eof()){ + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0x2D){ + LAYER += 0x5; + file.seekg(LAYER + 2, ios_base::beg); + file >> h; + + if (h == 2) { + layer.xAxisBreak.minorTicksBefore = layer.xAxis.minorTicks; + layer.xAxisBreak.scaleIncrementBefore = layer.xAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.xAxisBreak); + } else if(h == 4){ + layer.yAxisBreak.minorTicksBefore = layer.yAxis.minorTicks; + layer.yAxisBreak.scaleIncrementBefore = layer.yAxis.step; + file.seekg(LAYER, ios_base::beg); + readGraphAxisBreakInfo(layer.yAxisBreak); + } + LAYER += 0x2D + 0x1; + } + else + break; + } + LAYER += 0x5; + + file.seekg(LAYER, ios_base::beg); + size = readGraphAxisInfo(layer.xAxis); + LAYER += size*0x6 + 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.yAxis); + LAYER += size*0x6 + 0x5; + + file.seekg(LAYER, ios_base::beg); + readGraphAxisInfo(layer.zAxis); + LAYER += size*0x6 + 0x5; + + file.seekg(LAYER, ios_base::beg); + file >> size; + + if(size == 0) + break; + } + + file.seekg(LAYER + 0x5, ios_base::beg); + return true; +} diff --git a/3rdparty/liborigin2/Origin850Parser.h b/3rdparty/liborigin2/Origin850Parser.h new file mode 100644 index 000000000..bd7113ef1 --- /dev/null +++ b/3rdparty/liborigin2/Origin850Parser.h @@ -0,0 +1,43 @@ +/*************************************************************************** + File : Origin850Parser.h + -------------------------------------------------------------------- + Copyright : (C) 2011 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Origin 8.5 file parser 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_850_PARSER_H +#define ORIGIN_850_PARSER_H + +#include "Origin810Parser.h" + +class Origin850Parser : public Origin810Parser +{ +public: + Origin850Parser(const string& fileName); + +protected: + bool readGraphInfo(); +}; + +#endif // ORIGIN_850_PARSER_H diff --git a/3rdparty/liborigin2/OriginDefaultParser.cpp b/3rdparty/liborigin2/OriginDefaultParser.cpp new file mode 100644 index 000000000..12937cf12 --- /dev/null +++ b/3rdparty/liborigin2/OriginDefaultParser.cpp @@ -0,0 +1,471 @@ +/*************************************************************************** + File : OriginDefaultParser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2005-2008 Stefan Gerlach + (C) 2007-2008 Alex Kargovsky, Ion Vasilief + Email (use @ for *) : kargovsky*yumr.phys.msu.su, ion_vasilief*yahoo.fr + Description : Default Origin file parser 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 "OriginDefaultParser.h" +#include +#include +#include +#include +#include + +using namespace Origin; + +#define MAX_LEVEL 20 +#define ERROR_MSG "Please send the OPJ file and the opjfile.log to the author of liborigin!\n" + +#define SwapBytes(x) ByteSwap((unsigned char *) &x,sizeof(x)) + +void ByteSwap(unsigned char * b, int n) { + register int i = 0; + register int j = n-1; + while (i410) + for(i=0;i<5;i++) // skip "0" + fread(&c,1,1,f); + + int col_found; + fread(&col_found,4,1,f); + if(IsBigEndian()) SwapBytes(col_found); + + fread(&c,1,1,f); // skip '\n' + fprintf(debug," [column found = %d/0x%X @ 0x%X]\n",col_found,col_found,(unsigned int) ftell(f)); + + int current_col=1, nr=0, nbytes=0; + double a; + char name[25], valuesize; + while(col_found > 0 && col_found < 0x84) { // should be 0x72, 0x73 or 0x83 + //////////////////////////////// COLUMN HEADER ///////////////////////////////////////////// + fprintf(debug,"COLUMN HEADER :\n"); + for(i=0;i < 0x3D;i++) { // skip 0x3C chars to value size + fread(&c,1,1,f); + fprintf(debug,"%.2X ",c); + if(!((i+1)%16)) fprintf(debug,"\n"); + } + fprintf(debug,"\n"); + + fread(&valuesize,1,1,f); + fprintf(debug," [valuesize = %d @ 0x%X]\n",valuesize,(unsigned int) ftell(f)-1); + if(valuesize <= 0) { + fprintf(debug," WARNING : found strange valuesize of %d\n",valuesize); + valuesize=10; + } + + fprintf(debug,"SKIP :\n"); + for(i=0;i<0x1A;i++) { // skip to name + fread(&c,1,1,f); + fprintf(debug,"%.2X ",c); + if(!((i+1)%16)) fprintf(debug,"\n"); + } + fprintf(debug,"\n"); + + // read name + fprintf(debug," [Spreadsheet @ 0x%X]\n",(unsigned int) ftell(f)); + fflush(debug); + fread(&name,25,1,f); + char sname[26]; + sprintf(sname,"%s",strtok(name,"_")); // spreadsheet name + char* cname = strtok(NULL,"_"); // column name + while(char* tmpstr = strtok(NULL,"_")) { // get multiple-"_" title correct + strcat(sname,"_"); + strcat(sname,cname); + strcpy(cname,tmpstr); + } + int spread=0; + if(speadSheets.size() == 0 || findSpreadByName(sname) == -1) { + fprintf(debug,"NEW SPREADSHEET\n"); + current_col=1; + speadSheets.push_back(SpreadSheet(sname)); + spread=speadSheets.size()-1; + speadSheets.back().maxRows=0; + } + else { + + spread = findSpreadByName(sname); + + current_col=speadSheets[spread].columns.size(); + + if(!current_col) + current_col=1; + current_col++; + } + fprintf(debug,"SPREADSHEET = %s COLUMN %d NAME = %s (@0x%X)\n", + sname, current_col, cname, (unsigned int) ftell(f)); + fflush(debug); + + if(cname == 0) { + fprintf(debug,"NO COLUMN NAME FOUND! Must be a Matrix or Function.\n"); + ////////////////////////////// READ matrixes or functions //////////////////////////////////// + fprintf(debug,"Reading MATRIX.\n"); + fflush(debug); + + fprintf(debug," [position @ 0x%X]\n",(unsigned int) ftell(f)); + // TODO + fprintf(debug," SIGNATURE : "); + for(i=0;i<2;i++) { // skip header + fread(&c,1,1,f); + fprintf(debug,"%.2X ",c); + } + fflush(debug); + + do{ // skip until '\n' + fread(&c,1,1,f); + } while (c != '\n'); + fprintf(debug,"\n"); + fflush(debug); + + // read size + int size; + fread(&size,4,1,f); + fread(&c,1,1,f); // skip '\n' + // TODO : use entry size : double, float, ... + size /= 8; + fprintf(debug," SIZE = %d\n",size); + fflush(debug); + + // catch exception + if(size>10000) + size=1000; + + fprintf(debug,"VALUES :\n"); + speadSheets[speadSheets.size()-1].maxRows=1; + + double value=0; + for(i=0;i0) + fprintf(debug,"WARNING: data section could not be read correct\n"); + nr = nbytes / valuesize; + fprintf(debug," [number of rows = %d (%d Bytes) @ 0x%X]\n",nr,nbytes,(unsigned int) ftell(f)); + fflush(debug); + + speadSheets[spread].maxRows 16) { // skip 0 0 + fread(&c,1,1,f); + fread(&c,1,1,f); + } + fread(&col_found,4,1,f); + if(IsBigEndian()) SwapBytes(col_found); + fread(&c,1,1,f); // skip '\n' + fprintf(debug," [column found = %d/0x%X (@ 0x%X)]\n",col_found,col_found,(unsigned int) ftell(f)-5); + fflush(debug); + } + + ////////////////////// HEADER SECTION ////////////////////////////////////// + // TODO : use new method ('\n') + + int POS = ftell(f)-11; + fprintf(debug,"\nHEADER SECTION\n"); + fprintf(debug," nr_spreads = %d\n",speadSheets.size()); + fprintf(debug," [position @ 0x%X]\n",POS); + fflush(debug); + + ///////////////////// speadSheets INFOS //////////////////////////////////// + int LAYER=0; + int COL_JUMP = 0x1ED; + for(unsigned int i=0; i < speadSheets.size(); i++) { + fprintf(debug," reading Spreadsheet %d/%d properties\n", i+1, speadSheets.size()); + fflush(debug); + if(i > 0) { + if (version == 700 ) + POS += 0x2530 + speadSheets[i-1].columns.size()*COL_JUMP; + else if (version == 610 ) + POS += 0x25A4 + speadSheets[i-1].columns.size()*COL_JUMP; + else if (version == 604 ) + POS += 0x25A0 + speadSheets[i-1].columns.size()*COL_JUMP; + else if (version == 601 ) + POS += 0x2560 + speadSheets[i-1].columns.size()*COL_JUMP; // ? + else if (version == 600 ) + POS += 0x2560 + speadSheets[i-1].columns.size()*COL_JUMP; + else if (version == 500 ) + POS += 0x92C + speadSheets[i-1].columns.size()*COL_JUMP; + else if (version == 410 ) + POS += 0x7FB + speadSheets[i-1].columns.size()*COL_JUMP; + } + + fprintf(debug," reading Header\n"); + fflush(debug); + // HEADER + // check header + int ORIGIN = 0x55; + if(version == 500) + ORIGIN = 0x58; + fseek(f,POS + ORIGIN,SEEK_SET); // check for 'O'RIGIN + char c; + fread(&c,1,1,f); + int jump=0; + if( c == 'O') + fprintf(debug," \"ORIGIN\" found ! (@ 0x%X)\n",POS+ORIGIN); + while( c != 'O' && jump < MAX_LEVEL) { // no inf loop + fprintf(debug," TRY %d \"O\"RIGIN not found ! : %c (@ 0x%X)",jump+1,c,POS+ORIGIN); + fprintf(debug," POS=0x%X | ORIGIN = 0x%X\n",POS,ORIGIN); + fflush(debug); + POS+=0x1F2; + fseek(f,POS + ORIGIN,SEEK_SET); + fread(&c,1,1,f); + jump++; + } + + int spread=i; + if(jump == MAX_LEVEL){ + fprintf(debug," Spreadsheet SECTION not found ! (@ 0x%X)\n",POS-10*0x1F2+0x55); + return -5; + } + + fprintf(debug," [Spreadsheet SECTION (@ 0x%X)]\n",POS); + fflush(debug); + + // check spreadsheet name + fseek(f,POS + 0x12,SEEK_SET); + fread(&name,25,1,f); + + spread=findSpreadByName(name); + if(spread == -1) + spread=i; + + fprintf(debug," SPREADSHEET %d NAME : %s (@ 0x%X) has %d columns\n", + spread+1,name,POS + 0x12,speadSheets[spread].columns.size()); + fflush(debug); + + int ATYPE=0; + LAYER = POS; + if (version == 700) + ATYPE = 0x2E4; + else if (version == 610) + ATYPE = 0x358; + else if (version == 604) + ATYPE = 0x354; + else if (version == 601) + ATYPE = 0x500; // ? + else if (version == 600) + ATYPE = 0x314; + else if (version == 500) { + COL_JUMP=0x5D; + ATYPE = 0x300; + } + else if (version == 410) { + COL_JUMP = 0x58; + ATYPE = 0x229; + } + fflush(debug); + + /////////////// COLUMN Types /////////////////////////////////////////// + fprintf(debug," Spreadsheet has %d columns\n",speadSheets[spread].columns.size()); + for (unsigned int j=0; j +#include +#include + +using namespace boost; + +OriginFile::OriginFile(const string& fileName) +: fileVersion(0) +{ + ifstream file(fileName.c_str(), ios_base::binary); + if(!file.is_open()) + { + cerr << "Could not open " << fileName << "!" << endl; + return; + } + +#ifndef NO_LOG_FILE + FILE *logfile = NULL; + logfile = fopen("./opjfile.log", "w"); + if (logfile == NULL){ + cerr << "Could not open opjfile.log !" << endl; + return; + } +#endif + + unsigned char majVers; + file.seekg(0x5, ios_base::beg); + file >> majVers; + int majVersion = lexical_cast(majVers); + + string vers(4, 0); + file.seekg(0x7, ios_base::beg); + file >> vers; + fileVersion = atoi(vers.c_str()); + file.close(); + + LOG_PRINT(logfile, " [version = %d.%d]\n", majVersion, fileVersion); + + buildVersion = fileVersion; + // translate version + if (majVersion == 3){ + if (fileVersion > 520) // 3.5 ? + fileVersion = 350; + } else if (majVersion == 4){ + if (fileVersion < 110) // 4.0 ? + fileVersion = 400; + else if(fileVersion >= 110 && fileVersion < 140) // 4.1 ? + fileVersion = 410; + else if(fileVersion == 140 || fileVersion == 141) // 4.1 Patch 1 + fileVersion = 410; + else if(fileVersion > 141 && fileVersion < 210) // 5.0 + fileVersion = 500; + else if(fileVersion >= 210 && fileVersion < 2625) // 5.0 SR2 + fileVersion = 502; + else if(fileVersion == 2625) // 6.0 + fileVersion = 600; + else if(fileVersion == 2627) // 6.0 SR1 + fileVersion = 601; + else if(fileVersion == 2630) // 6.0 SR4 + fileVersion = 604; + else if(fileVersion == 2635) // 6.1 + fileVersion = 610; + else if(fileVersion >= 2656 && fileVersion < 2659) // 7.0 + fileVersion = 700; + else if(fileVersion >= 2659 && fileVersion <= 2664) // 7.0 SR1 + fileVersion = 701; + else if(fileVersion == 2672) // 7.0 SR3 + fileVersion = 703; + else if(fileVersion == 2673) // 7.0 E + fileVersion = 704; + else if(fileVersion >= 2766 && fileVersion <= 2769) // 7.5 + fileVersion = 750; + else if(fileVersion >= 2876 && fileVersion <= 2906) // 8.0 + fileVersion = 800; + else if(fileVersion >= 2907 && fileVersion < 2944) // 8.1 + fileVersion = 810; + else if(fileVersion >= 2944 && fileVersion < 2962) // 8.5 SR1 + fileVersion = 850; + else if(fileVersion >= 2962) // 8.5.1 SR2 + fileVersion = 851; + else { + LOG_PRINT(logfile, "Found unknown project version %d\n", fileVersion); + LOG_PRINT(logfile, "Please contact the authors of liborigin2"); + #ifndef NO_LOG_FILE + unsigned int ioret; + ioret = fclose(logfile); + #endif + throw std::logic_error("Unknown project version"); + } + } + LOG_PRINT(logfile, "Found project version %.2f\n", (fileVersion/100.0)); +#ifndef NO_LOG_FILE + fclose(logfile); +#endif + switch(fileVersion){ + case 850: + case 851: + parser.reset(createOrigin850Parser(fileName)); + break; + case 810: + parser.reset(createOrigin810Parser(fileName)); + break; + case 800: + parser.reset(createOrigin800Parser(fileName)); + break; + case 750: + parser.reset(createOrigin750Parser(fileName)); + break; + case 700: + case 701: + case 703: + case 704: + parser.reset(createOrigin700Parser(fileName)); + break; + case 600: + case 601: + case 604: + case 610: + parser.reset(createOrigin610Parser(fileName)); + break; + case 500: + case 502: + parser.reset(createOrigin500Parser(fileName)); + break; + case 350: + case 400: + case 410: + default: + parser.reset(createOrigin410Parser(fileName)); + break; + } +} + +bool OriginFile::parse() +{ + parser->setFileVersion(buildVersion); + return parser->parse(); +} + +double OriginFile::version() const +{ + return fileVersion/100.0; +} + +const tree* OriginFile::project() const +{ + return &parser->projectTree; +} + +vector::size_type OriginFile::spreadCount() const +{ + return parser->speadSheets.size(); +} + +Origin::SpreadSheet& OriginFile::spread(vector::size_type s) const +{ + return parser->speadSheets[s]; +} + +vector::size_type OriginFile::matrixCount() const +{ + return parser->matrices.size(); +} + +Origin::Matrix& OriginFile::matrix(vector::size_type m) const +{ + return parser->matrices[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]; +} + +string OriginFile::resultsLogString() const +{ + return parser->resultsLog; +} diff --git a/3rdparty/liborigin2/OriginFile.h b/3rdparty/liborigin2/OriginFile.h new file mode 100644 index 000000000..d2bc2306b --- /dev/null +++ b/3rdparty/liborigin2/OriginFile.h @@ -0,0 +1,75 @@ +/*************************************************************************** + File : OriginFile.h + -------------------------------------------------------------------- + Copyright : (C) 2007-2011 Ion Vasilief + (C) 2007-2008 Alex Kargovsky + Email (use @ for *) : 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 * + * * + ***************************************************************************/ + +#ifndef ORIGIN_FILE_H +#define ORIGIN_FILE_H + +/* version 0.0 2011-08-29 */ +#define LIBORIGIN_VERSION 0x00110829 +#define LIBORIGIN_VERSION_STRING "2011-08-29" + +#include "OriginObj.h" +#include "OriginParser.h" +#include + +using namespace std; + +class OriginFile +{ +public: + OriginFile(const string& fileName); + + bool parse(); //!< parse Origin file + double version() const; //!< get version of Origin file + + vector::size_type spreadCount() const; //!< get number of spreadsheets + Origin::SpreadSheet& spread(vector::size_type s) const; //!< get spreadsheet s + + vector::size_type matrixCount() const; //!< get number of matrices + Origin::Matrix& matrix(vector::size_type m) const; //!< get matrix m + + vector::size_type functionCount() const; //!< get number of functions + vector::size_type functionIndex(const string& name) const; //!< get name of function s + Origin::Function& function(vector::size_type f) const; //!< get function f + + vector::size_type graphCount() const; //!< get number of graphs + Origin::Graph& graph(vector::size_type g) const; //!< get graph g + + vector::size_type noteCount() const; //!< get number of notes + Origin::Note& note(vector::size_type n) const; //!< get note n + + const tree* project() const; //!< get project tree + string resultsLogString() const; //!< get Results Log + +private: + unsigned int fileVersion, buildVersion; + auto_ptr parser; +}; + +#endif // ORIGIN_FILE_H diff --git a/3rdparty/liborigin2/OriginObj.h b/3rdparty/liborigin2/OriginObj.h new file mode 100644 index 000000000..29a6bd7f7 --- /dev/null +++ b/3rdparty/liborigin2/OriginObj.h @@ -0,0 +1,809 @@ +/*************************************************************************** + File : OriginObj.h + -------------------------------------------------------------------- + Copyright : (C) 2005-2007 Stefan Gerlach + (C) 2007-2008 Alex Kargovsky + (C) 2009-2011 Ion Vasilief + Email (use @ for *) : 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 "boost/variant.hpp" +#include "boost/bind.hpp" +#include +#include + +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}; + 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, BDiagDense, BDiagMedium, BDiagSparse, FDiagDense, FDiagMedium, FDiagSparse, + DiagCrossDense, DiagCrossMedium, DiagCrossSparse, HorizontalDense, HorizontalMedium, HorizontalSparse, + VerticalDense, VerticalMedium, VerticalSparse, CrossDense, CrossMedium, CrossSparse}; + + struct Color + { + enum ColorType {None, Automatic, Regular, Custom, Increment, Indexing, RGB, Mapping}; + 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) + {}; + }; + + typedef boost::variant variant; + + struct SpreadColumn + { + enum ColumnType {X, Y, Z, XErr, YErr, Label, NONE}; + + string 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; + + 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 + { + return curves.end() != find_if(curves.begin(), curves.end(), + boost::bind(logical_or(), boost::bind(&GraphCurve::type, _1) == GraphCurve::Line3D, + boost::bind(&GraphCurve::type, _1) == GraphCurve::Mesh3D)); + } + }; + + 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/3rdparty/liborigin2/OriginParser.cpp b/3rdparty/liborigin2/OriginParser.cpp new file mode 100644 index 000000000..4e98d1708 --- /dev/null +++ b/3rdparty/liborigin2/OriginParser.cpp @@ -0,0 +1,217 @@ +/*************************************************************************** + File : OriginParser.cpp + -------------------------------------------------------------------- + Copyright : (C) 2008 Alex Kargovsky + Email (use @ for *) : kargovsky*yumr.phys.msu.su + 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 * + * * + ***************************************************************************/ + +#include "OriginParser.h" +#include + +using namespace boost; +using namespace Origin; + +int OriginParser::findSpreadByName(const string& name) const +{ + unsigned int spreads = speadSheets.size(); + for (unsigned int i = 0; i < spreads; i++){ + if (speadSheets[i].name == name) + return i; + } + return -1; +} + +int OriginParser::findExcelByName(const string& name) const +{ + unsigned int n = excels.size(); + for (unsigned int i = 0; i < n; i++){ + if (excels[i].name == name) + return i; + } + return -1; +} + +int OriginParser::findExcelColumnByName(int excel, int sheet, const string& name) const +{ + SpreadSheet sh = excels[excel].sheets[sheet]; + unsigned int columns = sh.columns.size(); + for (unsigned int i = 0; i < columns; i++){ + if (sh.columns[i].name == name) + return i; + } + return -1; +} + +int OriginParser::findMatrixByName(const string& name) const +{ + unsigned int n = matrices.size(); + for (unsigned int i = 0; i < n; i++){ + if (matrices[i].name == name) + return i; + } + return -1; +} + +int OriginParser::findFunctionByName(const string& name) const +{ + unsigned int n = functions.size(); + for (unsigned int i = 0; i < n; i++){ + if (functions[i].name == name) + return i; + } + return -1; +} + +pair OriginParser::findDataByIndex(unsigned int index) const +{ + for(vector::const_iterator it = speadSheets.begin(); it != speadSheets.end(); ++it) + { + for(vector::const_iterator it1 = it->columns.begin(); it1 != it->columns.end(); ++it1) + { + if(it1->index == index) + return make_pair("T_" + it->name, it1->name); + } + } + + for(vector::const_iterator it = matrices.begin(); it != matrices.end(); ++it) + { + for(vector::const_iterator it1 = it->sheets.begin(); it1 != it->sheets.end(); ++it1) + { + if(it1->index == index) + return make_pair("M_" + it->name, it1->name); + } + + } + + for(vector::const_iterator it = excels.begin(); it != excels.end(); ++it) + { + for(vector::const_iterator it1 = it->sheets.begin(); it1 != it->sheets.end(); ++it1) + { + for(vector::const_iterator it2 = it1->columns.begin(); it2 != it1->columns.end(); ++it2) + { + if(it2->index == index) + return make_pair("E_" + it->name, it2->name); + } + } + } + + for(vector::const_iterator it = functions.begin(); it != functions.end(); ++it) + { + if(it->index == index) + return make_pair("F_" + it->name, it->name); + } + + return pair(); +} + +pair OriginParser::findObjectByIndex(unsigned int index) const +{ + for(vector::const_iterator it = speadSheets.begin(); it != speadSheets.end(); ++it) + { + if(it->objectID == index) + return make_pair(ProjectNode::SpreadSheet, it->name); + } + + for(vector::const_iterator it = matrices.begin(); it != matrices.end(); ++it) + { + if(it->objectID == index) + return make_pair(ProjectNode::Matrix, it->name); + } + + for(vector::const_iterator it = excels.begin(); it != excels.end(); ++it) + { + if(it->objectID == index) + return make_pair(ProjectNode::Excel, it->name); + } + + for(vector::const_iterator it = graphs.begin(); it != graphs.end(); ++it) + { + if(it->objectID == index){ + if (it->is3D) + return make_pair(ProjectNode::Graph3D, it->name); + else + return make_pair(ProjectNode::Graph, it->name); + } + } + + return pair(); +} + +void OriginParser::convertSpreadToExcel(vector::size_type spread) +{ + //add new Excel sheet + excels.push_back(Excel(speadSheets[spread].name, speadSheets[spread].label, speadSheets[spread].maxRows, speadSheets[spread].hidden, speadSheets[spread].loose)); + + for(vector::iterator it = speadSheets[spread].columns.begin(); it != speadSheets[spread].columns.end(); ++it) + { + unsigned int index = 0; + int pos = it->name.find_last_of("@"); + if(pos != -1){ + index = atoi(it->name.substr(pos + 1).c_str()) - 1; + it->name = it->name.substr(0, pos); + } + + if(excels.back().sheets.size() <= index) + excels.back().sheets.resize(index + 1); + + excels.back().sheets[index].columns.push_back(*it); + } + + speadSheets.erase(speadSheets.begin() + spread); +} + +int OriginParser::findColumnByName(int spread, const string& name) +{ + unsigned int columns = speadSheets[spread].columns.size(); + for (unsigned int i = 0; i < columns; i++){ + string colName = speadSheets[spread].columns[i].name; + int l = colName.size(); + if (l >= 11) + l = 11; + + string s = name; + s.resize(l); + + if (colName == s) + return i; + } + return -1; +} + +int OriginParser::findColumnByIndexAndName(int spread, unsigned int index, const string& name) +{ + unsigned int columns = speadSheets[spread].columns.size(); + for (unsigned int i = 0; i < columns; i++){ + unsigned int colIndex = speadSheets[spread].columns[i].colIndex; + if (colIndex == index){ + string colName = speadSheets[spread].columns[i].name; + if (name == colName.substr(0, name.length())) + return i; + //else + //LOG_PRINT(logfile, " Column name at index %d is %s not %s!\n", index, colName, name); + } + } + //LOG_PRINT(logfile, " Couldn't find column by index, searching column by name..."); + return findColumnByName(spread, name); +} diff --git a/3rdparty/liborigin2/OriginParser.h b/3rdparty/liborigin2/OriginParser.h new file mode 100644 index 000000000..e6f967922 --- /dev/null +++ b/3rdparty/liborigin2/OriginParser.h @@ -0,0 +1,89 @@ +/*************************************************************************** + File : OriginParser.h + -------------------------------------------------------------------- + Copyright : (C) 2009 - 2011 Ion Vasilief + (C) 2008 Alex Kargovsky + Email (use @ for *) : ion_vasilief*yahoo.fr + 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_LOG_FILE + #define LOG_PRINT( logfile, args... )\ + {\ + int ioret = fprintf(logfile, args);\ + assert(ioret>0);\ + } +#else + #define LOG_PRINT( logfile, args... ) {}; +#endif + +class OriginParser +{ +public: + virtual ~OriginParser() {}; + virtual bool parse() = 0; + void setFileVersion(unsigned int version){fileVersion = version;}; + + int findSpreadByName(const string& name) const; + int findMatrixByName(const string& name) const; + int findFunctionByName(const string& name) const; + int findExcelByName(const string& name) const; + +protected: + int findExcelColumnByName(int excel, int 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); + int findColumnByIndexAndName(int spread, unsigned int index, const string& name); + +public: + vector speadSheets; + vector matrices; + vector excels; + vector functions; + vector graphs; + vector notes; + tree projectTree; + string resultsLog; + unsigned int windowsCount; + unsigned int fileVersion; +}; + +OriginParser* createOrigin410Parser(const string& fileName); +OriginParser* createOrigin500Parser(const string& fileName); +OriginParser* createOrigin610Parser(const string& fileName); +OriginParser* createOrigin700Parser(const string& fileName); +OriginParser* createOrigin750Parser(const string& fileName); +OriginParser* createOrigin800Parser(const string& fileName); +OriginParser* createOrigin810Parser(const string& fileName); +OriginParser* createOrigin850Parser(const string& fileName); + +#endif // ORIGIN_PARSER_H diff --git a/3rdparty/liborigin2/copying b/3rdparty/liborigin2/copying new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/3rdparty/liborigin2/copying @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/3rdparty/liborigin2/doc/Doxyfile b/3rdparty/liborigin2/doc/Doxyfile new file mode 100644 index 000000000..c1c37201f --- /dev/null +++ b/3rdparty/liborigin2/doc/Doxyfile @@ -0,0 +1,236 @@ +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = liborigin2 +PROJECT_NUMBER = 29/08/2011 +OUTPUT_DIRECTORY = . +CREATE_SUBDIRS = 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 +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = 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 +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = YES +SORT_BY_SCOPE_NAME = 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 +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# 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_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = .. +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.dox \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.txt \ + *.CC \ + *.C++ \ + *.HH \ + *.H++ \ + *.C \ + *.H +RECURSIVE = yes +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = *moc_* +EXAMPLE_PATH = .. +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# 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 +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# 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 = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# 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 = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# 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 +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# 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 +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +# recommendation: install graphviz and use HAVE_DOT = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +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/3rdparty/liborigin2/doc/html/images/origin_import.png b/3rdparty/liborigin2/doc/html/images/origin_import.png new file mode 100644 index 0000000000000000000000000000000000000000..1bf35a40fd944d63be15336d95d882dc71d60e33 GIT binary patch literal 57301 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 literal 0 HcmV?d00001 diff --git a/3rdparty/liborigin2/doc/liborigin2.dox b/3rdparty/liborigin2/doc/liborigin2.dox new file mode 100644 index 000000000..ea72aeb82 --- /dev/null +++ b/3rdparty/liborigin2/doc/liborigin2.dox @@ -0,0 +1,62 @@ +/*! + \mainpage liborigin2 + + A library for reading OriginLab project files created with versions ranging from 4.1 to 8.5.1. + Any help from developers interested in working on the import of files created with other OriginLab versions is most welcome. + Please contact me only if you have already improved the code, e-mails from persons "planning to work" will be ignored. + + \image html images/origin_import.png + + \section license License + + liborigin2 follows a licensing model similar to that used by Qt and is available under the following licenses: \ref gpllicense and Commercial. + The Commercial version is the appropriate version to use for the development of proprietary and/or commercial software. + This version is for developers who do not want to share the source code with others or otherwise comply with the terms of the GNU GPL version 3.0. + Please contact us for any questions related to pricing/licensing. + + \section platforms Platforms + + liborigin2 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) and + tree.hh.\n + + \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 + the qmake manual. + + \section relatedprojects Related Projects + + QtiPlot, data analysis and scientific plotting tool. + + \section credits Credits: + \par Author: + Ion Vasilief + \par Contributors (not active anymore): + Stefan Gerlach, Alex Kargovsky + \par Contact: + Ion Vasilief +*/ + +/*! + \page gpllicense GPL License, Version 3 + \include "copying" +*/ + +/*! + \page projectfile liborigin2.pro + \include "liborigin2.pro" +*/ + +/*! + \page liborigin2install README + \include "readme" +*/ diff --git a/3rdparty/liborigin2/endianfstream.hh b/3rdparty/liborigin2/endianfstream.hh new file mode 100644 index 000000000..adc6e7b99 --- /dev/null +++ b/3rdparty/liborigin2/endianfstream.hh @@ -0,0 +1,233 @@ +/*************************************************************************** + File : endianfstream.hh + -------------------------------------------------------------------- + Copyright : (C) 2008 Alex Kargovsky, (C) 2010 Ion Vasilief + Email (use @ for *) : ion_vasilief*yahoo.fr + Description : Endianless file stream 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 ENDIAN_FSTREAM_H +#define ENDIAN_FSTREAM_H + +#include +#include "OriginObj.h" + +namespace std +{ + class iendianfstream : public ifstream + { + public: + iendianfstream(const char *_Filename, ios_base::openmode _Mode = ios_base::in) + : ifstream(_Filename, _Mode) + { + short word = 0x4321; + bigEndian = (*(char*)& word) != 0x21; + }; + + iendianfstream& operator>>(bool& value) + { + char c; + get(c); + value = (c != 0); + return *this; + } + + iendianfstream& operator>>(char& value) + { + get(value); + return *this; + } + + iendianfstream& operator>>(unsigned char& value) + { + get(reinterpret_cast(value)); + return *this; + } + + iendianfstream& operator>>(short& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(unsigned short& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(int& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(unsigned int& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(long& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(unsigned long& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(float& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(double& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(long double& value) + { + read(reinterpret_cast(&value), sizeof(value)); + if(bigEndian) + swap_bytes(reinterpret_cast(&value), sizeof(value)); + + return *this; + } + + iendianfstream& operator>>(string& value) + { + read(reinterpret_cast(&value[0]), value.size()); + string::size_type pos = value.find_first_of('\0'); + if(pos != string::npos) + value.resize(pos); + + return *this; + } + + iendianfstream& operator>>(Origin::Color& value) + { + unsigned char color[4]; + read(reinterpret_cast(&color), sizeof(color)); + switch(color[3]) + { + case 0: + if(color[0] < 0x64) + { + value.type = Origin::Color::Regular; + value.regular = color[0]; + } + else + { + switch(color[2]) + { + case 0: + value.type = Origin::Color::Indexing; + break; + case 0x40: + value.type = Origin::Color::Mapping; + break; + case 0x80: + value.type = Origin::Color::RGB; + break; + } + + value.column = color[0] - 0x64; + } + + break; + case 1: + value.type = Origin::Color::Custom; + for(int i = 0; i < 3; ++i) + value.custom[i] = color[i]; + break; + case 0x20: + value.type = Origin::Color::Increment; + value.starting = color[1]; + break; + case 0xFF: + if(color[0] == 0xFC) + value.type = Origin::Color::None; + else if(color[0] == 0xF7) + value.type = Origin::Color::Automatic; + else + value.type = Origin::Color::Regular; + value.regular = color[0]; + break; + + default: + value.type = Origin::Color::Regular; + value.regular = color[0]; + break; + + } + + return *this; + } + + private: + bool bigEndian; + void swap_bytes(unsigned char* data, int size) + { + register int i = 0; + register int j = size - 1; + while(i < j) + { + std::swap(data[i], data[j]); + ++i, --j; + } + } + }; +} + +#endif // ENDIAN_FSTREAM_H diff --git a/3rdparty/liborigin2/liborigin2.pri b/3rdparty/liborigin2/liborigin2.pri new file mode 100644 index 000000000..7d4ece495 --- /dev/null +++ b/3rdparty/liborigin2/liborigin2.pri @@ -0,0 +1,26 @@ +############################################################### +################# liborigin2 source files ##################### +############################################################### + +HEADERS += OriginObj.h +HEADERS += OriginFile.h +HEADERS += OriginParser.h +HEADERS += Origin410Parser.h +HEADERS += Origin500Parser.h +HEADERS += Origin610Parser.h +HEADERS += Origin700Parser.h +HEADERS += Origin750Parser.h +HEADERS += Origin800Parser.h +HEADERS += Origin810Parser.h +HEADERS += Origin850Parser.h + +SOURCES += OriginFile.cpp +SOURCES += OriginParser.cpp +SOURCES += Origin410Parser.cpp +SOURCES += Origin500Parser.cpp +SOURCES += Origin610Parser.cpp +SOURCES += Origin700Parser.cpp +SOURCES += Origin750Parser.cpp +SOURCES += Origin800Parser.cpp +SOURCES += Origin810Parser.cpp +SOURCES += Origin850Parser.cpp diff --git a/3rdparty/liborigin2/liborigin2.pro b/3rdparty/liborigin2/liborigin2.pro new file mode 100644 index 000000000..c1c55186c --- /dev/null +++ b/3rdparty/liborigin2/liborigin2.pro @@ -0,0 +1,19 @@ +TARGET = origin2 +TEMPLATE = lib +CONFIG += warn_on release thread + +# Uncomment the following line if you want to build statically. +#CONFIG += staticlib + +MOC_DIR = ./tmp +OBJECTS_DIR = ./tmp + +DESTDIR = ./ + +# Uncomment the following line if you want to disable logging. +#DEFINES += NO_LOG_FILE + +# Path to the folder where the header files of the BOOST C++ libraries are installed +INCLUDEPATH += ../boost + +include(liborigin2.pri) diff --git a/3rdparty/liborigin2/readme b/3rdparty/liborigin2/readme new file mode 100644 index 000000000..5d36fe685 --- /dev/null +++ b/3rdparty/liborigin2/readme @@ -0,0 +1,24 @@ +liborigin2 +--------------------- + +AUTHOR: Ion Vasilief + +CONTRIBUTORS (not active anymore): Stefan Gerlach, Alex Kargovsky + +DEPENDENCIES: liborigin2 depends on the BOOST C++ libraries (version >= 1.33.0): http://www.boost.org/ + and tree.hh: http://tree.phi-sci.com/ +------------------------------------------------------------------------------------------------------ +COMPILING: liborigin2 uses qmake for the building process. + qmake is part of a Qt distribution: http://trolltech.com/ + qmake reads project files, that contain the options and rules how to build a certain project. + A project file ends with the suffix "*.pro". Please read the qmake documentation for more details. + +After installing qmake, tree.hh and the BOOST C++ libraries on your system, type the following command lines: + $ qmake + $ make + +------------------------------------------------------------------------------------------------------ +FEATURES : + * supports the import of OriginLab projects with versions ranging from 4.1 to 8.5.1 + +------------------------------------------------------------------------------------------------------ diff --git a/3rdparty/liborigin2/tree.hh b/3rdparty/liborigin2/tree.hh new file mode 100644 index 000000000..b2f300535 --- /dev/null +++ b/3rdparty/liborigin2/tree.hh @@ -0,0 +1,2786 @@ + +// STL-like templated tree class. +// +// Copyright (C) 2001-2011 Kasper Peeters +// Distributed under the GNU General Public License version 3. +// +// When used together with the htmlcxx library to create +// HTML::Node template instances, the GNU Lesser General Public +// version 2 applies. Special permission to use tree.hh under +// the LGPL for other projects can be requested from the author. + +/** \mainpage tree.hh + \author Kasper Peeters + \version 2.81 + \date 23-Aug-2011 + \see http://tree.phi-sci.com/ + \see http://tree.phi-sci.com/ChangeLog + + The tree.hh library for C++ provides an STL-like container class + for n-ary trees, templated over the data stored at the + nodes. Various types of iterators are provided (post-order, + pre-order, and others). Where possible the access methods are + compatible with the STL or alternative algorithms are + available. +*/ + + +#ifndef tree_hh_ +#define tree_hh_ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/// A node in the tree, combining links to other nodes as well as the actual data. +template +class tree_node_ { // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8. + public: + tree_node_(); + tree_node_(const T&); + + tree_node_ *parent; + tree_node_ *first_child, *last_child; + tree_node_ *prev_sibling, *next_sibling; + T data; +}; // __attribute__((packed)); + +template +tree_node_::tree_node_() + : parent(0), first_child(0), last_child(0), prev_sibling(0), next_sibling(0) + { + } + +template +tree_node_::tree_node_(const T& val) + : parent(0), first_child(0), last_child(0), prev_sibling(0), next_sibling(0), data(val) + { + } + +template > > +class tree { + protected: + typedef tree_node_ tree_node; + public: + /// Value of the data stored at a node. + typedef T value_type; + + class iterator_base; + class pre_order_iterator; + class post_order_iterator; + class sibling_iterator; + class leaf_iterator; + + tree(); + tree(const T&); + tree(const iterator_base&); + tree(const tree&); + ~tree(); + tree& operator=(const tree&); + + /// Base class for iterators, only pointers stored, no traversal logic. +#ifdef __SGI_STL_PORT + class iterator_base : public stlport::bidirectional_iterator { +#else + class iterator_base { +#endif + public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + iterator_base(); + iterator_base(tree_node *); + + T& operator*() const; + T* operator->() const; + + /// When called, the next increment/decrement skips children of this node. + void skip_children(); + void skip_children(bool skip); + /// Number of children of the node pointed to by the iterator. + unsigned int number_of_children() const; + + sibling_iterator begin() const; + sibling_iterator end() const; + + tree_node *node; + protected: + bool skip_current_children_; + }; + + /// Depth-first iterator, first accessing the node, then its children. + class pre_order_iterator : public iterator_base { + public: + pre_order_iterator(); + pre_order_iterator(tree_node *); + pre_order_iterator(const iterator_base&); + pre_order_iterator(const sibling_iterator&); + + bool operator==(const pre_order_iterator&) const; + bool operator!=(const pre_order_iterator&) const; + pre_order_iterator& operator++(); + pre_order_iterator& operator--(); + pre_order_iterator operator++(int); + pre_order_iterator operator--(int); + pre_order_iterator& operator+=(unsigned int); + pre_order_iterator& operator-=(unsigned int); + }; + + /// Depth-first iterator, first accessing the children, then the node itself. + class post_order_iterator : public iterator_base { + public: + post_order_iterator(); + post_order_iterator(tree_node *); + post_order_iterator(const iterator_base&); + post_order_iterator(const sibling_iterator&); + + bool operator==(const post_order_iterator&) const; + bool operator!=(const post_order_iterator&) const; + post_order_iterator& operator++(); + post_order_iterator& operator--(); + post_order_iterator operator++(int); + post_order_iterator operator--(int); + post_order_iterator& operator+=(unsigned int); + post_order_iterator& operator-=(unsigned int); + + /// Set iterator to the first child as deep as possible down the tree. + void descend_all(); + }; + + /// Breadth-first iterator, using a queue + class breadth_first_queued_iterator : public iterator_base { + public: + breadth_first_queued_iterator(); + breadth_first_queued_iterator(tree_node *); + breadth_first_queued_iterator(const iterator_base&); + + bool operator==(const breadth_first_queued_iterator&) const; + bool operator!=(const breadth_first_queued_iterator&) const; + breadth_first_queued_iterator& operator++(); + breadth_first_queued_iterator operator++(int); + breadth_first_queued_iterator& operator+=(unsigned int); + + private: + std::queue traversal_queue; + }; + + /// The default iterator types throughout the tree class. + typedef pre_order_iterator iterator; + typedef breadth_first_queued_iterator breadth_first_iterator; + + /// Iterator which traverses only the nodes at a given depth from the root. + class fixed_depth_iterator : public iterator_base { + public: + fixed_depth_iterator(); + fixed_depth_iterator(tree_node *); + fixed_depth_iterator(const iterator_base&); + fixed_depth_iterator(const sibling_iterator&); + fixed_depth_iterator(const fixed_depth_iterator&); + + bool operator==(const fixed_depth_iterator&) const; + bool operator!=(const fixed_depth_iterator&) const; + fixed_depth_iterator& operator++(); + fixed_depth_iterator& operator--(); + fixed_depth_iterator operator++(int); + fixed_depth_iterator operator--(int); + fixed_depth_iterator& operator+=(unsigned int); + fixed_depth_iterator& operator-=(unsigned int); + + tree_node *top_node; + }; + + /// Iterator which traverses only the nodes which are siblings of each other. + class sibling_iterator : public iterator_base { + public: + sibling_iterator(); + sibling_iterator(tree_node *); + sibling_iterator(const sibling_iterator&); + sibling_iterator(const iterator_base&); + + bool operator==(const sibling_iterator&) const; + bool operator!=(const sibling_iterator&) const; + sibling_iterator& operator++(); + sibling_iterator& operator--(); + sibling_iterator operator++(int); + sibling_iterator operator--(int); + sibling_iterator& operator+=(unsigned int); + sibling_iterator& operator-=(unsigned int); + + tree_node *range_first() const; + tree_node *range_last() const; + tree_node *parent_; + private: + void set_parent_(); + }; + + /// Iterator which traverses only the leaves. + class leaf_iterator : public iterator_base { + public: + leaf_iterator(); + leaf_iterator(tree_node *, tree_node *top=0); + leaf_iterator(const sibling_iterator&); + leaf_iterator(const iterator_base&); + + bool operator==(const leaf_iterator&) const; + bool operator!=(const leaf_iterator&) const; + leaf_iterator& operator++(); + leaf_iterator& operator--(); + leaf_iterator operator++(int); + leaf_iterator operator--(int); + leaf_iterator& operator+=(unsigned int); + leaf_iterator& operator-=(unsigned int); + private: + tree_node *top_node; + }; + + /// Return iterator to the beginning of the tree. + inline pre_order_iterator begin() const; + /// Return iterator to the end of the tree. + inline pre_order_iterator end() const; + /// Return post-order iterator to the beginning of the tree. + post_order_iterator begin_post() const; + /// Return post-order end iterator of the tree. + post_order_iterator end_post() const; + /// Return fixed-depth iterator to the first node at a given depth from the given iterator. + fixed_depth_iterator begin_fixed(const iterator_base&, unsigned int) const; + /// Return fixed-depth end iterator. + fixed_depth_iterator end_fixed(const iterator_base&, unsigned int) const; + /// Return breadth-first iterator to the first node at a given depth. + breadth_first_queued_iterator begin_breadth_first() const; + /// Return breadth-first end iterator. + breadth_first_queued_iterator end_breadth_first() const; + /// Return sibling iterator to the first child of given node. + sibling_iterator begin(const iterator_base&) const; + /// Return sibling end iterator for children of given node. + sibling_iterator end(const iterator_base&) const; + /// Return leaf iterator to the first leaf of the tree. + leaf_iterator begin_leaf() const; + /// Return leaf end iterator for entire tree. + leaf_iterator end_leaf() const; + /// Return leaf iterator to the first leaf of the subtree at the given node. + leaf_iterator begin_leaf(const iterator_base& top) const; + /// Return leaf end iterator for the subtree at the given node. + leaf_iterator end_leaf(const iterator_base& top) const; + + /// Return iterator to the parent of a node. + template static iter parent(iter); + /// Return iterator to the previous sibling of a node. + template iter previous_sibling(iter) const; + /// Return iterator to the next sibling of a node. + template iter next_sibling(iter) const; + /// Return iterator to the next node at a given depth. + template iter next_at_same_depth(iter) const; + + /// Erase all nodes of the tree. + void clear(); + /// Erase element at position pointed to by iterator, return incremented iterator. + template iter erase(iter); + /// Erase all children of the node pointed to by iterator. + void erase_children(const iterator_base&); + + /// Insert empty node as last/first child of node pointed to by position. + template iter append_child(iter position); + template iter prepend_child(iter position); + /// Insert node as last/first child of node pointed to by position. + template iter append_child(iter position, const T& x); + template iter prepend_child(iter position, const T& x); + /// Append the node (plus its children) at other_position as last/first child of position. + template iter append_child(iter position, iter other_position); + template iter prepend_child(iter position, iter other_position); + /// Append the nodes in the from-to range (plus their children) as last/first children of position. + template iter append_children(iter position, sibling_iterator from, sibling_iterator to); + template iter prepend_children(iter position, sibling_iterator from, sibling_iterator to); + + /// Short-hand to insert topmost node in otherwise empty tree. + pre_order_iterator set_head(const T& x); + /// Insert node as previous sibling of node pointed to by position. + template iter insert(iter position, const T& x); + /// Specialisation of previous member. + sibling_iterator insert(sibling_iterator position, const T& x); + /// Insert node (with children) pointed to by subtree as previous sibling of node pointed to by position. + template iter insert_subtree(iter position, const iterator_base& subtree); + /// Insert node as next sibling of node pointed to by position. + template iter insert_after(iter position, const T& x); + /// Insert node (with children) pointed to by subtree as next sibling of node pointed to by position. + template iter insert_subtree_after(iter position, const iterator_base& subtree); + + /// Replace node at 'position' with other node (keeping same children); 'position' becomes invalid. + template iter replace(iter position, const T& x); + /// Replace node at 'position' with subtree starting at 'from' (do not erase subtree at 'from'); see above. + template iter replace(iter position, const iterator_base& from); + /// Replace string of siblings (plus their children) with copy of a new string (with children); see above + sibling_iterator replace(sibling_iterator orig_begin, sibling_iterator orig_end, + sibling_iterator new_begin, sibling_iterator new_end); + + /// Move all children of node at 'position' to be siblings, returns position. + template iter flatten(iter position); + /// Move nodes in range to be children of 'position'. + template iter reparent(iter position, sibling_iterator begin, sibling_iterator end); + /// Move all child nodes of 'from' to be children of 'position'. + template iter reparent(iter position, iter from); + + /// Replace node with a new node, making the old node a child of the new node. + template iter wrap(iter position, const T& x); + + /// Move 'source' node (plus its children) to become the next sibling of 'target'. + template iter move_after(iter target, iter source); + /// Move 'source' node (plus its children) to become the previous sibling of 'target'. + template iter move_before(iter target, iter source); + sibling_iterator move_before(sibling_iterator target, sibling_iterator source); + /// Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target'). + template iter move_ontop(iter target, iter source); + + /// Merge with other tree, creating new branches and leaves only if they are not already present. + void merge(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator, + bool duplicate_leaves=false); + /// Sort (std::sort only moves values of nodes, this one moves children as well). + void sort(sibling_iterator from, sibling_iterator to, bool deep=false); + template + void sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false); + /// Compare two ranges of nodes (compares nodes as well as tree structure). + template + bool equal(const iter& one, const iter& two, const iter& three) const; + template + bool equal(const iter& one, const iter& two, const iter& three, BinaryPredicate) const; + template + bool equal_subtree(const iter& one, const iter& two) const; + template + bool equal_subtree(const iter& one, const iter& two, BinaryPredicate) const; + /// Extract a new tree formed by the range of siblings plus all their children. + tree subtree(sibling_iterator from, sibling_iterator to) const; + void subtree(tree&, sibling_iterator from, sibling_iterator to) const; + /// Exchange the node (plus subtree) with its sibling node (do nothing if no sibling present). + void swap(sibling_iterator it); + /// Exchange two nodes (plus subtrees) + void swap(iterator, iterator); + + /// Count the total number of nodes. + size_t size() const; + /// Count the total number of nodes below the indicated node (plus one). + size_t size(const iterator_base&) const; + /// Check if tree is empty. + bool empty() const; + /// Compute the depth to the root or to a fixed other iterator. + static int depth(const iterator_base&); + static int depth(const iterator_base&, const iterator_base&); + /// Determine the maximal depth of the tree. An empty tree has max_depth=-1. + int max_depth() const; + /// Determine the maximal depth of the tree with top node at the given position. + int max_depth(const iterator_base&) const; + /// Count the number of children of node at position. + static unsigned int number_of_children(const iterator_base&); + /// Count the number of siblings (left and right) of node at iterator. Total nodes at this level is +1. + unsigned int number_of_siblings(const iterator_base&) const; + /// Determine whether node at position is in the subtrees with root in the range. + bool is_in_subtree(const iterator_base& position, const iterator_base& begin, + const iterator_base& end) const; + /// Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node. + bool is_valid(const iterator_base&) const; + /// Find the lowest common ancestor of two nodes, that is, the deepest node such that + /// both nodes are descendants of it. + iterator lowest_common_ancestor(const iterator_base&, const iterator_base &) const; + + /// Determine the index of a node in the range of siblings to which it belongs. + unsigned int index(sibling_iterator it) const; + /// Inverse of 'index': return the n-th child of the node at position. + static sibling_iterator child(const iterator_base& position, unsigned int); + /// Return iterator to the sibling indicated by index + sibling_iterator sibling(const iterator_base& position, unsigned int); + + /// For debugging only: verify internal consistency by inspecting all pointers in the tree + /// (which will also trigger a valgrind error in case something got corrupted). + void debug_verify_consistency() const; + + /// Comparator class for iterators (compares pointer values; why doesn't this work automatically?) + class iterator_base_less { + public: + bool operator()(const typename tree::iterator_base& one, + const typename tree::iterator_base& two) const + { + return one.node < two.node; + } + }; + tree_node *head, *feet; // head/feet are always dummy; if an iterator points to them it is invalid + private: + tree_node_allocator alloc_; + void head_initialise_(); + void copy_(const tree& other); + + /// Comparator class for two nodes of a tree (used for sorting and searching). + template + class compare_nodes { + public: + compare_nodes(StrictWeakOrdering comp) : comp_(comp) {}; + + bool operator()(const tree_node *a, const tree_node *b) + { + return comp_(a->data, b->data); + } + private: + StrictWeakOrdering comp_; + }; +}; + +//template +//class iterator_base_less { +// public: +// bool operator()(const typename tree::iterator_base& one, +// const typename tree::iterator_base& two) const +// { +// txtout << "operatorclass<" << one.node < two.node << std::endl; +// return one.node < two.node; +// } +//}; + +// template +// bool operator<(const typename tree::iterator& one, +// const typename tree::iterator& two) +// { +// txtout << "operator< " << one.node < two.node << std::endl; +// if(one.node < two.node) return true; +// return false; +// } +// +// template +// bool operator==(const typename tree::iterator& one, +// const typename tree::iterator& two) +// { +// txtout << "operator== " << one.node == two.node << std::endl; +// if(one.node == two.node) return true; +// return false; +// } +// +// template +// bool operator>(const typename tree::iterator_base& one, +// const typename tree::iterator_base& two) +// { +// txtout << "operator> " << one.node < two.node << std::endl; +// if(one.node > two.node) return true; +// return false; +// } + + + +// Tree + +template +tree::tree() + { + head_initialise_(); + } + +template +tree::tree(const T& x) + { + head_initialise_(); + set_head(x); + } + +template +tree::tree(const iterator_base& other) + { + head_initialise_(); + set_head((*other)); + replace(begin(), other); + } + +template +tree::~tree() + { + clear(); + alloc_.destroy(head); + alloc_.destroy(feet); + alloc_.deallocate(head,1); + alloc_.deallocate(feet,1); + } + +template +void tree::head_initialise_() + { + head = alloc_.allocate(1,0); // MSVC does not have default second argument + feet = alloc_.allocate(1,0); + alloc_.construct(head, tree_node_()); + alloc_.construct(feet, tree_node_()); + + head->parent=0; + head->first_child=0; + head->last_child=0; + head->prev_sibling=0; //head; + head->next_sibling=feet; //head; + + feet->parent=0; + feet->first_child=0; + feet->last_child=0; + feet->prev_sibling=head; + feet->next_sibling=0; + } + +template +tree& tree::operator=(const tree& other) + { + if(this != &other) + copy_(other); + return *this; + } + +template +tree::tree(const tree& other) + { + head_initialise_(); + copy_(other); + } + +template +void tree::copy_(const tree& other) + { + clear(); + pre_order_iterator it=other.begin(), to=begin(); + while(it!=other.end()) { + to=insert(to, (*it)); + it.skip_children(); + ++it; + } + to=begin(); + it=other.begin(); + while(it!=other.end()) { + to=replace(to, it); + to.skip_children(); + it.skip_children(); + ++to; + ++it; + } + } + +template +void tree::clear() + { + if(head) + while(head->next_sibling!=feet) + erase(pre_order_iterator(head->next_sibling)); + } + +template +void tree::erase_children(const iterator_base& it) + { +// std::cout << "erase_children " << it.node << std::endl; + if(it.node==0) return; + + tree_node *cur=it.node->first_child; + tree_node *prev=0; + + while(cur!=0) { + prev=cur; + cur=cur->next_sibling; + erase_children(pre_order_iterator(prev)); +// kp::destructor(&prev->data); + alloc_.destroy(prev); + alloc_.deallocate(prev,1); + } + it.node->first_child=0; + it.node->last_child=0; +// std::cout << "exit" << std::endl; + } + +template +template +iter tree::erase(iter it) + { + tree_node *cur=it.node; + assert(cur!=head); + iter ret=it; + ret.skip_children(); + ++ret; + erase_children(it); + if(cur->prev_sibling==0) { + cur->parent->first_child=cur->next_sibling; + } + else { + cur->prev_sibling->next_sibling=cur->next_sibling; + } + if(cur->next_sibling==0) { + cur->parent->last_child=cur->prev_sibling; + } + else { + cur->next_sibling->prev_sibling=cur->prev_sibling; + } + +// kp::destructor(&cur->data); + alloc_.destroy(cur); + alloc_.deallocate(cur,1); + return ret; + } + +template +typename tree::pre_order_iterator tree::begin() const + { + return pre_order_iterator(head->next_sibling); + } + +template +typename tree::pre_order_iterator tree::end() const + { + return pre_order_iterator(feet); + } + +template +typename tree::breadth_first_queued_iterator tree::begin_breadth_first() const + { + return breadth_first_queued_iterator(head->next_sibling); + } + +template +typename tree::breadth_first_queued_iterator tree::end_breadth_first() const + { + return breadth_first_queued_iterator(); + } + +template +typename tree::post_order_iterator tree::begin_post() const + { + tree_node *tmp=head->next_sibling; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return post_order_iterator(tmp); + } + +template +typename tree::post_order_iterator tree::end_post() const + { + return post_order_iterator(feet); + } + +template +typename tree::fixed_depth_iterator tree::begin_fixed(const iterator_base& pos, unsigned int dp) const + { + typename tree::fixed_depth_iterator ret; + ret.top_node=pos.node; + + tree_node *tmp=pos.node; + unsigned int curdepth=0; + while(curdepthfirst_child==0) { + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + if(tmp==ret.top_node) + throw std::range_error("tree: begin_fixed out of range"); + tmp=tmp->parent; + if(tmp==0) + throw std::range_error("tree: begin_fixed out of range"); + --curdepth; + } while(tmp->next_sibling==0); + } + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + } + + ret.node=tmp; + return ret; + } + +template +typename tree::fixed_depth_iterator tree::end_fixed(const iterator_base& pos, unsigned int dp) const + { + assert(1==0); // FIXME: not correct yet: use is_valid() as a temporary workaround + tree_node *tmp=pos.node; + unsigned int curdepth=1; + while(curdepthfirst_child==0) { + tmp=tmp->next_sibling; + if(tmp==0) + throw std::range_error("tree: end_fixed out of range"); + } + tmp=tmp->first_child; + ++curdepth; + } + return tmp; + } + +template +typename tree::sibling_iterator tree::begin(const iterator_base& pos) const + { + assert(pos.node!=0); + if(pos.node->first_child==0) { + return end(pos); + } + return pos.node->first_child; + } + +template +typename tree::sibling_iterator tree::end(const iterator_base& pos) const + { + sibling_iterator ret(0); + ret.parent_=pos.node; + return ret; + } + +template +typename tree::leaf_iterator tree::begin_leaf() const + { + tree_node *tmp=head->next_sibling; + if(tmp!=feet) { + while(tmp->first_child) + tmp=tmp->first_child; + } + return leaf_iterator(tmp); + } + +template +typename tree::leaf_iterator tree::end_leaf() const + { + return leaf_iterator(feet); + } + +template +typename tree::leaf_iterator tree::begin_leaf(const iterator_base& top) const + { + tree_node *tmp=top.node; + while(tmp->first_child) + tmp=tmp->first_child; + return leaf_iterator(tmp, top.node); + } + +template +typename tree::leaf_iterator tree::end_leaf(const iterator_base& top) const + { + return leaf_iterator(top.node, top.node); + } + +template +template +iter tree::parent(iter position) + { + assert(position.node!=0); + return iter(position.node->parent); + } + +template +template +iter tree::previous_sibling(iter position) const + { + assert(position.node!=0); + iter ret(position); + ret.node=position.node->prev_sibling; + return ret; + } + +template +template +iter tree::next_sibling(iter position) const + { + assert(position.node!=0); + iter ret(position); + ret.node=position.node->next_sibling; + return ret; + } + +template +template +iter tree::next_at_same_depth(iter position) const + { + // We make use of a temporary fixed_depth iterator to implement this. + + typename tree::fixed_depth_iterator tmp(position.node); + + ++tmp; + return iter(tmp); + +// assert(position.node!=0); +// iter ret(position); +// +// if(position.node->next_sibling) { +// ret.node=position.node->next_sibling; +// } +// else { +// int relative_depth=0; +// upper: +// do { +// ret.node=ret.node->parent; +// if(ret.node==0) return ret; +// --relative_depth; +// } while(ret.node->next_sibling==0); +// lower: +// ret.node=ret.node->next_sibling; +// while(ret.node->first_child==0) { +// if(ret.node->next_sibling==0) +// goto upper; +// ret.node=ret.node->next_sibling; +// if(ret.node==0) return ret; +// } +// while(relative_depth<0 && ret.node->first_child!=0) { +// ret.node=ret.node->first_child; +// ++relative_depth; +// } +// if(relative_depth<0) { +// if(ret.node->next_sibling==0) goto upper; +// else goto lower; +// } +// } +// return ret; + } + +template +template +iter tree::append_child(iter position) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + tree_node *tmp=alloc_.allocate(1,0); + alloc_.construct(tmp, tree_node_()); +// kp::constructor(&tmp->data); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; + } + +template +template +iter tree::prepend_child(iter position) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + tree_node *tmp=alloc_.allocate(1,0); + alloc_.construct(tmp, tree_node_()); +// kp::constructor(&tmp->data); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->prev_child=tmp; + tmp->prev_sibling=0; + return tmp; + } + +template +template +iter tree::append_child(iter position, const T& x) + { + // If your program fails here you probably used 'append_child' to add the top + // node to an empty tree. From version 1.45 the top element should be added + // using 'insert'. See the documentation for further information, and sorry about + // the API change. + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->last_child!=0) { + position.node->last_child->next_sibling=tmp; + } + else { + position.node->first_child=tmp; + } + tmp->prev_sibling=position.node->last_child; + position.node->last_child=tmp; + tmp->next_sibling=0; + return tmp; + } + +template +template +iter tree::prepend_child(iter position, const T& x) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node; + if(position.node->first_child!=0) { + position.node->first_child->prev_sibling=tmp; + } + else { + position.node->last_child=tmp; + } + tmp->next_sibling=position.node->first_child; + position.node->first_child=tmp; + tmp->prev_sibling=0; + return tmp; + } + +template +template +iter tree::append_child(iter position, iter other) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + sibling_iterator aargh=append_child(position, value_type()); + return replace(aargh, other); + } + +template +template +iter tree::prepend_child(iter position, iter other) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + sibling_iterator aargh=prepend_child(position, value_type()); + return replace(aargh, other); + } + +template +template +iter tree::append_children(iter position, sibling_iterator from, sibling_iterator to) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + iter ret=from; + + while(from!=to) { + insert_subtree(position.end(), from); + ++from; + } + return ret; + } + +template +template +iter tree::prepend_children(iter position, sibling_iterator from, sibling_iterator to) + { + assert(position.node!=head); + assert(position.node!=feet); + assert(position.node); + + iter ret=from; + + while(from!=to) { + insert_subtree(position.begin(), from); + ++from; + } + return ret; + } + +template +typename tree::pre_order_iterator tree::set_head(const T& x) + { + assert(head->next_sibling==feet); + return insert(iterator(feet), x); + } + +template +template +iter tree::insert(iter position, const T& x) + { + if(position.node==0) { + position.node=feet; // Backward compatibility: when calling insert on a null node, + // insert before the feet. + } + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->next_sibling=position.node; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; + } + +template +typename tree::sibling_iterator tree::insert(sibling_iterator position, const T& x) + { + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->next_sibling=position.node; + if(position.node==0) { // iterator points to end of a subtree + tmp->parent=position.parent_; + tmp->prev_sibling=position.range_last(); + tmp->parent->last_child=tmp; + } + else { + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node->prev_sibling; + position.node->prev_sibling=tmp; + } + + if(tmp->prev_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->first_child=tmp; + } + else + tmp->prev_sibling->next_sibling=tmp; + return tmp; + } + +template +template +iter tree::insert_after(iter position, const T& x) + { + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, x); +// kp::constructor(&tmp->data, x); + tmp->first_child=0; + tmp->last_child=0; + + tmp->parent=position.node->parent; + tmp->prev_sibling=position.node; + tmp->next_sibling=position.node->next_sibling; + position.node->next_sibling=tmp; + + if(tmp->next_sibling==0) { + if(tmp->parent) // when inserting nodes at the head, there is no parent + tmp->parent->last_child=tmp; + } + else { + tmp->next_sibling->prev_sibling=tmp; + } + return tmp; + } + +template +template +iter tree::insert_subtree(iter position, const iterator_base& subtree) + { + // insert dummy + iter it=insert(position, value_type()); + // replace dummy with subtree + return replace(it, subtree); + } + +template +template +iter tree::insert_subtree_after(iter position, const iterator_base& subtree) + { + // insert dummy + iter it=insert_after(position, value_type()); + // replace dummy with subtree + return replace(it, subtree); + } + +// template +// template +// iter tree::insert_subtree(sibling_iterator position, iter subtree) +// { +// // insert dummy +// iter it(insert(position, value_type())); +// // replace dummy with subtree +// return replace(it, subtree); +// } + +template +template +iter tree::replace(iter position, const T& x) + { +// kp::destructor(&position.node->data); +// kp::constructor(&position.node->data, x); + position.node->data=x; +// alloc_.destroy(position.node); +// alloc_.construct(position.node, x); + return position; + } + +template +template +iter tree::replace(iter position, const iterator_base& from) + { + assert(position.node!=head); + tree_node *current_from=from.node; + tree_node *start_from=from.node; + tree_node *current_to =position.node; + + // replace the node at position with head of the replacement tree at from +// std::cout << "warning!" << position.node << std::endl; + erase_children(position); +// std::cout << "no warning!" << std::endl; + tree_node* tmp = alloc_.allocate(1,0); + alloc_.construct(tmp, (*from)); +// kp::constructor(&tmp->data, (*from)); + tmp->first_child=0; + tmp->last_child=0; + if(current_to->prev_sibling==0) { + if(current_to->parent!=0) + current_to->parent->first_child=tmp; + } + else { + current_to->prev_sibling->next_sibling=tmp; + } + tmp->prev_sibling=current_to->prev_sibling; + if(current_to->next_sibling==0) { + if(current_to->parent!=0) + current_to->parent->last_child=tmp; + } + else { + current_to->next_sibling->prev_sibling=tmp; + } + tmp->next_sibling=current_to->next_sibling; + tmp->parent=current_to->parent; +// kp::destructor(¤t_to->data); + alloc_.destroy(current_to); + alloc_.deallocate(current_to,1); + current_to=tmp; + + // only at this stage can we fix 'last' + tree_node *last=from.node->next_sibling; + + pre_order_iterator toit=tmp; + // copy all children + do { + assert(current_from!=0); + if(current_from->first_child != 0) { + current_from=current_from->first_child; + toit=append_child(toit, current_from->data); + } + else { + while(current_from->next_sibling==0 && current_from!=start_from) { + current_from=current_from->parent; + toit=parent(toit); + assert(current_from!=0); + } + current_from=current_from->next_sibling; + if(current_from!=last) { + toit=append_child(parent(toit), current_from->data); + } + } + } while(current_from!=last); + + return current_to; + } + +template +typename tree::sibling_iterator tree::replace( + sibling_iterator orig_begin, + sibling_iterator orig_end, + sibling_iterator new_begin, + sibling_iterator new_end) + { + tree_node *orig_first=orig_begin.node; + tree_node *new_first=new_begin.node; + tree_node *orig_last=orig_first; + while((++orig_begin)!=orig_end) + orig_last=orig_last->next_sibling; + tree_node *new_last=new_first; + while((++new_begin)!=new_end) + new_last=new_last->next_sibling; + + // insert all siblings in new_first..new_last before orig_first + bool first=true; + pre_order_iterator ret; + while(1==1) { + pre_order_iterator tt=insert_subtree(pre_order_iterator(orig_first), pre_order_iterator(new_first)); + if(first) { + ret=tt; + first=false; + } + if(new_first==new_last) + break; + new_first=new_first->next_sibling; + } + + // erase old range of siblings + bool last=false; + tree_node *next=orig_first; + while(1==1) { + if(next==orig_last) + last=true; + next=next->next_sibling; + erase((pre_order_iterator)orig_first); + if(last) + break; + orig_first=next; + } + return ret; + } + +template +template +iter tree::flatten(iter position) + { + if(position.node->first_child==0) + return position; + + tree_node *tmp=position.node->first_child; + while(tmp) { + tmp->parent=position.node->parent; + tmp=tmp->next_sibling; + } + if(position.node->next_sibling) { + position.node->last_child->next_sibling=position.node->next_sibling; + position.node->next_sibling->prev_sibling=position.node->last_child; + } + else { + position.node->parent->last_child=position.node->last_child; + } + position.node->next_sibling=position.node->first_child; + position.node->next_sibling->prev_sibling=position.node; + position.node->first_child=0; + position.node->last_child=0; + + return position; + } + + +template +template +iter tree::reparent(iter position, sibling_iterator begin, sibling_iterator end) + { + tree_node *first=begin.node; + tree_node *last=first; + + assert(first!=position.node); + + if(begin==end) return begin; + // determine last node + while((++begin)!=end) { + last=last->next_sibling; + } + // move subtree + if(first->prev_sibling==0) { + first->parent->first_child=last->next_sibling; + } + else { + first->prev_sibling->next_sibling=last->next_sibling; + } + if(last->next_sibling==0) { + last->parent->last_child=first->prev_sibling; + } + else { + last->next_sibling->prev_sibling=first->prev_sibling; + } + if(position.node->first_child==0) { + position.node->first_child=first; + position.node->last_child=last; + first->prev_sibling=0; + } + else { + position.node->last_child->next_sibling=first; + first->prev_sibling=position.node->last_child; + position.node->last_child=last; + } + last->next_sibling=0; + + tree_node *pos=first; + for(;;) { + pos->parent=position.node; + if(pos==last) break; + pos=pos->next_sibling; + } + + return first; + } + +template +template iter tree::reparent(iter position, iter from) + { + if(from.node->first_child==0) return position; + return reparent(position, from.node->first_child, end(from)); + } + +template +template iter tree::wrap(iter position, const T& x) + { + assert(position.node!=0); + sibling_iterator fr=position, to=position; + ++to; + iter ret = insert(position, x); + reparent(ret, fr, to); + return ret; + } + +template +template iter tree::move_after(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->next_sibling) + if(dst->next_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->next_sibling!=0) dst->next_sibling->prev_sibling=src; + else dst->parent->last_child=src; + src->next_sibling=dst->next_sibling; + dst->next_sibling=src; + src->prev_sibling=dst; + src->parent=dst->parent; + return src; + } + +template +template iter tree::move_before(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + if(dst->prev_sibling) + if(dst->prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst->prev_sibling!=0) dst->prev_sibling->next_sibling=src; + else dst->parent->first_child=src; + src->prev_sibling=dst->prev_sibling; + dst->prev_sibling=src; + src->next_sibling=dst; + src->parent=dst->parent; + return src; + } + +// specialisation for sibling_iterators +template +typename tree::sibling_iterator tree::move_before(sibling_iterator target, + sibling_iterator source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + tree_node *dst_prev_sibling; + if(dst==0) { // must then be an end iterator + dst_prev_sibling=target.parent_->last_child; + assert(dst_prev_sibling); + } + else dst_prev_sibling=dst->prev_sibling; + assert(src); + + if(dst==src) return source; + if(dst_prev_sibling) + if(dst_prev_sibling==src) // already in the right spot + return source; + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(dst_prev_sibling!=0) dst_prev_sibling->next_sibling=src; + else target.parent_->first_child=src; + src->prev_sibling=dst_prev_sibling; + if(dst) { + dst->prev_sibling=src; + src->parent=dst->parent; + } + src->next_sibling=dst; + return src; + } + +template +template iter tree::move_ontop(iter target, iter source) + { + tree_node *dst=target.node; + tree_node *src=source.node; + assert(dst); + assert(src); + + if(dst==src) return source; + +// if(dst==src->prev_sibling) { +// +// } + + // remember connection points + tree_node *b_prev_sibling=dst->prev_sibling; + tree_node *b_next_sibling=dst->next_sibling; + tree_node *b_parent=dst->parent; + + // remove target + erase(target); + + // take src out of the tree + if(src->prev_sibling!=0) src->prev_sibling->next_sibling=src->next_sibling; + else src->parent->first_child=src->next_sibling; + if(src->next_sibling!=0) src->next_sibling->prev_sibling=src->prev_sibling; + else src->parent->last_child=src->prev_sibling; + + // connect it to the new point + if(b_prev_sibling!=0) b_prev_sibling->next_sibling=src; + else b_parent->first_child=src; + if(b_next_sibling!=0) b_next_sibling->prev_sibling=src; + else b_parent->last_child=src; + src->prev_sibling=b_prev_sibling; + src->next_sibling=b_next_sibling; + src->parent=b_parent; + return src; + } + +template +void tree::merge(sibling_iterator to1, sibling_iterator to2, + sibling_iterator from1, sibling_iterator from2, + bool duplicate_leaves) + { + sibling_iterator fnd; + while(from1!=from2) { + if((fnd=std::find(to1, to2, (*from1))) != to2) { // element found + if(from1.begin()==from1.end()) { // full depth reached + if(duplicate_leaves) + append_child(parent(to1), (*from1)); + } + else { // descend further + merge(fnd.begin(), fnd.end(), from1.begin(), from1.end(), duplicate_leaves); + } + } + else { // element missing + insert_subtree(to2, from1); + } + ++from1; + } + } + + +template +void tree::sort(sibling_iterator from, sibling_iterator to, bool deep) + { + std::less comp; + sort(from, to, comp, deep); + } + +template +template +void tree::sort(sibling_iterator from, sibling_iterator to, + StrictWeakOrdering comp, bool deep) + { + if(from==to) return; + // make list of sorted nodes + // CHECK: if multiset stores equivalent nodes in the order in which they + // are inserted, then this routine should be called 'stable_sort'. + std::multiset > nodes(comp); + sibling_iterator it=from, it2=to; + while(it != to) { + nodes.insert(it.node); + ++it; + } + // reassemble + --it2; + + // prev and next are the nodes before and after the sorted range + tree_node *prev=from.node->prev_sibling; + tree_node *next=it2.node->next_sibling; + typename std::multiset >::iterator nit=nodes.begin(), eit=nodes.end(); + if(prev==0) { + if((*nit)->parent!=0) // to catch "sorting the head" situations, when there is no parent + (*nit)->parent->first_child=(*nit); + } + else prev->next_sibling=(*nit); + + --eit; + while(nit!=eit) { + (*nit)->prev_sibling=prev; + if(prev) + prev->next_sibling=(*nit); + prev=(*nit); + ++nit; + } + // prev now points to the last-but-one node in the sorted range + if(prev) + prev->next_sibling=(*eit); + + // eit points to the last node in the sorted range. + (*eit)->next_sibling=next; + (*eit)->prev_sibling=prev; // missed in the loop above + if(next==0) { + if((*eit)->parent!=0) // to catch "sorting the head" situations, when there is no parent + (*eit)->parent->last_child=(*eit); + } + else next->prev_sibling=(*eit); + + if(deep) { // sort the children of each node too + sibling_iterator bcs(*nodes.begin()); + sibling_iterator ecs(*eit); + ++ecs; + while(bcs!=ecs) { + sort(begin(bcs), end(bcs), comp, deep); + ++bcs; + } + } + } + +template +template +bool tree::equal(const iter& one_, const iter& two, const iter& three_) const + { + std::equal_to comp; + return equal(one_, two, three_, comp); + } + +template +template +bool tree::equal_subtree(const iter& one_, const iter& two_) const + { + std::equal_to comp; + return equal_subtree(one_, two_, comp); + } + +template +template +bool tree::equal(const iter& one_, const iter& two, const iter& three_, BinaryPredicate fun) const + { + pre_order_iterator one(one_), three(three_); + +// if(one==two && is_valid(three) && three.number_of_children()!=0) +// return false; + while(one!=two && is_valid(three)) { + if(!fun(*one,*three)) + return false; + if(one.number_of_children()!=three.number_of_children()) + return false; + ++one; + ++three; + } + return true; + } + +template +template +bool tree::equal_subtree(const iter& one_, const iter& two_, BinaryPredicate fun) const + { + pre_order_iterator one(one_), two(two_); + + if(!fun(*one,*two)) return false; + if(number_of_children(one)!=number_of_children(two)) return false; + return equal(begin(one),end(one),begin(two),fun); + } + +template +tree tree::subtree(sibling_iterator from, sibling_iterator to) const + { + tree tmp; + tmp.set_head(value_type()); + tmp.replace(tmp.begin(), tmp.end(), from, to); + return tmp; + } + +template +void tree::subtree(tree& tmp, sibling_iterator from, sibling_iterator to) const + { + tmp.set_head(value_type()); + tmp.replace(tmp.begin(), tmp.end(), from, to); + } + +template +size_t tree::size() const + { + size_t i=0; + pre_order_iterator it=begin(), eit=end(); + while(it!=eit) { + ++i; + ++it; + } + return i; + } + +template +size_t tree::size(const iterator_base& top) const + { + size_t i=0; + pre_order_iterator it=top, eit=top; + eit.skip_children(); + ++eit; + while(it!=eit) { + ++i; + ++it; + } + return i; + } + +template +bool tree::empty() const + { + pre_order_iterator it=begin(), eit=end(); + return (it==eit); + } + +template +int tree::depth(const iterator_base& it) + { + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0) { + pos=pos->parent; + ++ret; + } + return ret; + } + +template +int tree::depth(const iterator_base& it, const iterator_base& root) + { + tree_node* pos=it.node; + assert(pos!=0); + int ret=0; + while(pos->parent!=0 && pos!=root.node) { + pos=pos->parent; + ++ret; + } + return ret; + } + +template +int tree::max_depth() const + { + int maxd=-1; + for(tree_node *it = head->next_sibling; it!=feet; it=it->next_sibling) + maxd=std::max(maxd, max_depth(it)); + + return maxd; + } + + +template +int tree::max_depth(const iterator_base& pos) const + { + tree_node *tmp=pos.node; + + if(tmp==0 || tmp==head || tmp==feet) return -1; + + int curdepth=0, maxdepth=0; + while(true) { // try to walk the bottom of the tree + while(tmp->first_child==0) { + if(tmp==pos.node) return maxdepth; + if(tmp->next_sibling==0) { + // try to walk up and then right again + do { + tmp=tmp->parent; + if(tmp==0) return maxdepth; + --curdepth; + } while(tmp->next_sibling==0); + } + if(tmp==pos.node) return maxdepth; + tmp=tmp->next_sibling; + } + tmp=tmp->first_child; + ++curdepth; + maxdepth=std::max(curdepth, maxdepth); + } + } + +template +unsigned int tree::number_of_children(const iterator_base& it) + { + tree_node *pos=it.node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; +// while(pos!=it.node->last_child) { +// ++ret; +// pos=pos->next_sibling; +// } + while((pos=pos->next_sibling)) + ++ret; + return ret; + } + +template +unsigned int tree::number_of_siblings(const iterator_base& it) const + { + tree_node *pos=it.node; + unsigned int ret=0; + // count forward + while(pos->next_sibling && + pos->next_sibling!=head && + pos->next_sibling!=feet) { + ++ret; + pos=pos->next_sibling; + } + // count backward + pos=it.node; + while(pos->prev_sibling && + pos->prev_sibling!=head && + pos->prev_sibling!=feet) { + ++ret; + pos=pos->prev_sibling; + } + + return ret; + } + +template +void tree::swap(sibling_iterator it) + { + tree_node *nxt=it.node->next_sibling; + if(nxt) { + if(it.node->prev_sibling) + it.node->prev_sibling->next_sibling=nxt; + else + it.node->parent->first_child=nxt; + nxt->prev_sibling=it.node->prev_sibling; + tree_node *nxtnxt=nxt->next_sibling; + if(nxtnxt) + nxtnxt->prev_sibling=it.node; + else + it.node->parent->last_child=it.node; + nxt->next_sibling=it.node; + it.node->prev_sibling=nxt; + it.node->next_sibling=nxtnxt; + } + } + +template +void tree::swap(iterator one, iterator two) + { + // if one and two are adjacent siblings, use the sibling swap + if(one.node->next_sibling==two.node) swap(one); + else if(two.node->next_sibling==one.node) swap(two); + else { + tree_node *nxt1=one.node->next_sibling; + tree_node *nxt2=two.node->next_sibling; + tree_node *pre1=one.node->prev_sibling; + tree_node *pre2=two.node->prev_sibling; + tree_node *par1=one.node->parent; + tree_node *par2=two.node->parent; + + // reconnect + one.node->parent=par2; + one.node->next_sibling=nxt2; + if(nxt2) nxt2->prev_sibling=one.node; + else par2->last_child=one.node; + one.node->prev_sibling=pre2; + if(pre2) pre2->next_sibling=one.node; + else par2->first_child=one.node; + + two.node->parent=par1; + two.node->next_sibling=nxt1; + if(nxt1) nxt1->prev_sibling=two.node; + else par1->last_child=two.node; + two.node->prev_sibling=pre1; + if(pre1) pre1->next_sibling=two.node; + else par1->first_child=two.node; + } + } + +// template +// tree::iterator tree::find_subtree( +// sibling_iterator subfrom, sibling_iterator subto, iterator from, iterator to, +// BinaryPredicate fun) const +// { +// assert(1==0); // this routine is not finished yet. +// while(from!=to) { +// if(fun(*subfrom, *from)) { +// +// } +// } +// return to; +// } + +template +bool tree::is_in_subtree(const iterator_base& it, const iterator_base& begin, + const iterator_base& end) const + { + // FIXME: this should be optimised. + pre_order_iterator tmp=begin; + while(tmp!=end) { + if(tmp==it) return true; + ++tmp; + } + return false; + } + +template +bool tree::is_valid(const iterator_base& it) const + { + if(it.node==0 || it.node==feet || it.node==head) return false; + else return true; + } + +template +typename tree::iterator tree::lowest_common_ancestor( + const iterator_base& one, const iterator_base& two) const + { + std::set parents; + + // Walk up from 'one' storing all parents. + iterator walk=one; + do { + walk=parent(walk); + parents.insert(walk); + } while( is_valid(parent(walk)) ); + + // Walk up from 'two' until we encounter a node in parents. + walk=two; + do { + walk=parent(walk); + if(parents.find(walk) != parents.end()) break; + } while( is_valid(parent(walk)) ); + + return walk; + } + +template +unsigned int tree::index(sibling_iterator it) const + { + unsigned int ind=0; + if(it.node->parent==0) { + while(it.node->prev_sibling!=head) { + it.node=it.node->prev_sibling; + ++ind; + } + } + else { + while(it.node->prev_sibling!=0) { + it.node=it.node->prev_sibling; + ++ind; + } + } + return ind; + } + +template +typename tree::sibling_iterator tree::sibling(const iterator_base& it, unsigned int num) + { + tree_node *tmp; + if(it.node->parent==0) { + tmp=head->next_sibling; + while(num) { + tmp = tmp->next_sibling; + --num; + } + } + else { + tmp=it.node->parent->first_child; + while(num) { + assert(tmp!=0); + tmp = tmp->next_sibling; + --num; + } + } + return tmp; + } + +template +void tree::debug_verify_consistency() const + { + iterator it=begin(); + while(it!=end()) { + if(it.node->parent!=0) { + if(it.node->prev_sibling==0) + assert(it.node->parent->first_child==it.node); + else + assert(it.node->prev_sibling->next_sibling==it.node); + if(it.node->next_sibling==0) + assert(it.node->parent->last_child==it.node); + else + assert(it.node->next_sibling->prev_sibling==it.node); + } + ++it; + } + } + +template +typename tree::sibling_iterator tree::child(const iterator_base& it, unsigned int num) + { + tree_node *tmp=it.node->first_child; + while(num--) { + assert(tmp!=0); + tmp=tmp->next_sibling; + } + return tmp; + } + + + + +// Iterator base + +template +tree::iterator_base::iterator_base() + : node(0), skip_current_children_(false) + { + } + +template +tree::iterator_base::iterator_base(tree_node *tn) + : node(tn), skip_current_children_(false) + { + } + +template +T& tree::iterator_base::operator*() const + { + return node->data; + } + +template +T* tree::iterator_base::operator->() const + { + return &(node->data); + } + +template +bool tree::post_order_iterator::operator!=(const post_order_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::post_order_iterator::operator==(const post_order_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::pre_order_iterator::operator!=(const pre_order_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::pre_order_iterator::operator==(const pre_order_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::sibling_iterator::operator!=(const sibling_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::sibling_iterator::operator==(const sibling_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +bool tree::leaf_iterator::operator!=(const leaf_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::leaf_iterator::operator==(const leaf_iterator& other) const + { + if(other.node==this->node && other.top_node==this->top_node) return true; + else return false; + } + +template +typename tree::sibling_iterator tree::iterator_base::begin() const + { + if(node->first_child==0) + return end(); + + sibling_iterator ret(node->first_child); + ret.parent_=this->node; + return ret; + } + +template +typename tree::sibling_iterator tree::iterator_base::end() const + { + sibling_iterator ret(0); + ret.parent_=node; + return ret; + } + +template +void tree::iterator_base::skip_children() + { + skip_current_children_=true; + } + +template +void tree::iterator_base::skip_children(bool skip) + { + skip_current_children_=skip; + } + +template +unsigned int tree::iterator_base::number_of_children() const + { + tree_node *pos=node->first_child; + if(pos==0) return 0; + + unsigned int ret=1; + while(pos!=node->last_child) { + ++ret; + pos=pos->next_sibling; + } + return ret; + } + + + +// Pre-order iterator + +template +tree::pre_order_iterator::pre_order_iterator() + : iterator_base(0) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(tree_node *tn) + : iterator_base(tn) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(const iterator_base &other) + : iterator_base(other.node) + { + } + +template +tree::pre_order_iterator::pre_order_iterator(const sibling_iterator& other) + : iterator_base(other.node) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + this->skip_children(); + ++(*this); + } + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator++() + { + assert(this->node!=0); + if(!this->skip_current_children_ && this->node->first_child != 0) { + this->node=this->node->first_child; + } + else { + this->skip_current_children_=false; + while(this->node->next_sibling==0) { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + this->node=this->node->next_sibling; + } + return *this; + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator--() + { + assert(this->node!=0); + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + } + else { + this->node=this->node->parent; + if(this->node==0) + return *this; + } + return *this; +} + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator++(int) + { + pre_order_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::pre_order_iterator tree::pre_order_iterator::operator--(int) +{ + pre_order_iterator copy = *this; + --(*this); + return copy; +} + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::pre_order_iterator& tree::pre_order_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + + + +// Post-order iterator + +template +tree::post_order_iterator::post_order_iterator() + : iterator_base(0) + { + } + +template +tree::post_order_iterator::post_order_iterator(tree_node *tn) + : iterator_base(tn) + { + } + +template +tree::post_order_iterator::post_order_iterator(const iterator_base &other) + : iterator_base(other.node) + { + } + +template +tree::post_order_iterator::post_order_iterator(const sibling_iterator& other) + : iterator_base(other.node) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + this->skip_children(); + ++(*this); + } + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator++() + { + assert(this->node!=0); + if(this->node->next_sibling==0) { + this->node=this->node->parent; + this->skip_current_children_=false; + } + else { + this->node=this->node->next_sibling; + if(this->skip_current_children_) { + this->skip_current_children_=false; + } + else { + while(this->node->first_child) + this->node=this->node->first_child; + } + } + return *this; + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator--() + { + assert(this->node!=0); + if(this->skip_current_children_ || this->node->last_child==0) { + this->skip_current_children_=false; + while(this->node->prev_sibling==0) + this->node=this->node->parent; + this->node=this->node->prev_sibling; + } + else { + this->node=this->node->last_child; + } + return *this; + } + +template +typename tree::post_order_iterator tree::post_order_iterator::operator++(int) + { + post_order_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::post_order_iterator tree::post_order_iterator::operator--(int) + { + post_order_iterator copy = *this; + --(*this); + return copy; + } + + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::post_order_iterator& tree::post_order_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +template +void tree::post_order_iterator::descend_all() + { + assert(this->node!=0); + while(this->node->first_child) + this->node=this->node->first_child; + } + + +// Breadth-first iterator + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator() + : iterator_base() + { + } + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(tree_node *tn) + : iterator_base(tn) + { + traversal_queue.push(tn); + } + +template +tree::breadth_first_queued_iterator::breadth_first_queued_iterator(const iterator_base& other) + : iterator_base(other.node) + { + traversal_queue.push(other.node); + } + +template +bool tree::breadth_first_queued_iterator::operator!=(const breadth_first_queued_iterator& other) const + { + if(other.node!=this->node) return true; + else return false; + } + +template +bool tree::breadth_first_queued_iterator::operator==(const breadth_first_queued_iterator& other) const + { + if(other.node==this->node) return true; + else return false; + } + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator++() + { + assert(this->node!=0); + + // Add child nodes and pop current node + sibling_iterator sib=this->begin(); + while(sib!=this->end()) { + traversal_queue.push(sib.node); + ++sib; + } + traversal_queue.pop(); + if(traversal_queue.size()>0) + this->node=traversal_queue.front(); + else + this->node=0; + return (*this); + } + +template +typename tree::breadth_first_queued_iterator tree::breadth_first_queued_iterator::operator++(int) + { + breadth_first_queued_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::breadth_first_queued_iterator& tree::breadth_first_queued_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + + + +// Fixed depth iterator + +template +tree::fixed_depth_iterator::fixed_depth_iterator() + : iterator_base() + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(tree_node *tn) + : iterator_base(tn), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const iterator_base& other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const sibling_iterator& other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::fixed_depth_iterator::fixed_depth_iterator(const fixed_depth_iterator& other) + : iterator_base(other.node), top_node(other.top_node) + { + } + +template +bool tree::fixed_depth_iterator::operator==(const fixed_depth_iterator& other) const + { + if(other.node==this->node && other.top_node==top_node) return true; + else return false; + } + +template +bool tree::fixed_depth_iterator::operator!=(const fixed_depth_iterator& other) const + { + if(other.node!=this->node || other.top_node!=top_node) return true; + else return false; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator++() + { + assert(this->node!=0); + + if(this->node->next_sibling) { + this->node=this->node->next_sibling; + } + else { + int relative_depth=0; + upper: + do { + if(this->node==this->top_node) { + this->node=0; // FIXME: return a proper fixed_depth end iterator once implemented + return *this; + } + this->node=this->node->parent; + if(this->node==0) return *this; + --relative_depth; + } while(this->node->next_sibling==0); + lower: + this->node=this->node->next_sibling; + while(this->node->first_child==0) { + if(this->node->next_sibling==0) + goto upper; + this->node=this->node->next_sibling; + if(this->node==0) return *this; + } + while(relative_depth<0 && this->node->first_child!=0) { + this->node=this->node->first_child; + ++relative_depth; + } + if(relative_depth<0) { + if(this->node->next_sibling==0) goto upper; + else goto lower; + } + } + return *this; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator--() + { + assert(this->node!=0); + + if(this->node->prev_sibling) { + this->node=this->node->prev_sibling; + } + else { + int relative_depth=0; + upper: + do { + if(this->node==this->top_node) { + this->node=0; + return *this; + } + this->node=this->node->parent; + if(this->node==0) return *this; + --relative_depth; + } while(this->node->prev_sibling==0); + lower: + this->node=this->node->prev_sibling; + while(this->node->last_child==0) { + if(this->node->prev_sibling==0) + goto upper; + this->node=this->node->prev_sibling; + if(this->node==0) return *this; + } + while(relative_depth<0 && this->node->last_child!=0) { + this->node=this->node->last_child; + ++relative_depth; + } + if(relative_depth<0) { + if(this->node->prev_sibling==0) goto upper; + else goto lower; + } + } + return *this; + +// +// +// assert(this->node!=0); +// if(this->node->prev_sibling!=0) { +// this->node=this->node->prev_sibling; +// assert(this->node!=0); +// if(this->node->parent==0 && this->node->prev_sibling==0) // head element +// this->node=0; +// } +// else { +// tree_node *par=this->node->parent; +// do { +// par=par->prev_sibling; +// if(par==0) { // FIXME: need to keep track of this! +// this->node=0; +// return *this; +// } +// } while(par->last_child==0); +// this->node=par->last_child; +// } +// return *this; + } + +template +typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator++(int) + { + fixed_depth_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::fixed_depth_iterator tree::fixed_depth_iterator::operator--(int) + { + fixed_depth_iterator copy = *this; + --(*this); + return copy; + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --(num); + } + return (*this); + } + +template +typename tree::fixed_depth_iterator& tree::fixed_depth_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --(num); + } + return *this; + } + + +// Sibling iterator + +template +tree::sibling_iterator::sibling_iterator() + : iterator_base() + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(tree_node *tn) + : iterator_base(tn) + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(const iterator_base& other) + : iterator_base(other.node) + { + set_parent_(); + } + +template +tree::sibling_iterator::sibling_iterator(const sibling_iterator& other) + : iterator_base(other), parent_(other.parent_) + { + } + +template +void tree::sibling_iterator::set_parent_() + { + parent_=0; + if(this->node==0) return; + if(this->node->parent!=0) + parent_=this->node->parent; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator++() + { + if(this->node) + this->node=this->node->next_sibling; + return *this; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator--() + { + if(this->node) this->node=this->node->prev_sibling; + else { + assert(parent_); + this->node=parent_->last_child; + } + return *this; +} + +template +typename tree::sibling_iterator tree::sibling_iterator::operator++(int) + { + sibling_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::sibling_iterator tree::sibling_iterator::operator--(int) + { + sibling_iterator copy = *this; + --(*this); + return copy; + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::sibling_iterator& tree::sibling_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +template +typename tree::tree_node *tree::sibling_iterator::range_first() const + { + tree_node *tmp=parent_->first_child; + return tmp; + } + +template +typename tree::tree_node *tree::sibling_iterator::range_last() const + { + return parent_->last_child; + } + +// Leaf iterator + +template +tree::leaf_iterator::leaf_iterator() + : iterator_base(0), top_node(0) + { + } + +template +tree::leaf_iterator::leaf_iterator(tree_node *tn, tree_node *top) + : iterator_base(tn), top_node(top) + { + } + +template +tree::leaf_iterator::leaf_iterator(const iterator_base &other) + : iterator_base(other.node), top_node(0) + { + } + +template +tree::leaf_iterator::leaf_iterator(const sibling_iterator& other) + : iterator_base(other.node), top_node(0) + { + if(this->node==0) { + if(other.range_last()!=0) + this->node=other.range_last(); + else + this->node=other.parent_; + ++(*this); + } + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator++() + { + assert(this->node!=0); + if(this->node->first_child!=0) { // current node is no longer leaf (children got added) + while(this->node->first_child) + this->node=this->node->first_child; + } + else { + while(this->node->next_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node != 0 && this->node==top_node) return *this; + } + this->node=this->node->next_sibling; + while(this->node->first_child) + this->node=this->node->first_child; + } + return *this; + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator--() + { + assert(this->node!=0); + while (this->node->prev_sibling==0) { + if (this->node->parent==0) return *this; + this->node=this->node->parent; + if (top_node !=0 && this->node==top_node) return *this; + } + this->node=this->node->prev_sibling; + while(this->node->last_child) + this->node=this->node->last_child; + return *this; + } + +template +typename tree::leaf_iterator tree::leaf_iterator::operator++(int) + { + leaf_iterator copy = *this; + ++(*this); + return copy; + } + +template +typename tree::leaf_iterator tree::leaf_iterator::operator--(int) + { + leaf_iterator copy = *this; + --(*this); + return copy; + } + + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator+=(unsigned int num) + { + while(num>0) { + ++(*this); + --num; + } + return (*this); + } + +template +typename tree::leaf_iterator& tree::leaf_iterator::operator-=(unsigned int num) + { + while(num>0) { + --(*this); + --num; + } + return (*this); + } + +#endif + +// Local variables: +// default-tab-width: 3 +// End: diff --git a/3rdparty/minigzip/minigzip.c b/3rdparty/minigzip/minigzip.c new file mode 100755 index 000000000..9f4292e14 --- /dev/null +++ b/3rdparty/minigzip/minigzip.c @@ -0,0 +1,317 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2006, 2010, 2011, 2016 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* Copyright notice from zlib.h: + zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.11, January 15th, 2017 + + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id$ */ + +#include "zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1900 +# define snprintf _snprintf +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +static char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); +#else + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); +#endif + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + unsigned len = strlen(file); + + if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(buf, sizeof(buf), "%s", file); +#else + strcpy(buf, file); +#endif + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); +#else + strcat(infile, GZ_SUFFIX); +#endif + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + diff --git a/3rdparty/patch-configs.py b/3rdparty/patch-configs.py new file mode 100644 index 000000000..d2b1503f2 --- /dev/null +++ b/3rdparty/patch-configs.py @@ -0,0 +1,23 @@ +# Patch Qwt and Qwtplot3D configurations to fit into SciDAVis/Windows build process + +qwt_conf = "qwt/qwtconfig.pri" +qwtplot3d_conf = "qwtplot3d/qwtplot3d.pro" + +# patch Qwt config file +with open(qwt_conf, 'r') as file: + content = file.readlines() +with open (qwt_conf, 'w') as file: + for line in content: + if ("QwtDll" in line or "QwtWidgets" in line or "QwtDesigner" in line) and line[0] != '#': + file.write("#") + file.write(line) + +# patch Qwtplot3D config file +with open(qwtplot3d_conf, 'r') as file: + content = file.readlines() +with open(qwtplot3d_conf, 'w') as file: + for line in content: + if ("vclib" in line or "DESTDIR" in line) and line[0] != '#': + file.write("#") + file.write(line.replace("debug", "release")) + file.write("\nDESTDIR = ../../output\n") diff --git a/makeDist.sh b/makeDist.sh index 3069f60eb..db569cfc8 100644 --- a/makeDist.sh +++ b/makeDist.sh @@ -7,15 +7,4 @@ else name=scidavis-$version~$extra fi -git archive --format=tar --prefix=$name/ HEAD -o $name.tar - -# add submodules -git submodule update --init --recursive -git submodule|cut -f3 -d' '|while read s; do - pushd $s - git archive --format=tar --prefix=$name/$s/ HEAD -o /tmp/$$.tar - popd - tar Af $name.tar /tmp/$$.tar -done -gzip -f $name.tar -rm /tmp/$$.tar +git archive --format=tar.gz --prefix=$name/ HEAD -o $name.tar.gz