From: rnv Date: Mon, 26 Oct 2015 12:40:52 +0000 (+0300) Subject: Implementation of the "0023167: [CEA 1592] JSON ParaView reader" issue. X-Git-Tag: V8_0_pre~1 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=5565ef9400614283ee2f1c63c99a60463f893a78;p=modules%2Fparavis.git Implementation of the "0023167: [CEA 1592] JSON ParaView reader" issue. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ec42e80..4aed0ec8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,8 @@ CMAKE_DEPENDENT_OPTION(SALOME_LIGHT_ONLY "Build SALOME Light only (no CORBA)" OF IF(SALOME_BUILD_TESTS) ENABLE_TESTING() + FIND_PACKAGE(SalomeCppUnit) + SALOME_LOG_OPTIONAL_PACKAGE(CppUnit SALOME_BUILD_TESTS) ENDIF() # Prerequisites diff --git a/src/Plugins/CMakeLists.txt b/src/Plugins/CMakeLists.txt index ba04a76b..20310a07 100755 --- a/src/Plugins/CMakeLists.txt +++ b/src/Plugins/CMakeLists.txt @@ -34,6 +34,7 @@ SET(_subdirs EllipseBuilder DifferenceTimesteps ArrayRenamer + JSONReader ) IF(NOT SALOME_LIGHT_ONLY) diff --git a/src/Plugins/JSONReader/CMakeLists.txt b/src/Plugins/JSONReader/CMakeLists.txt new file mode 100644 index 00000000..163fef31 --- /dev/null +++ b/src/Plugins/JSONReader/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2015 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# Author : Roman NIKOLAEV + +PROJECT(JSONReader) + +cmake_minimum_required(VERSION 2.8) + +# Find ParaView +FIND_PACKAGE(ParaView REQUIRED) +INCLUDE(${PARAVIEW_USE_FILE}) + +# Standard CMake option for building libraries shared or static by default. +OPTION(BUILD_SHARED_LIBS "Build with shared libraries" ${VTK_BUILD_SHARED_LIBS}) + +# Add subdirectories +ADD_SUBDIRECTORY(JSONParser) +ADD_SUBDIRECTORY(ParaViewPlugin) +IF(SALOME_BUILD_TESTS) + ENABLE_TESTING() + ADD_SUBDIRECTORY(Test) +ENDIF() \ No newline at end of file diff --git a/src/Plugins/JSONReader/Examples/example1.json b/src/Plugins/JSONReader/Examples/example1.json new file mode 100644 index 00000000..db0edfcf --- /dev/null +++ b/src/Plugins/JSONReader/Examples/example1.json @@ -0,0 +1,32 @@ +{ + "_metadata": { + "_comment": "", + "table_name": "Short name of the table", + "table_description": "A somewhat longer description for the table", + + "short_names": ["P", "u", "weight" ], + "long_names": [ "Pressure", "Velocity", "Total weight" ], + "units": [ "Pa", "m/s", "kg" ], + "date" : "12/09/2015" + }, + + "items": [ + { + "P":3.15, + "u": 0.0, + "weight": 43.5 + }, + + { + "P": 3.15, + "u": 0.0, + "weight": 43.5 + }, + + { + "P": 3.15, + "u": 0.0, + "weight": 43.5 + } + ] +} \ No newline at end of file diff --git a/src/Plugins/JSONReader/Examples/example1_wo_metadata.json b/src/Plugins/JSONReader/Examples/example1_wo_metadata.json new file mode 100644 index 00000000..ad7bf545 --- /dev/null +++ b/src/Plugins/JSONReader/Examples/example1_wo_metadata.json @@ -0,0 +1,22 @@ +{ + + "items": [ + { + "P":3.15, + "u": 0.0, + "weight": 43.5 + }, + + { + "P": 3.15, + "u": 0.0, + "weight": 43.5 + }, + + { + "P": 3.15, + "u": 0.0, + "weight": 43.5 + } + ] +} \ No newline at end of file diff --git a/src/Plugins/JSONReader/Examples/example2.json b/src/Plugins/JSONReader/Examples/example2.json new file mode 100644 index 00000000..55d17e87 --- /dev/null +++ b/src/Plugins/JSONReader/Examples/example2.json @@ -0,0 +1,32 @@ +{ + "_metadata": { + "_comment": "", + "table_name": "Short name of the table", + "table_description": "A somewhat longer description for the table", + + "short_names": ["P", "u", "weight"], + "long_names": ["Pressure", "Velocity", "Total weight"], + "date" : "12/12/12", + "units": ["Pa", "m/s", "kg"] + }, + + "item1" : { + "P": 3.15, + "u": 0.0, + "weight": 43.5 + }, + + "item2" : + { + "P": 3.15, + "u": 0.0, + "weight": 43.5 + }, + + "item3" : + { + "P": 3.15, + "u": 0.0, + "weight": 43.5 + } +} diff --git a/src/Plugins/JSONReader/Examples/example2_wo_metadata.json b/src/Plugins/JSONReader/Examples/example2_wo_metadata.json new file mode 100644 index 00000000..d52cea5f --- /dev/null +++ b/src/Plugins/JSONReader/Examples/example2_wo_metadata.json @@ -0,0 +1,22 @@ +{ + + "item1" : { + "P": 3.15, + "u": 0.0, + "weight": 43.5 + }, + + "item2" : + { + "P": 4.156, + "u": 465.0, + "weight": 137.5 + }, + + "item3" : + { + "P": -3.0305890e+4, + "u": 1.0305890e-1, + "weight": -3.0305890e+5 + } +} diff --git a/src/Plugins/JSONReader/JSONParser/CMakeLists.txt b/src/Plugins/JSONReader/JSONParser/CMakeLists.txt new file mode 100644 index 00000000..10f1d0e6 --- /dev/null +++ b/src/Plugins/JSONReader/JSONParser/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# Author: Roman NIKOLAEV + +SET(PARCER_SRCS + vtkJSONParser.cxx) + +ADD_LIBRARY(vtkJSONParser ${PARCER_SRCS}) + +TARGET_LINK_LIBRARIES(vtkJSONParser ${VTK_LIBRARIES}) + +INSTALL( + TARGETS vtkJSONParser + DESTINATION lib/salome) diff --git a/src/Plugins/JSONReader/JSONParser/vtkJSONParser.cxx b/src/Plugins/JSONReader/JSONParser/vtkJSONParser.cxx new file mode 100644 index 00000000..cfbcbdbd --- /dev/null +++ b/src/Plugins/JSONReader/JSONParser/vtkJSONParser.cxx @@ -0,0 +1,807 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author: Roman NIKOLAEV + +#include "vtkJSONParser.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +//DEBUG macro +//#define __DEBUG + + +// Key worlds +#define MD "_metadata" +#define CMT "_comment" +#define TBN "table_name" +#define TBD "table_description" +#define SHT "short_names" +#define LNG "long_names" +#define UNT "units" +#define DT "date" + +// Separators +#define COMMA ',' + +#define COLON ':' + +#define OSB '[' +#define CSB ']' + +#define OCB '{' +#define CCB '}' +#define ENDL '\n' +#define QTS '"' +#define SPS ' ' +#define TAB '\t' + +#define NA "n/a" + + +#define addInfo(info) \ + Info I; \ + I.type = info; \ + I.ln = this->LineNumber; \ + I.cn = this->ColumnNumber; \ + I.pos = ftell(this->File); \ + this->CInfoVector.push_back(I); + +//--------------------------------------------------- +bool isBlankOrEnd(const char c) { + return c == SPS || c == ENDL || c == TAB || c == EOF; +} + +bool isDigitOrDot(const char c) { + return (c >= '.' && c <='9') || c == '+' || c == '-' || c == 'e'; +} + +// Exception +//--------------------------------------------------- +vtkJSONException::vtkJSONException(const char *reason) : Reason(reason) { +} + +//--------------------------------------------------- +vtkJSONException::~vtkJSONException() throw () { +} + +//--------------------------------------------------- +const char* vtkJSONException::what() const throw() { + return Reason.c_str(); +} + +// Containers to store information about nodes: + +// Base node +//--------------------------------------------------- +class vtkJSONNode { +public: + vtkJSONNode() { Name = 0; } + virtual ~vtkJSONNode() { } + const char* GetName() { return this->Name ; } + void SetName(const char* name) { this->Name = name; } +private: + const char* Name; +}; + +class vtkJSONMetaNode : public vtkJSONNode { +public: + vtkJSONMetaNode() : vtkJSONNode() { + this->SetName(MD); + this->Comment = 0; + this->TableName = 0; + this->TableDescription = 0; + this->Date = 0; + } + + virtual ~vtkJSONMetaNode() { + delete this->Comment; this->Comment = 0; + delete this->TableName; this->TableName = 0; + delete this->Date; this->Date= 0; + delete this->TableDescription; this->TableDescription = 0; + for(int i = 0; i < this->ShortNames.size(); i++) { + delete this->ShortNames[i]; this->ShortNames[i] = 0; + } + for(int i = 0; i < this->LongNames.size(); i++) { + delete this->LongNames[i]; this->LongNames[i] = 0; + } + for(int i = 0; i < this->Units.size(); i++) { + delete this->Units[i]; this->Units[i] = 0; + } + } + + void SetComment(const char* comment) { this->Comment = comment; } + const char* GetComment() { return this->Comment; } + + void SetTableName(const char* name) { this->TableName = name; } + const char* GetTableName() { return this->TableName; } + + void SetDate(const char* name) { this->Date = name; } + const char* GetDate() { return this->Date; } + + void SetTableDescription(const char* description) { this->TableDescription = description; } + const char* GetDescription() { return this->TableDescription; } + + void SetShortNames(std::vector names) { this->ShortNames = names; } + std::vector GetShortNames() { return this->ShortNames; } + + void SetLongNames(std::vector names) { this->LongNames = names; } + std::vector GetLongNames() { return this->LongNames; } + + void SetUnits(std::vector units) { this->Units = units; } + std::vector GetUnits() { return this->Units; } + +private: + const char* Comment; + const char* TableName; + const char* TableDescription; + const char* Date; + std::vector ShortNames; + std::vector LongNames; + std::vector Units; +}; + +struct char_cmp { + bool operator () (const char *a, const char *b) const + { + return strcmp(a,b)<0; + } +}; + +typedef std::map vtkJSONMap; + +class vtkJSONInfoNode : public vtkJSONNode { +public: + vtkJSONInfoNode(const char* name) : vtkJSONNode() { + this->SetName(name); + } + virtual ~vtkJSONInfoNode() { + vtkJSONMap::iterator it = this->Values.begin(); + for( ;it != this->Values.end(); it++) { + delete it->first; + const char* c = it->first; + c = 0; + } + } + void AddValue(const char* key, const double value) { + this->Values.insert(std::pair(key,value)); + } + vtkJSONMap& GetValues() { return this->Values; } +private: + vtkJSONMap Values; +}; + + +//--------------------------------------------------- +vtkStandardNewMacro(vtkJSONParser); + +//--------------------------------------------------- +vtkJSONParser::vtkJSONParser() +{ + this->FileName = NULL; + this->LineNumber = 1; + this->ColumnNumber = 0; + this->File = 0; + this->InsideQuotes = false; + this->LastString = 0; + this->CurrentNode = 0; + this->ParseList = false; + this->ParseObjectList = false; + this->LastValue = NAN; + this->ShortNamesFilled = false; +} + +//--------------------------------------------------- +vtkJSONParser::~vtkJSONParser() +{ + delete this->FileName; + this->FileName = 0; +} + + +//--------------------------------------------------- +int vtkJSONParser::Parse(vtkTable* theTable) +{ + if(!this->FileName) { + vtkErrorMacro("The name of the file is not defined"); + return 1; + } + this->File = fopen( this->FileName, "r" ); + + if( !this->File ) { + std::string message = std::string("Can't open file: ") + std::string(this->FileName); + throwSimpleException(message.c_str()); + return 1; + } + char ch = 0; + + this->ExpectedCharacters.push_back(OCB); + + while( ch != EOF ) { + ch = fgetc(this->File); + processCharacter(ch); + if(isDigitsAllowed() && isDigitOrDot(ch)) { + readDoubleValue(); + } + int nb = 1; + switch(ch) { + case OCB: processOCB(); break; + case CCB: processCCB(); break; + + case OSB: processOSB(); break; + case CSB: processCSB(); break; + + case ENDL: processENDL(); nb = 0; break; + + case QTS: processQTS(); break; + + case COLON: processCOLON(); break; + + case COMMA: processCOMMA(); break; + } + this->ColumnNumber+=nb; + } + fclose(this->File); + + if(this->CInfoVector.size() > 0 ) { + throwException("braket is not closed ", + this->CInfoVector.back().ln, + this->CInfoVector.back().cn); + } + + finalize(theTable); + clean(); + return 1; +} + +//--------------------------------------------------- +void vtkJSONParser::finalize( vtkTable *t ) { + std::vector::iterator it = this->Nodes.begin(); + vtkJSONMetaNode* mn = 0; + for( ; it != this->Nodes.end(); it++ ) { + mn = dynamic_cast(*it); + if (mn) + break; + } + std::vector units; + if(mn) { + if(!mn->GetShortNames().empty()) { + this->ShortNames.clear(); + this->ShortNames = mn->GetShortNames(); + } + t->GetInformation()->Set(vtkDataObject::FIELD_NAME(), mn->GetTableName() ? mn->GetTableName() : ""); + units = mn->GetUnits(); + } + + long nbRow = mn ? (this->Nodes.size() - 1 ) : this->Nodes.size(); + for (long col=0; col < this->ShortNames.size(); col++) { + vtkDoubleArray* newCol = vtkDoubleArray::New(); + newCol->SetNumberOfValues(nbRow); + vtkJSONInfoNode* in = 0; + std::string name = this->ShortNames[col]; + name += "["; + if(col < units.size()){ + name += units[col]; + } else { + name += NA; + } + name += "]"; + newCol->SetName(name.c_str()); + it = this->Nodes.begin(); + long row = 0; + for( ; it != this->Nodes.end(); it++ ) { + in = dynamic_cast(*it); + if (in) { + vtkJSONMap& vl = in->GetValues(); + vtkJSONMap::iterator mit = vl.find(this->ShortNames[col]); + if(mit != vl.end()) { + newCol->SetValue(row, mit->second); + vl.erase(mit); + delete mit->first; + const char* c = mit->first; + c = 0; + row++; + } else { + std::string s("Item with name '"); + s+=in->GetName(); + s+="' has not key '"; + s+=this->ShortNames[col]; + s+="' !"; + throwSimpleException(s.c_str()); + } + } + } + t->AddColumn(newCol); + } + it = this->Nodes.begin(); + vtkJSONInfoNode* in = 0; + for( ; it != this->Nodes.end(); it++ ) { + in = dynamic_cast(*it); + if (in) { + vtkJSONMap& vl = in->GetValues(); + if(vl.size() > 0 ) { + std::string s("Item with name '"); + s+=in->GetName(); + s+="' has unexpected key '"; + s+=vl.begin()->first; + s+="' !"; + throwSimpleException(s.c_str()); + } + } + } +} + +//--------------------------------------------------- +void vtkJSONParser::processQTS() { + this->InsideQuotes = !this->InsideQuotes; + if(this->InsideQuotes) { + addInfo(QTS); + } else { + // Quotes is closed, get content + Info i = this->CInfoVector.back(); + this->CInfoVector.pop_back(); + if(i.type == QTS) { + long begin = i.pos; + long end = ftell(this->File) - 1; + this->LastString = getString(begin, end); + bool parse_list = (this->CInfoVector.size() >= 1 && this->CInfoVector.back().type == OSB); + if(parse_list) { + this->CurrentList.push_back(this->LastString); + } else { + this->Strings.push_back(this->LastString); + processMetaNode(); + } +#ifdef __DEBUG + std::cout<<"String : "<LastString<ExpectedCharacters.clear(); + this->ExpectedCharacters.push_back(COLON); + this->ExpectedCharacters.push_back(COMMA); + this->ExpectedCharacters.push_back(CCB); + this->ExpectedCharacters.push_back(CSB); + } + } +} + +//--------------------------------------------------- +void vtkJSONParser::processCOLON() { + if (this->InsideQuotes) + return; + this->ExpectedCharacters.clear(); + this->ExpectedCharacters.push_back(OCB); + this->ExpectedCharacters.push_back(QTS); + this->ExpectedCharacters.push_back(OSB); + if(GetInfoNode() && Strings.size() == 1 ) { + allowsDigits(); + } +} + +//--------------------------------------------------- +void vtkJSONParser::processOCB() { + if (this->InsideQuotes) + return; + this->ExpectedCharacters.clear(); + this->ExpectedCharacters.push_back(QTS); + this->ExpectedCharacters.push_back(CCB); + + // Create node + if(this->CInfoVector.size() >= 1) { + if ( !GetMetaNode() && this->Strings.size() > 0 && + this->Strings.back() && + strcmp(this->Strings.back(), MD) == 0 ) { +#ifdef __DEBUG + std::cout<<"Create new Meta Node !!!"<CurrentNode = new vtkJSONMetaNode(); + delete this->Strings.back(); + this->Strings.back() = 0; + this->Strings.pop_back(); + } else { + if(this->CInfoVector.back().type == OSB ) { + this->ParseObjectList = true; + } +#ifdef __DEBUG + std::cout<<"Create new Node with name '"<<(this->Strings.size() == 0 ? "" : this->Strings.back())<<"' !!!"<CurrentNode = new vtkJSONInfoNode(this->Strings.size() == 0 ? "" : this->Strings.back()); + if(!this->ParseObjectList && this->Strings.size() == 1) { + this->Strings.pop_back(); + } + } + } + addInfo(OCB); +} + +//--------------------------------------------------- +vtkJSONMetaNode* vtkJSONParser::GetMetaNode() { + vtkJSONMetaNode *mnode = 0; + if( this->CurrentNode ) { + mnode = dynamic_cast(this->CurrentNode); + } + return mnode; +} + +//--------------------------------------------------- +vtkJSONInfoNode* vtkJSONParser::GetInfoNode() { + vtkJSONInfoNode *mnode = 0; + if( this->CurrentNode ) { + mnode = dynamic_cast(this->CurrentNode); + } + return mnode; +} + +//--------------------------------------------------- +void vtkJSONParser::processENDL() { + if(this->InsideQuotes) { + + throwException("quote is not closed !"); + } + this->LineNumber++; + this->ColumnNumber=0; +} + + +//--------------------------------------------------- +void vtkJSONParser::processCSB() { + if (this->InsideQuotes) + return; + + if(this->CInfoVector.back().type == OSB) { + if(this->ParseList) { + this->ParseList = false; + } + if(this->ParseObjectList) { + this->ParseObjectList = false; + } + this->CInfoVector.pop_back(); + } + + this->ExpectedCharacters.clear(); + this->ExpectedCharacters.push_back(COMMA); + this->ExpectedCharacters.push_back(OCB); + this->ExpectedCharacters.push_back(CCB); +} + +//--------------------------------------------------- +void vtkJSONParser::processOSB() { + if (this->InsideQuotes) + return; + + if(this->ParseList) { + Info i = CInfoVector.back(); + if(i.type == OSB) { + throwException("list, which has been opened in this place, has not been closed !", i.ln, i.cn); + } + } + if(GetMetaNode()) { + this->ParseList = true; + } else { + if( this->Strings.size() > 0 ) { + delete this->Strings[Strings.size()-1]; + this->Strings[Strings.size()-1] = 0; + this->Strings.pop_back(); + } + } + addInfo(OSB); + this->ExpectedCharacters.clear(); + this->ExpectedCharacters.push_back(QTS); + this->ExpectedCharacters.push_back(OCB); +} + +//--------------------------------------------------- +void vtkJSONParser::processCCB() { + if (this->InsideQuotes) + return; + + this->ExpectedCharacters.clear(); + this->ExpectedCharacters.push_back(COMMA); + this->ExpectedCharacters.push_back(CCB); + if(this->ParseObjectList) { + this->ExpectedCharacters.push_back(CSB); + } + + processMetaNode(); + processInfoNode(); + + if(this->CurrentNode) + this->Nodes.push_back(this->CurrentNode); + if( !this->ShortNamesFilled ){ + vtkJSONInfoNode* n = dynamic_cast(this->CurrentNode); + if(n){ + this->ShortNamesFilled = true; + } + } + +#ifdef __DEBUG + if(this->CurrentNode) + std::cout<<"End parsing node with name '"<CurrentNode->GetName()<<"' !!!!"<CInfoVector.size() > 0 && this->CInfoVector.back().type == OCB ) { + this->CInfoVector.pop_back(); + } else{ + throwException ("unexpected closed braket '}' !"); + } + + this->CurrentNode = 0; +} + +//--------------------------------------------------- +void vtkJSONParser::processCOMMA() { + if (this->InsideQuotes) + return; + this->ExpectedCharacters.clear(); + this->ExpectedCharacters.push_back(QTS); + this->ExpectedCharacters.push_back(OCB); + processMetaNode(); + processInfoNode(); +} + +void vtkJSONParser::processMetaNode() { + vtkJSONMetaNode* mn = GetMetaNode(); + if(mn) { + bool strings = this->Strings.size() == 2 && !this->ParseList; + bool str_and_list = (this->Strings.size() == 1 && this->CurrentList.size() > 0 && !this->ParseList); + + if( strings ) { + if ( strcmp(this->Strings[0], CMT) == 0 ) { + mn->SetComment(this->Strings[1]); +#ifdef __DEBUG + std::cout<<"Table Comment : "<Strings[1]<Strings[0], TBN) == 0 ) { + mn->SetTableName(this->Strings[1]); +#ifdef __DEBUG + std::cout<<"Table Name : "<Strings[1]<Strings[0], TBD) == 0 ) { + mn->SetTableDescription(this->Strings[1]); +#ifdef __DEBUG + std::cout<<"Table Description : "<Strings[1]<Strings[0], DT) == 0 ) { + mn->SetDate(this->Strings[1]); +#ifdef __DEBUG + std::cout<<"Date : "<Strings[1]<FileName; + s << ", line "<LineNumber; + s << " unexpected key world: '"<Strings[0]<<"'"; + } + delete this->Strings[0]; + this->Strings[0] = 0; + Strings.pop_back(); + Strings.pop_back(); + + } else if(str_and_list) { + if ( strcmp(this->Strings[0], SHT) == 0 ) { + std::vector::const_iterator it = this->CurrentList.begin(); + for( ;it != this->CurrentList.end(); it++) { + checkShortName(*it); + } + mn->SetShortNames(this->CurrentList); +#ifdef __DEBUG + std::cout<<"Short Names : "<Strings[0], LNG) == 0 ) { + mn->SetLongNames(this->CurrentList); +#ifdef __DEBUG + std::cout<<"Long Names : "<Strings[0], UNT) == 0 ) { + mn->SetUnits(this->CurrentList); +#ifdef __DEBUG + std::cout<<"Units : "; +#endif + } else { + std::stringstream s; + s << "File : "<< this->FileName; + s << ", line "<LineNumber; + s << " unexpected key world: '"<Strings[0]<<"'"; + } + delete this->Strings[0]; + this->Strings[0] = 0; + Strings.pop_back(); +#ifdef __DEBUG + std::vector::const_iterator it = this->CurrentList.begin(); + std::cout<<"[ "; + for( ;it != this->CurrentList.end(); it++) { + std::cout<<"'"<<*it<<"'"; + if ( it+1 != this->CurrentList.end() ) + std::cout<<", "; + } + std::cout<<" ]"<CurrentList.clear(); + } + } +} +//--------------------------------------------------- +void vtkJSONParser::processInfoNode() { + vtkJSONInfoNode* in = GetInfoNode(); + if(in) { + if(this->Strings.size() == 1 && !isnan(this->LastValue)) { + in->AddValue(this->Strings[0],this->LastValue); + if(!ShortNamesFilled) { + char* name = new char[strlen(Strings[0])]; + strcpy(name, Strings[0]); + this->ShortNames.push_back(name); + } + this->Strings.pop_back(); + this->LastValue = NAN; + } + } +} + +//--------------------------------------------------- +void vtkJSONParser::processCharacter(const char ch) { + if (this->InsideQuotes) + return; + if(isBlankOrEnd(ch)) + return; + + if(this->ExpectedCharacters.empty()) + return; + + std::vector::const_iterator it = std::find(this->ExpectedCharacters.begin(), + this->ExpectedCharacters.end(), + ch); + + // Unexpected character is found + if(it == this->ExpectedCharacters.end()) { + std::string s("unexpected character '"); + s+=ch; + s+="' !"; + throwException(s.c_str()); + + } +} + +//--------------------------------------------------- +char* vtkJSONParser::getString(long b, long e) { + char* result = 0; + + long old_pos = ftell(this->File); + fseek(this->File, b, SEEK_SET); + long data_s = e - b; + result = new char[data_s]; + result[0] = 0; + size_t nb_read = fread(result, sizeof(char), data_s, this->File); + result[nb_read] = '\0'; + fseek(this->File, old_pos, SEEK_SET); + return result; +} + +//--------------------------------------------------- +void vtkJSONParser::allowsDigits() { + for(char c = '.'; c <= '9'; c++) { + ExpectedCharacters.push_back(c); + } + ExpectedCharacters.push_back('-'); + ExpectedCharacters.push_back('+'); + ExpectedCharacters.push_back('e'); +} + +//--------------------------------------------------- +bool vtkJSONParser::isDigitsAllowed() { + std::vector::const_iterator it = std::find(this->ExpectedCharacters.begin(), + this->ExpectedCharacters.end(), + '0'); + return (it != this->ExpectedCharacters.end()); +} + +//--------------------------------------------------- +void vtkJSONParser::readDoubleValue() { + long b = ftell(this->File); + + while(1) { + char ch = fgetc(this->File); + if(!isDigitOrDot(ch)) { + break; + } + } + + long e = ftell(this->File); + fseek(this->File, b-1, SEEK_SET); + long data_s = e - b; + char* result = new char[data_s]; + result[0] = 0; + size_t nb_read = fread(result, sizeof(char), data_s, this->File); + result[nb_read] = '\0'; + this->ExpectedCharacters.clear(); + this->ExpectedCharacters.push_back(COMMA); + this->ExpectedCharacters.push_back(CCB); + this->LastValue = atof(result); +#ifdef __DEBUG + std::cout<<"Read number : "<LastValue< 0 ){ + for( size_t i = 0; i < ln; i++ ) { + // a - z + if(!(name[i] >= 'a' && name[i] <= 'z') && + // A - Z + !(name[i] >= 'A' && name[i] <= 'Z') ) { + std::string s("wrong short name '"); + s += name; + s += "' !"; + throwException(s.c_str(), this->LineNumber); + } + } + } +} + +void vtkJSONParser::clean() { + std::vector::iterator it = this->Nodes.begin(); + for( ; it != this->Nodes.end(); it++ ) { + delete *(it); + *it = 0; + } +} + +//--------------------------------------------------- +void vtkJSONParser::throwException(const char* message) { + std::stringstream s; + s << "File : "<< this->FileName; + s << ", line "<LineNumber; + s << ", column " << this->ColumnNumber<<" : "; + s << message; + clean(); + throw vtkJSONException(s.str().c_str()); +} + +//--------------------------------------------------- +void vtkJSONParser::throwException(const char* message, int ln, int cn) { + std::stringstream s; + s << "File : "<< this->FileName; + s << ", line "<FileName; + s << ", line "< +#include +#include +#include +#include + + +class vtkTable; +class vtkJSONNode; +class vtkJSONMetaNode; +class vtkJSONInfoNode; + +//--------------------------------------------------- +class vtkJSONException : public std::exception { + public: + vtkJSONException(const char *reason); + ~vtkJSONException() throw (); + const char* what() const throw(); + protected: + std::string Reason; +}; + +class vtkJSONParser : public vtkObject +{ +public: + static vtkJSONParser* New(); + + // Description: + // Specifies the name of the file + vtkGetStringMacro(FileName); + vtkSetStringMacro(FileName); + + virtual int Parse(vtkTable* theTable); + +protected: + + //Struct to store cursor information + //---------------------------------- + struct Info { + public: + char type; + long ln; + long cn; + long pos; + + Info() { + type = 0; + ln = -1; + cn = -1; + pos = -1; + } + }; + + vtkJSONParser(); + ~vtkJSONParser(); + + // name of the file to read from + //---------------------------------- + char* FileName; + + // current line and column + //---------------------------------- + int LineNumber; + int ColumnNumber; + + // markup information + //---------------------------------- + std::vector CInfoVector; + + // file + //---------------------------------- + FILE* File; + + // Nodes + //---------------------------------- + std::vector Nodes; + vtkJSONNode* CurrentNode; + vtkJSONMetaNode* MetaNode; + + // Nodes + //---------------------------------- + std::vector ExpectedCharacters; + + // Flags + //---------------------------------- + bool InsideQuotes; + bool ParseList; + bool ParseObjectList; + bool ShortNamesFilled; + + // Last parced string + //---------------------------------- + char* LastString; + std::vector Strings; + std::vector CurrentList; + std::vector ShortNames; + + // Last parced values + //---------------------------------- + double LastValue; + +private: + vtkJSONParser(const vtkJSONParser&); // Not implemented. + void operator=(const vtkJSONParser&); // Not implemented. + + vtkJSONMetaNode* GetMetaNode(); + vtkJSONInfoNode* GetInfoNode(); + + void processOCB(); + void processCCB(); + + void processOSB(); + void processCSB(); + + void processCOMMA(); + + void processCOLON(); + + void processENDL(); + + void processQTS(); + + void processCharacter(const char ch); + + void processMetaNode(); + void processInfoNode(); + + void readDoubleValue(); + + char* getString(long b, long e); + + void allowsDigits(); + + bool isDigitsAllowed(); + + void checkShortName(const char* unit); + + void finalize(vtkTable *t); + + void clean(); + + void throwSimpleException(const char* message); + + void throwException(const char* message); + + void throwException(const char* message, int ln, int cn); + + void throwException(const char* message, int ln); +}; +#endif //__vtkJSONParser_h_ diff --git a/src/Plugins/JSONReader/ParaViewPlugin/CMakeLists.txt b/src/Plugins/JSONReader/ParaViewPlugin/CMakeLists.txt new file mode 100644 index 00000000..6fd4e2c4 --- /dev/null +++ b/src/Plugins/JSONReader/ParaViewPlugin/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +# Author : Roman NIKOLAEV + +INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/JSONParser ) + +ADD_PARAVIEW_PLUGIN(JSONReader "1.0" + SERVER_MANAGER_XML JSONReader.xml + SERVER_MANAGER_SOURCES vtkJSONReader.cxx + REQUIRED_ON_SERVER) + +TARGET_LINK_LIBRARIES(JSONReader vtkJSONParser) + +INSTALL(TARGETS JSONReader + DESTINATION lib/paraview +) diff --git a/src/Plugins/JSONReader/ParaViewPlugin/JSONReader.xml b/src/Plugins/JSONReader/ParaViewPlugin/JSONReader.xml new file mode 100644 index 00000000..5b35ddd0 --- /dev/null +++ b/src/Plugins/JSONReader/ParaViewPlugin/JSONReader.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + This property specifies the file name for the JSON reader + + + + + diff --git a/src/Plugins/JSONReader/ParaViewPlugin/plugin.cmake b/src/Plugins/JSONReader/ParaViewPlugin/plugin.cmake new file mode 100644 index 00000000..4a646baa --- /dev/null +++ b/src/Plugins/JSONReader/ParaViewPlugin/plugin.cmake @@ -0,0 +1,3 @@ +pv_plugin(JSONReader + DESCRIPTION "Reads the JSON file and converts it to the VTK table" + DEFAULT_ENABLED) diff --git a/src/Plugins/JSONReader/ParaViewPlugin/vtkJSONReader.cxx b/src/Plugins/JSONReader/ParaViewPlugin/vtkJSONReader.cxx new file mode 100644 index 00000000..5a02d465 --- /dev/null +++ b/src/Plugins/JSONReader/ParaViewPlugin/vtkJSONReader.cxx @@ -0,0 +1,96 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +// Author: Roman NIKOLAEV + +#include "vtkJSONReader.h" +#include "vtkJSONParser.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +vtkStandardNewMacro(vtkJSONReader); + +//--------------------------------------------------- +vtkJSONReader::vtkJSONReader() +{ + this->SetNumberOfInputPorts(0); + this->SetNumberOfOutputPorts(1); + this->FileName = NULL; + this->Parser = vtkJSONParser::New(); +} + +//--------------------------------------------------- +vtkJSONReader::~vtkJSONReader() +{ + this->SetFileName(NULL); + this->Parser->Delete(); +} + +//--------------------------------------------------- +int vtkJSONReader::CanReadFile(const char* fname) +{ + return 1; +} + +//--------------------------------------------------- +void vtkJSONReader::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + os << indent << "FileName: " + << (this->FileName ? this->FileName : "(none)") << endl; + os << indent << "Parser: "<Parser << endl; +} + +//--------------------------------------------------- +int vtkJSONReader::RequestData(vtkInformation*, + vtkInformationVector**, + vtkInformationVector* outputVector) +{ + vtkTable* const output_table = vtkTable::GetData(outputVector); + + vtkInformation* const outInfo = outputVector->GetInformationObject(0); + if(outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) && + outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) + { + return 1; + } + + // If the filename is not defined + if (!this->FileName && !this->Parser) + { + return 1; + } + + this->Parser->SetFileName(this->FileName); + try{ + return this->Parser->Parse(output_table); + } catch(vtkJSONException e) { + std::cout< +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// ============================================================================ +/*! + * Main program source for Unit Tests with cppunit package does not depend + * on actual tests, so we use the same for all partial unit tests. + */ +// ============================================================================ + +int main(int argc, char* argv[]) +{ + // --- Create the event manager and test controller + CPPUNIT_NS::TestResult controller; + + // --- Add a listener that colllects test result + CPPUNIT_NS::TestResultCollector result; + controller.addListener( &result ); + + // --- Add a listener that print dots as test run. +#ifdef WIN32 + CPPUNIT_NS::TextTestProgressListener progress; +#else + CPPUNIT_NS::BriefTestProgressListener progress; +#endif + controller.addListener( &progress ); + + // --- Get the top level suite from the registry + + CPPUNIT_NS::Test *suite = + CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest(); + + // --- Adds the test to the list of test to run + + CPPUNIT_NS::TestRunner runner; + runner.addTest( suite ); + runner.run( controller); + + // --- Print test in a compiler compatible format. + + std::ofstream testFile; + testFile.open("UnitTestsResult.txt", std::ios::out | std::ios::trunc); + //CPPUNIT_NS::CompilerOutputter outputter( &result, std::cerr ); + CPPUNIT_NS::CompilerOutputter outputter( &result, testFile ); + outputter.write(); + + // --- Run the tests. + + bool wasSucessful = result.wasSuccessful(); + testFile.close(); + + // --- Return error code 1 if the one of test failed. + + return wasSucessful ? 0 : 1; +} + +#endif diff --git a/src/Plugins/JSONReader/Test/vtkJSONParserTest.cxx b/src/Plugins/JSONReader/Test/vtkJSONParserTest.cxx new file mode 100644 index 00000000..256461f2 --- /dev/null +++ b/src/Plugins/JSONReader/Test/vtkJSONParserTest.cxx @@ -0,0 +1,164 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + + +#include "vtkJSONParserTest.hxx" +#include + +#include +#include +#include + +#include +#include +#include + +//--------------------------------------------------- +std::string vtkJSONParserTest::getGoodFilesDir() { + char* c = getenv("PARAVIS_SRC_DIR"); + std::string s = std::string(c == 0 ? "" : c); + if( !s.empty() ) { + s+="/src"; + s+="/Plugins"; + s+="/JSONReader"; + s+="/Examples/"; + } + return s; +} + +//--------------------------------------------------- +std::string vtkJSONParserTest::getBadFilesDir() { + char* c = getenv("PARAVIS_SRC_DIR"); + std::string s = std::string(c == 0 ? "" : c); + if( !s.empty() ) { + s+="/src"; + s+="/Plugins"; + s+="/JSONReader"; + s+="/Test"; + s+="/BadFiles"; + s+="/"; + } + return s; +} + +//--------------------------------------------------- +void vtkJSONParserTest::testParseBadFiles() { + std::string dir = getBadFilesDir(); + if(dir.empty()) + CPPUNIT_FAIL("Can't get examples dir !!! "); + std::string fn = "bad_ex"; + + // 11 existing files, bad_ex12.json doesn't exists, check exception + for(int i = 1; i <=12; i++) { + std::string s = dir + fn; + std::stringstream convert; + convert << i; + s += convert.str(); + s += ".json"; + vtkJSONParser* Parser = vtkJSONParser::New(); + vtkTable* table = vtkTable::New(); + Parser->SetFileName(s.c_str()); + bool expected_exception_thrown = false; + try{ + Parser->Parse(table); + } catch(vtkJSONException e) { + expected_exception_thrown = true; + } + Parser->Delete(); + table->Delete(); + if(!expected_exception_thrown) { + CPPUNIT_FAIL("Expected exception is not thrown !!! "); + } + } +} + +//--------------------------------------------------- +void vtkJSONParserTest::testParseGoodFiles() { + std::string dir = getGoodFilesDir(); + if(dir.empty()) + CPPUNIT_FAIL("Can't get examples dir !!! "); + std::string fn = "example"; + + for(int i = 1; i <=2; i++) { + std::string s = dir + fn; + std::stringstream convert; + convert << i; + s += convert.str(); + s += ".json"; + vtkJSONParser* Parser = vtkJSONParser::New(); + vtkTable* table = vtkTable::New(); + Parser->SetFileName(s.c_str()); + bool exception_thrown = false; + try{ + Parser->Parse(table); + } catch(vtkJSONException e) { + exception_thrown = true; + } + Parser->Delete(); + table->Delete(); + + if(exception_thrown) { + CPPUNIT_FAIL("Unexpected exception has been thrown !!! "); + } + } + + vtkJSONParser* Parser = vtkJSONParser::New(); + vtkTable* table = vtkTable::New(); + fn = "example"; + std::string s = dir + fn; + std::stringstream convert; + convert << 2; + s += convert.str(); + s += "_wo_metadata.json"; + Parser->SetFileName(s.c_str()); + bool exception_thrown = false; + try{ + Parser->Parse(table); + } catch(vtkJSONException e) { + exception_thrown = true; + } + if(exception_thrown) { + CPPUNIT_FAIL("Unexpected exception has been thrown !!! "); + } + + double v = table->GetValue(2,0).ToDouble(); + double v1 = table->GetValue(2,1).ToDouble(); + double v2 = table->GetValue(2,2).ToDouble(); + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", 3.15, table->GetValue(0,0).ToDouble(), 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", 0.0, table->GetValue(0,1).ToDouble(), 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", 43.5, table->GetValue(0,2).ToDouble(), 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", 4.156, table->GetValue(1,0).ToDouble(), 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", 465, table->GetValue(1,1).ToDouble(), 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", 137.5, table->GetValue(1,2).ToDouble(), 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", -3.0305890e+4, table->GetValue(2,0).ToDouble(), 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", 1.0305890e-1, table->GetValue(2,1).ToDouble(), 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Unexpected value : ", -3.0305890e+5, table->GetValue(2,2).ToDouble(), 0.001); + + std::string s1 (); + + CPPUNIT_ASSERT_EQUAL( std::string("P[n/a]"), std::string(table->GetColumn(0)->GetName())); + CPPUNIT_ASSERT_EQUAL( std::string("u[n/a]"), std::string(table->GetColumn(1)->GetName())); + CPPUNIT_ASSERT_EQUAL( std::string("weight[n/a]"), std::string(table->GetColumn(2)->GetName())); + + Parser->Delete(); + table->Delete(); +} diff --git a/src/Plugins/JSONReader/Test/vtkJSONParserTest.hxx b/src/Plugins/JSONReader/Test/vtkJSONParserTest.hxx new file mode 100644 index 00000000..2f89cb40 --- /dev/null +++ b/src/Plugins/JSONReader/Test/vtkJSONParserTest.hxx @@ -0,0 +1,40 @@ +// Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// +#ifndef __VTKJSONPARSERTEST_HXX__ +#define __VTKJSONPARSERTEST_HXX__ + +#include +#include + +class vtkJSONParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(vtkJSONParserTest); + CPPUNIT_TEST( testParseGoodFiles ); + CPPUNIT_TEST( testParseBadFiles ); + CPPUNIT_TEST_SUITE_END(); + +public: + void testParseGoodFiles(); + void testParseBadFiles(); +private: + std::string getGoodFilesDir(); + std::string getBadFilesDir(); +}; + +#endif