1 // Copyright (C) 2015-2016 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author: Roman NIKOLAEV
21 #include "vtkJSONParser.h"
23 #include <vtkObjectFactory.h>
25 #include <vtkInformation.h>
26 #include <vtkDoubleArray.h>
38 #define NAN std::numeric_limits<double>::quiet_NaN()
43 #define MD "_metadata"
44 #define CMT "_comment"
45 #define TBN "table_name"
46 #define TBD "table_description"
47 #define SHT "short_names"
48 #define LNG "long_names"
70 #define addInfo(info) \
73 I.ln = this->LineNumber; \
74 I.cn = this->ColumnNumber; \
75 I.pos = ftell(this->File); \
76 this->CInfoVector.push_back(I);
78 //---------------------------------------------------
79 bool isBlankOrEnd(const char c) {
80 return c == SPS || c == ENDL || c == TAB || c == EOF;
83 bool isDigitOrDot(const char c) {
84 return (c >= '.' && c <='9') || c == '+' || c == '-' || c == 'e';
88 //---------------------------------------------------
89 vtkJSONException::vtkJSONException(const char *reason) : Reason(reason) {
92 //---------------------------------------------------
93 vtkJSONException::~vtkJSONException() throw () {
96 //---------------------------------------------------
97 const char* vtkJSONException::what() const throw() {
98 return Reason.c_str();
101 // Containers to store information about nodes:
104 //---------------------------------------------------
107 vtkJSONNode() { Name = 0; }
108 virtual ~vtkJSONNode() { }
109 const char* GetName() { return this->Name ; }
110 void SetName(const char* name) { this->Name = name; }
115 class vtkJSONMetaNode : public vtkJSONNode {
117 vtkJSONMetaNode() : vtkJSONNode() {
121 this->TableDescription = 0;
125 virtual ~vtkJSONMetaNode() {
126 delete this->Comment; this->Comment = 0;
127 delete this->TableName; this->TableName = 0;
128 delete this->Date; this->Date= 0;
129 delete this->TableDescription; this->TableDescription = 0;
130 for(int i = 0; i < this->ShortNames.size(); i++) {
131 delete this->ShortNames[i]; this->ShortNames[i] = 0;
133 for(int i = 0; i < this->LongNames.size(); i++) {
134 delete this->LongNames[i]; this->LongNames[i] = 0;
136 for(int i = 0; i < this->Units.size(); i++) {
137 delete this->Units[i]; this->Units[i] = 0;
141 void SetComment(const char* comment) { this->Comment = comment; }
142 const char* GetComment() { return this->Comment; }
144 void SetTableName(const char* name) { this->TableName = name; }
145 const char* GetTableName() { return this->TableName; }
147 void SetDate(const char* name) { this->Date = name; }
148 const char* GetDate() { return this->Date; }
150 void SetTableDescription(const char* description) { this->TableDescription = description; }
151 const char* GetDescription() { return this->TableDescription; }
153 void SetShortNames(std::vector<const char*> names) { this->ShortNames = names; }
154 std::vector<const char*> GetShortNames() { return this->ShortNames; }
156 void SetLongNames(std::vector<const char*> names) { this->LongNames = names; }
157 std::vector<const char*> GetLongNames() { return this->LongNames; }
159 void SetUnits(std::vector<const char*> units) { this->Units = units; }
160 std::vector<const char*> GetUnits() { return this->Units; }
164 const char* TableName;
165 const char* TableDescription;
167 std::vector<const char*> ShortNames;
168 std::vector<const char*> LongNames;
169 std::vector<const char*> Units;
173 bool operator () (const char *a, const char *b) const
175 return strcmp(a,b)<0;
179 typedef std::map<const char*, double, char_cmp> vtkJSONMap;
181 class vtkJSONInfoNode : public vtkJSONNode {
183 vtkJSONInfoNode(const char* name) : vtkJSONNode() {
186 virtual ~vtkJSONInfoNode() {
187 vtkJSONMap::iterator it = this->Values.begin();
188 for( ;it != this->Values.end(); it++) {
190 const char* c = it->first;
194 void AddValue(const char* key, const double value) {
195 this->Values.insert(std::pair<const char*,double>(key,value));
197 vtkJSONMap& GetValues() { return this->Values; }
203 //---------------------------------------------------
204 vtkStandardNewMacro(vtkJSONParser);
206 //---------------------------------------------------
207 vtkJSONParser::vtkJSONParser()
209 this->FileName = NULL;
210 this->LineNumber = 1;
211 this->ColumnNumber = 0;
213 this->InsideQuotes = false;
214 this->LastString = 0;
215 this->CurrentNode = 0;
216 this->ParseList = false;
217 this->ParseObjectList = false;
218 this->LastValue = NAN;
219 this->ShortNamesFilled = false;
222 //---------------------------------------------------
223 vtkJSONParser::~vtkJSONParser()
225 delete this->FileName;
230 //---------------------------------------------------
231 int vtkJSONParser::Parse(vtkTable* theTable)
233 if(!this->FileName) {
234 vtkErrorMacro("The name of the file is not defined");
237 this->File = fopen( this->FileName, "r" );
240 std::string message = std::string("Can't open file: ") + std::string(this->FileName);
241 throwSimpleException(message.c_str());
246 this->ExpectedCharacters.push_back(OCB);
249 ch = fgetc(this->File);
250 processCharacter(ch);
251 if(isDigitsAllowed() && isDigitOrDot(ch)) {
256 case OCB: processOCB(); break;
257 case CCB: processCCB(); break;
259 case OSB: processOSB(); break;
260 case CSB: processCSB(); break;
262 case ENDL: processENDL(); nb = 0; break;
264 case QTS: processQTS(); break;
266 case COLON: processCOLON(); break;
268 case COMMA: processCOMMA(); break;
270 this->ColumnNumber+=nb;
274 if(this->CInfoVector.size() > 0 ) {
275 throwException("braket is not closed ",
276 this->CInfoVector.back().ln,
277 this->CInfoVector.back().cn);
285 //---------------------------------------------------
286 void vtkJSONParser::finalize( vtkTable *t ) {
287 std::vector<vtkJSONNode*>::iterator it = this->Nodes.begin();
288 vtkJSONMetaNode* mn = 0;
289 for( ; it != this->Nodes.end(); it++ ) {
290 mn = dynamic_cast<vtkJSONMetaNode*>(*it);
294 std::vector<const char*> units;
296 if(!mn->GetShortNames().empty()) {
297 this->ShortNames.clear();
298 this->ShortNames = mn->GetShortNames();
300 t->GetInformation()->Set(vtkDataObject::FIELD_NAME(), mn->GetTableName() ? mn->GetTableName() : "");
301 units = mn->GetUnits();
304 long nbRow = mn ? (this->Nodes.size() - 1 ) : this->Nodes.size();
305 for (long col=0; col < this->ShortNames.size(); col++) {
306 vtkDoubleArray* newCol = vtkDoubleArray::New();
307 newCol->SetNumberOfValues(nbRow);
308 vtkJSONInfoNode* in = 0;
309 std::string name = this->ShortNames[col];
311 if(col < units.size()){
317 newCol->SetName(name.c_str());
318 it = this->Nodes.begin();
320 for( ; it != this->Nodes.end(); it++ ) {
321 in = dynamic_cast<vtkJSONInfoNode*>(*it);
323 vtkJSONMap& vl = in->GetValues();
324 vtkJSONMap::iterator mit = vl.find(this->ShortNames[col]);
325 if(mit != vl.end()) {
326 newCol->SetValue(row, mit->second);
327 const char* c = mit->first;
333 std::string s("Item with name '");
335 s+="' has no key (or not a numerical value for key) '";
336 s+=this->ShortNames[col];
337 s+="'! Value set to 0.0.";
338 //throwSimpleException(s.c_str());
339 std::ostringstream oss;
340 oss << "vtkJSONParser::finalize(): " << s << std::endl;
341 if(this->HasObserver("ErrorEvent") )
342 this->InvokeEvent("ErrorEvent",const_cast<char *>(oss.str().c_str()));
344 vtkOutputWindowDisplayErrorText(const_cast<char *>(oss.str().c_str()));
345 vtkObject::BreakOnError();
347 newCol->SetValue(row, 0.0);
351 t->AddColumn(newCol);
353 it = this->Nodes.begin();
354 vtkJSONInfoNode* in = 0;
355 for( ; it != this->Nodes.end(); it++ ) {
356 in = dynamic_cast<vtkJSONInfoNode*>(*it);
358 vtkJSONMap& vl = in->GetValues();
360 std::string s("Item with name '");
362 s+="' has unexpected key '";
363 s+=vl.begin()->first;
365 throwSimpleException(s.c_str());
371 //---------------------------------------------------
372 void vtkJSONParser::processQTS() {
373 this->InsideQuotes = !this->InsideQuotes;
374 if(this->InsideQuotes) {
377 // Quotes is closed, get content
378 Info i = this->CInfoVector.back();
379 this->CInfoVector.pop_back();
382 long end = ftell(this->File) - 1;
383 this->LastString = getString(begin, end);
384 bool parse_list = (this->CInfoVector.size() >= 1 && this->CInfoVector.back().type == OSB);
386 this->CurrentList.push_back(this->LastString);
388 this->Strings.push_back(this->LastString);
392 std::cout<<"String : "<<this->LastString<<std::endl;
395 this->ExpectedCharacters.clear();
396 this->ExpectedCharacters.push_back(COLON);
397 this->ExpectedCharacters.push_back(COMMA);
398 this->ExpectedCharacters.push_back(CCB);
399 this->ExpectedCharacters.push_back(CSB);
404 //---------------------------------------------------
405 void vtkJSONParser::processCOLON() {
406 if (this->InsideQuotes)
408 this->ExpectedCharacters.clear();
409 this->ExpectedCharacters.push_back(OCB);
410 this->ExpectedCharacters.push_back(QTS);
411 this->ExpectedCharacters.push_back(OSB);
412 if(GetInfoNode() && Strings.size() == 1 ) {
417 //---------------------------------------------------
418 void vtkJSONParser::processOCB() {
419 if (this->InsideQuotes)
421 this->ExpectedCharacters.clear();
422 this->ExpectedCharacters.push_back(QTS);
423 this->ExpectedCharacters.push_back(CCB);
426 if(this->CInfoVector.size() >= 1) {
427 if ( !GetMetaNode() && this->Strings.size() > 0 &&
428 this->Strings.back() &&
429 strcmp(this->Strings.back(), MD) == 0 ) {
431 std::cout<<"Create new Meta Node !!!"<<std::endl;
433 this->CurrentNode = new vtkJSONMetaNode();
434 delete this->Strings.back();
435 this->Strings.back() = 0;
436 this->Strings.pop_back();
438 if(this->CInfoVector.back().type == OSB ) {
439 this->ParseObjectList = true;
442 std::cout<<"Create new Node with name '"<<(this->Strings.size() == 0 ? "" : this->Strings.back())<<"' !!!"<<std::endl;
444 this->CurrentNode = new vtkJSONInfoNode(this->Strings.size() == 0 ? "" : this->Strings.back());
445 if(!this->ParseObjectList && this->Strings.size() == 1) {
446 this->Strings.pop_back();
453 //---------------------------------------------------
454 vtkJSONMetaNode* vtkJSONParser::GetMetaNode() {
455 vtkJSONMetaNode *mnode = 0;
456 if( this->CurrentNode ) {
457 mnode = dynamic_cast<vtkJSONMetaNode*>(this->CurrentNode);
462 //---------------------------------------------------
463 vtkJSONInfoNode* vtkJSONParser::GetInfoNode() {
464 vtkJSONInfoNode *mnode = 0;
465 if( this->CurrentNode ) {
466 mnode = dynamic_cast<vtkJSONInfoNode*>(this->CurrentNode);
471 //---------------------------------------------------
472 void vtkJSONParser::processENDL() {
473 if(this->InsideQuotes) {
475 throwException("quote is not closed !");
478 this->ColumnNumber=0;
482 //---------------------------------------------------
483 void vtkJSONParser::processCSB() {
484 if (this->InsideQuotes)
487 if(this->CInfoVector.back().type == OSB) {
488 if(this->ParseList) {
489 this->ParseList = false;
491 if(this->ParseObjectList) {
492 this->ParseObjectList = false;
494 this->CInfoVector.pop_back();
497 this->ExpectedCharacters.clear();
498 this->ExpectedCharacters.push_back(COMMA);
499 this->ExpectedCharacters.push_back(OCB);
500 this->ExpectedCharacters.push_back(CCB);
503 //---------------------------------------------------
504 void vtkJSONParser::processOSB() {
505 if (this->InsideQuotes)
508 if(this->ParseList) {
509 Info i = CInfoVector.back();
511 throwException("list, which has been opened in this place, has not been closed !", i.ln, i.cn);
515 this->ParseList = true;
517 if( this->Strings.size() > 0 ) {
518 delete this->Strings[Strings.size()-1];
519 this->Strings[Strings.size()-1] = 0;
520 this->Strings.pop_back();
524 this->ExpectedCharacters.clear();
525 this->ExpectedCharacters.push_back(QTS);
526 this->ExpectedCharacters.push_back(OCB);
529 //---------------------------------------------------
530 void vtkJSONParser::processCCB() {
531 if (this->InsideQuotes)
534 this->ExpectedCharacters.clear();
535 this->ExpectedCharacters.push_back(COMMA);
536 this->ExpectedCharacters.push_back(CCB);
537 if(this->ParseObjectList) {
538 this->ExpectedCharacters.push_back(CSB);
544 if(this->CurrentNode)
545 this->Nodes.push_back(this->CurrentNode);
546 if( !this->ShortNamesFilled ){
547 vtkJSONInfoNode* n = dynamic_cast<vtkJSONInfoNode*>(this->CurrentNode);
549 this->ShortNamesFilled = true;
554 if(this->CurrentNode)
555 std::cout<<"End parsing node with name '"<<this->CurrentNode->GetName()<<"' !!!!"<<std::endl;
558 if (this->CInfoVector.size() > 0 && this->CInfoVector.back().type == OCB ) {
559 this->CInfoVector.pop_back();
561 throwException ("unexpected closed braket '}' !");
564 this->CurrentNode = 0;
567 //---------------------------------------------------
568 void vtkJSONParser::processCOMMA() {
569 if (this->InsideQuotes)
571 this->ExpectedCharacters.clear();
572 this->ExpectedCharacters.push_back(QTS);
573 this->ExpectedCharacters.push_back(OCB);
578 void vtkJSONParser::processMetaNode() {
579 vtkJSONMetaNode* mn = GetMetaNode();
581 bool strings = this->Strings.size() == 2 && !this->ParseList;
582 bool str_and_list = (this->Strings.size() == 1 && this->CurrentList.size() > 0 && !this->ParseList);
585 if ( strcmp(this->Strings[0], CMT) == 0 ) {
586 mn->SetComment(this->Strings[1]);
588 std::cout<<"Table Comment : "<<this->Strings[1]<<std::endl;
590 } else if ( strcmp(this->Strings[0], TBN) == 0 ) {
591 mn->SetTableName(this->Strings[1]);
593 std::cout<<"Table Name : "<<this->Strings[1]<<std::endl;
595 } else if ( strcmp(this->Strings[0], TBD) == 0 ) {
596 mn->SetTableDescription(this->Strings[1]);
598 std::cout<<"Table Description : "<<this->Strings[1]<<std::endl;
600 } else if ( strcmp(this->Strings[0], DT) == 0 ) {
601 mn->SetDate(this->Strings[1]);
603 std::cout<<"Date : "<<this->Strings[1]<<std::endl;
607 s << "File : "<< this->FileName;
608 s << ", line "<<this->LineNumber;
609 s << " unexpected key word: '"<<this->Strings[0]<<"'";
611 delete this->Strings[0];
612 this->Strings[0] = 0;
616 } else if(str_and_list) {
617 if ( strcmp(this->Strings[0], SHT) == 0 ) {
618 std::vector<const char*>::const_iterator it = this->CurrentList.begin();
619 for( ;it != this->CurrentList.end(); it++) {
622 mn->SetShortNames(this->CurrentList);
624 std::cout<<"Short Names : "<<std::endl;
626 } else if ( strcmp(this->Strings[0], LNG) == 0 ) {
627 mn->SetLongNames(this->CurrentList);
629 std::cout<<"Long Names : "<<std::endl;
631 } else if ( strcmp(this->Strings[0], UNT) == 0 ) {
632 mn->SetUnits(this->CurrentList);
634 std::cout<<"Units : ";
638 s << "File : "<< this->FileName;
639 s << ", line "<<this->LineNumber;
640 s << " unexpected key word: '"<<this->Strings[0]<<"'";
642 delete this->Strings[0];
643 this->Strings[0] = 0;
646 std::vector<const char*>::const_iterator it = this->CurrentList.begin();
648 for( ;it != this->CurrentList.end(); it++) {
649 std::cout<<"'"<<*it<<"'";
650 if ( it+1 != this->CurrentList.end() )
653 std::cout<<" ]"<<std::endl;
655 this->CurrentList.clear();
659 //---------------------------------------------------
660 void vtkJSONParser::processInfoNode() {
661 vtkJSONInfoNode* in = GetInfoNode();
663 if(this->Strings.size() == 1 && !isnan(this->LastValue)) {
664 in->AddValue(this->Strings[0],this->LastValue);
665 if(!ShortNamesFilled) {
666 char* name = new char[strlen(Strings[0])];
667 strcpy(name, Strings[0]);
668 this->ShortNames.push_back(name);
670 this->Strings.pop_back();
671 this->LastValue = NAN;
673 if(this->Strings.size() == 2) {
674 std::string s("Item with name '");
676 s+="' has not a numerical value for key '";
678 s+="'! Value set to 0.0.";
679 //throwSimpleException(s.c_str());
680 std::ostringstream oss;
681 oss << "vtkJSONParser::processInfoNode(): " << s << std::endl;
682 if(this->HasObserver("ErrorEvent") )
683 this->InvokeEvent("ErrorEvent",const_cast<char *>(oss.str().c_str()));
685 vtkOutputWindowDisplayErrorText(const_cast<char *>(oss.str().c_str()));
686 vtkObject::BreakOnError();
688 in->AddValue(this->Strings[0],0.0);
689 if(!ShortNamesFilled) {
690 char* name = new char[strlen(Strings[0])];
691 strcpy(name, Strings[0]);
692 this->ShortNames.push_back(name);
694 this->Strings.clear();
695 this->LastValue = NAN;
700 //---------------------------------------------------
701 void vtkJSONParser::processCharacter(const char ch) {
702 if (this->InsideQuotes)
707 if(this->ExpectedCharacters.empty())
710 std::vector<char>::const_iterator it = std::find(this->ExpectedCharacters.begin(),
711 this->ExpectedCharacters.end(),
714 // Unexpected character is found
715 if(it == this->ExpectedCharacters.end()) {
716 std::string s("unexpected character '");
719 throwException(s.c_str());
724 //---------------------------------------------------
725 char* vtkJSONParser::getString(long b, long e) {
728 long old_pos = ftell(this->File);
729 fseek(this->File, b, SEEK_SET);
731 result = new char[data_s + 1]; // + 1 for the '\0' symbol
733 size_t nb_read = fread(result, sizeof(char), data_s, this->File);
734 result[nb_read] = '\0';
735 fseek(this->File, old_pos, SEEK_SET);
739 //---------------------------------------------------
740 void vtkJSONParser::allowsDigits() {
741 for(char c = '.'; c <= '9'; c++) {
742 ExpectedCharacters.push_back(c);
744 ExpectedCharacters.push_back('-');
745 ExpectedCharacters.push_back('+');
746 ExpectedCharacters.push_back('e');
749 //---------------------------------------------------
750 bool vtkJSONParser::isDigitsAllowed() {
751 std::vector<char>::const_iterator it = std::find(this->ExpectedCharacters.begin(),
752 this->ExpectedCharacters.end(),
754 return (it != this->ExpectedCharacters.end());
757 //---------------------------------------------------
758 void vtkJSONParser::readDoubleValue() {
759 long b = ftell(this->File);
762 char ch = fgetc(this->File);
763 if(!isDigitOrDot(ch)) {
768 long e = ftell(this->File);
769 fseek(this->File, b-1, SEEK_SET);
771 char* result = new char[data_s];
773 size_t nb_read = fread(result, sizeof(char), data_s, this->File);
774 result[nb_read] = '\0';
775 this->ExpectedCharacters.clear();
776 this->ExpectedCharacters.push_back(COMMA);
777 this->ExpectedCharacters.push_back(CCB);
778 this->LastValue = atof(result);
780 std::cout<<"Read number : "<<this->LastValue<<std::endl;
784 //---------------------------------------------------
785 void vtkJSONParser::checkShortName(const char* name) {
786 size_t ln = strlen(name);
788 for( size_t i = 0; i < ln; i++ ) {
790 if(!(name[i] >= 'a' && name[i] <= 'z') &&
792 !(name[i] >= 'A' && name[i] <= 'Z') ) {
793 std::string s("wrong short name '");
796 throwException(s.c_str(), this->LineNumber);
802 void vtkJSONParser::clean() {
803 std::vector<vtkJSONNode*>::iterator it = this->Nodes.begin();
804 for( ; it != this->Nodes.end(); it++ ) {
810 //---------------------------------------------------
811 void vtkJSONParser::throwException(const char* message) {
813 s << "File : "<< this->FileName;
814 s << ", line "<<this->LineNumber;
815 s << ", column " << this->ColumnNumber<<" : ";
818 throw vtkJSONException(s.str().c_str());
821 //---------------------------------------------------
822 void vtkJSONParser::throwException(const char* message, int ln, int cn) {
824 s << "File : "<< this->FileName;
826 s << ", column :" << cn << " ";
829 throw vtkJSONException(s.str().c_str());
831 //---------------------------------------------------
832 void vtkJSONParser::throwException(const char* message, int ln) {
834 s << "File "<< this->FileName;
835 s << ", line "<<ln <<" : ";
838 throw vtkJSONException(s.str().c_str());
841 //---------------------------------------------------
842 void vtkJSONParser::throwSimpleException(const char* message) {
844 throw vtkJSONException(message);