1 // Copyright (C) 2015 CEA/DEN, EDF R&D, OPEN CASCADE
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 MD "_metadata"
39 #define CMT "_comment"
40 #define TBN "table_name"
41 #define TBD "table_description"
42 #define SHT "short_names"
43 #define LNG "long_names"
65 #define addInfo(info) \
68 I.ln = this->LineNumber; \
69 I.cn = this->ColumnNumber; \
70 I.pos = ftell(this->File); \
71 this->CInfoVector.push_back(I);
73 //---------------------------------------------------
74 bool isBlankOrEnd(const char c) {
75 return c == SPS || c == ENDL || c == TAB || c == EOF;
78 bool isDigitOrDot(const char c) {
79 return (c >= '.' && c <='9') || c == '+' || c == '-' || c == 'e';
83 //---------------------------------------------------
84 vtkJSONException::vtkJSONException(const char *reason) : Reason(reason) {
87 //---------------------------------------------------
88 vtkJSONException::~vtkJSONException() throw () {
91 //---------------------------------------------------
92 const char* vtkJSONException::what() const throw() {
93 return Reason.c_str();
96 // Containers to store information about nodes:
99 //---------------------------------------------------
102 vtkJSONNode() { Name = 0; }
103 virtual ~vtkJSONNode() { }
104 const char* GetName() { return this->Name ; }
105 void SetName(const char* name) { this->Name = name; }
110 class vtkJSONMetaNode : public vtkJSONNode {
112 vtkJSONMetaNode() : vtkJSONNode() {
116 this->TableDescription = 0;
120 virtual ~vtkJSONMetaNode() {
121 delete this->Comment; this->Comment = 0;
122 delete this->TableName; this->TableName = 0;
123 delete this->Date; this->Date= 0;
124 delete this->TableDescription; this->TableDescription = 0;
125 for(int i = 0; i < this->ShortNames.size(); i++) {
126 delete this->ShortNames[i]; this->ShortNames[i] = 0;
128 for(int i = 0; i < this->LongNames.size(); i++) {
129 delete this->LongNames[i]; this->LongNames[i] = 0;
131 for(int i = 0; i < this->Units.size(); i++) {
132 delete this->Units[i]; this->Units[i] = 0;
136 void SetComment(const char* comment) { this->Comment = comment; }
137 const char* GetComment() { return this->Comment; }
139 void SetTableName(const char* name) { this->TableName = name; }
140 const char* GetTableName() { return this->TableName; }
142 void SetDate(const char* name) { this->Date = name; }
143 const char* GetDate() { return this->Date; }
145 void SetTableDescription(const char* description) { this->TableDescription = description; }
146 const char* GetDescription() { return this->TableDescription; }
148 void SetShortNames(std::vector<const char*> names) { this->ShortNames = names; }
149 std::vector<const char*> GetShortNames() { return this->ShortNames; }
151 void SetLongNames(std::vector<const char*> names) { this->LongNames = names; }
152 std::vector<const char*> GetLongNames() { return this->LongNames; }
154 void SetUnits(std::vector<const char*> units) { this->Units = units; }
155 std::vector<const char*> GetUnits() { return this->Units; }
159 const char* TableName;
160 const char* TableDescription;
162 std::vector<const char*> ShortNames;
163 std::vector<const char*> LongNames;
164 std::vector<const char*> Units;
168 bool operator () (const char *a, const char *b) const
170 return strcmp(a,b)<0;
174 typedef std::map<const char*, double, char_cmp> vtkJSONMap;
176 class vtkJSONInfoNode : public vtkJSONNode {
178 vtkJSONInfoNode(const char* name) : vtkJSONNode() {
181 virtual ~vtkJSONInfoNode() {
182 vtkJSONMap::iterator it = this->Values.begin();
183 for( ;it != this->Values.end(); it++) {
185 const char* c = it->first;
189 void AddValue(const char* key, const double value) {
190 this->Values.insert(std::pair<const char*,double>(key,value));
192 vtkJSONMap& GetValues() { return this->Values; }
198 //---------------------------------------------------
199 vtkStandardNewMacro(vtkJSONParser);
201 //---------------------------------------------------
202 vtkJSONParser::vtkJSONParser()
204 this->FileName = NULL;
205 this->LineNumber = 1;
206 this->ColumnNumber = 0;
208 this->InsideQuotes = false;
209 this->LastString = 0;
210 this->CurrentNode = 0;
211 this->ParseList = false;
212 this->ParseObjectList = false;
213 this->LastValue = NAN;
214 this->ShortNamesFilled = false;
217 //---------------------------------------------------
218 vtkJSONParser::~vtkJSONParser()
220 delete this->FileName;
225 //---------------------------------------------------
226 int vtkJSONParser::Parse(vtkTable* theTable)
228 if(!this->FileName) {
229 vtkErrorMacro("The name of the file is not defined");
232 this->File = fopen( this->FileName, "r" );
235 std::string message = std::string("Can't open file: ") + std::string(this->FileName);
236 throwSimpleException(message.c_str());
241 this->ExpectedCharacters.push_back(OCB);
244 ch = fgetc(this->File);
245 processCharacter(ch);
246 if(isDigitsAllowed() && isDigitOrDot(ch)) {
251 case OCB: processOCB(); break;
252 case CCB: processCCB(); break;
254 case OSB: processOSB(); break;
255 case CSB: processCSB(); break;
257 case ENDL: processENDL(); nb = 0; break;
259 case QTS: processQTS(); break;
261 case COLON: processCOLON(); break;
263 case COMMA: processCOMMA(); break;
265 this->ColumnNumber+=nb;
269 if(this->CInfoVector.size() > 0 ) {
270 throwException("braket is not closed ",
271 this->CInfoVector.back().ln,
272 this->CInfoVector.back().cn);
280 //---------------------------------------------------
281 void vtkJSONParser::finalize( vtkTable *t ) {
282 std::vector<vtkJSONNode*>::iterator it = this->Nodes.begin();
283 vtkJSONMetaNode* mn = 0;
284 for( ; it != this->Nodes.end(); it++ ) {
285 mn = dynamic_cast<vtkJSONMetaNode*>(*it);
289 std::vector<const char*> units;
291 if(!mn->GetShortNames().empty()) {
292 this->ShortNames.clear();
293 this->ShortNames = mn->GetShortNames();
295 t->GetInformation()->Set(vtkDataObject::FIELD_NAME(), mn->GetTableName() ? mn->GetTableName() : "");
296 units = mn->GetUnits();
299 long nbRow = mn ? (this->Nodes.size() - 1 ) : this->Nodes.size();
300 for (long col=0; col < this->ShortNames.size(); col++) {
301 vtkDoubleArray* newCol = vtkDoubleArray::New();
302 newCol->SetNumberOfValues(nbRow);
303 vtkJSONInfoNode* in = 0;
304 std::string name = this->ShortNames[col];
306 if(col < units.size()){
312 newCol->SetName(name.c_str());
313 it = this->Nodes.begin();
315 for( ; it != this->Nodes.end(); it++ ) {
316 in = dynamic_cast<vtkJSONInfoNode*>(*it);
318 vtkJSONMap& vl = in->GetValues();
319 vtkJSONMap::iterator mit = vl.find(this->ShortNames[col]);
320 if(mit != vl.end()) {
321 newCol->SetValue(row, mit->second);
324 const char* c = mit->first;
328 std::string s("Item with name '");
330 s+="' has not key '";
331 s+=this->ShortNames[col];
333 throwSimpleException(s.c_str());
337 t->AddColumn(newCol);
339 it = this->Nodes.begin();
340 vtkJSONInfoNode* in = 0;
341 for( ; it != this->Nodes.end(); it++ ) {
342 in = dynamic_cast<vtkJSONInfoNode*>(*it);
344 vtkJSONMap& vl = in->GetValues();
346 std::string s("Item with name '");
348 s+="' has unexpected key '";
349 s+=vl.begin()->first;
351 throwSimpleException(s.c_str());
357 //---------------------------------------------------
358 void vtkJSONParser::processQTS() {
359 this->InsideQuotes = !this->InsideQuotes;
360 if(this->InsideQuotes) {
363 // Quotes is closed, get content
364 Info i = this->CInfoVector.back();
365 this->CInfoVector.pop_back();
368 long end = ftell(this->File) - 1;
369 this->LastString = getString(begin, end);
370 bool parse_list = (this->CInfoVector.size() >= 1 && this->CInfoVector.back().type == OSB);
372 this->CurrentList.push_back(this->LastString);
374 this->Strings.push_back(this->LastString);
378 std::cout<<"String : "<<this->LastString<<std::endl;
381 this->ExpectedCharacters.clear();
382 this->ExpectedCharacters.push_back(COLON);
383 this->ExpectedCharacters.push_back(COMMA);
384 this->ExpectedCharacters.push_back(CCB);
385 this->ExpectedCharacters.push_back(CSB);
390 //---------------------------------------------------
391 void vtkJSONParser::processCOLON() {
392 if (this->InsideQuotes)
394 this->ExpectedCharacters.clear();
395 this->ExpectedCharacters.push_back(OCB);
396 this->ExpectedCharacters.push_back(QTS);
397 this->ExpectedCharacters.push_back(OSB);
398 if(GetInfoNode() && Strings.size() == 1 ) {
403 //---------------------------------------------------
404 void vtkJSONParser::processOCB() {
405 if (this->InsideQuotes)
407 this->ExpectedCharacters.clear();
408 this->ExpectedCharacters.push_back(QTS);
409 this->ExpectedCharacters.push_back(CCB);
412 if(this->CInfoVector.size() >= 1) {
413 if ( !GetMetaNode() && this->Strings.size() > 0 &&
414 this->Strings.back() &&
415 strcmp(this->Strings.back(), MD) == 0 ) {
417 std::cout<<"Create new Meta Node !!!"<<std::endl;
419 this->CurrentNode = new vtkJSONMetaNode();
420 delete this->Strings.back();
421 this->Strings.back() = 0;
422 this->Strings.pop_back();
424 if(this->CInfoVector.back().type == OSB ) {
425 this->ParseObjectList = true;
428 std::cout<<"Create new Node with name '"<<(this->Strings.size() == 0 ? "" : this->Strings.back())<<"' !!!"<<std::endl;
430 this->CurrentNode = new vtkJSONInfoNode(this->Strings.size() == 0 ? "" : this->Strings.back());
431 if(!this->ParseObjectList && this->Strings.size() == 1) {
432 this->Strings.pop_back();
439 //---------------------------------------------------
440 vtkJSONMetaNode* vtkJSONParser::GetMetaNode() {
441 vtkJSONMetaNode *mnode = 0;
442 if( this->CurrentNode ) {
443 mnode = dynamic_cast<vtkJSONMetaNode*>(this->CurrentNode);
448 //---------------------------------------------------
449 vtkJSONInfoNode* vtkJSONParser::GetInfoNode() {
450 vtkJSONInfoNode *mnode = 0;
451 if( this->CurrentNode ) {
452 mnode = dynamic_cast<vtkJSONInfoNode*>(this->CurrentNode);
457 //---------------------------------------------------
458 void vtkJSONParser::processENDL() {
459 if(this->InsideQuotes) {
461 throwException("quote is not closed !");
464 this->ColumnNumber=0;
468 //---------------------------------------------------
469 void vtkJSONParser::processCSB() {
470 if (this->InsideQuotes)
473 if(this->CInfoVector.back().type == OSB) {
474 if(this->ParseList) {
475 this->ParseList = false;
477 if(this->ParseObjectList) {
478 this->ParseObjectList = false;
480 this->CInfoVector.pop_back();
483 this->ExpectedCharacters.clear();
484 this->ExpectedCharacters.push_back(COMMA);
485 this->ExpectedCharacters.push_back(OCB);
486 this->ExpectedCharacters.push_back(CCB);
489 //---------------------------------------------------
490 void vtkJSONParser::processOSB() {
491 if (this->InsideQuotes)
494 if(this->ParseList) {
495 Info i = CInfoVector.back();
497 throwException("list, which has been opened in this place, has not been closed !", i.ln, i.cn);
501 this->ParseList = true;
503 if( this->Strings.size() > 0 ) {
504 delete this->Strings[Strings.size()-1];
505 this->Strings[Strings.size()-1] = 0;
506 this->Strings.pop_back();
510 this->ExpectedCharacters.clear();
511 this->ExpectedCharacters.push_back(QTS);
512 this->ExpectedCharacters.push_back(OCB);
515 //---------------------------------------------------
516 void vtkJSONParser::processCCB() {
517 if (this->InsideQuotes)
520 this->ExpectedCharacters.clear();
521 this->ExpectedCharacters.push_back(COMMA);
522 this->ExpectedCharacters.push_back(CCB);
523 if(this->ParseObjectList) {
524 this->ExpectedCharacters.push_back(CSB);
530 if(this->CurrentNode)
531 this->Nodes.push_back(this->CurrentNode);
532 if( !this->ShortNamesFilled ){
533 vtkJSONInfoNode* n = dynamic_cast<vtkJSONInfoNode*>(this->CurrentNode);
535 this->ShortNamesFilled = true;
540 if(this->CurrentNode)
541 std::cout<<"End parsing node with name '"<<this->CurrentNode->GetName()<<"' !!!!"<<std::endl;
544 if (this->CInfoVector.size() > 0 && this->CInfoVector.back().type == OCB ) {
545 this->CInfoVector.pop_back();
547 throwException ("unexpected closed braket '}' !");
550 this->CurrentNode = 0;
553 //---------------------------------------------------
554 void vtkJSONParser::processCOMMA() {
555 if (this->InsideQuotes)
557 this->ExpectedCharacters.clear();
558 this->ExpectedCharacters.push_back(QTS);
559 this->ExpectedCharacters.push_back(OCB);
564 void vtkJSONParser::processMetaNode() {
565 vtkJSONMetaNode* mn = GetMetaNode();
567 bool strings = this->Strings.size() == 2 && !this->ParseList;
568 bool str_and_list = (this->Strings.size() == 1 && this->CurrentList.size() > 0 && !this->ParseList);
571 if ( strcmp(this->Strings[0], CMT) == 0 ) {
572 mn->SetComment(this->Strings[1]);
574 std::cout<<"Table Comment : "<<this->Strings[1]<<std::endl;
576 } else if ( strcmp(this->Strings[0], TBN) == 0 ) {
577 mn->SetTableName(this->Strings[1]);
579 std::cout<<"Table Name : "<<this->Strings[1]<<std::endl;
581 } else if ( strcmp(this->Strings[0], TBD) == 0 ) {
582 mn->SetTableDescription(this->Strings[1]);
584 std::cout<<"Table Description : "<<this->Strings[1]<<std::endl;
586 } else if ( strcmp(this->Strings[0], DT) == 0 ) {
587 mn->SetDate(this->Strings[1]);
589 std::cout<<"Date : "<<this->Strings[1]<<std::endl;
593 s << "File : "<< this->FileName;
594 s << ", line "<<this->LineNumber;
595 s << " unexpected key world: '"<<this->Strings[0]<<"'";
597 delete this->Strings[0];
598 this->Strings[0] = 0;
602 } else if(str_and_list) {
603 if ( strcmp(this->Strings[0], SHT) == 0 ) {
604 std::vector<const char*>::const_iterator it = this->CurrentList.begin();
605 for( ;it != this->CurrentList.end(); it++) {
608 mn->SetShortNames(this->CurrentList);
610 std::cout<<"Short Names : "<<std::endl;
612 } else if ( strcmp(this->Strings[0], LNG) == 0 ) {
613 mn->SetLongNames(this->CurrentList);
615 std::cout<<"Long Names : "<<std::endl;
617 } else if ( strcmp(this->Strings[0], UNT) == 0 ) {
618 mn->SetUnits(this->CurrentList);
620 std::cout<<"Units : ";
624 s << "File : "<< this->FileName;
625 s << ", line "<<this->LineNumber;
626 s << " unexpected key world: '"<<this->Strings[0]<<"'";
628 delete this->Strings[0];
629 this->Strings[0] = 0;
632 std::vector<const char*>::const_iterator it = this->CurrentList.begin();
634 for( ;it != this->CurrentList.end(); it++) {
635 std::cout<<"'"<<*it<<"'";
636 if ( it+1 != this->CurrentList.end() )
639 std::cout<<" ]"<<std::endl;
641 this->CurrentList.clear();
645 //---------------------------------------------------
646 void vtkJSONParser::processInfoNode() {
647 vtkJSONInfoNode* in = GetInfoNode();
649 if(this->Strings.size() == 1 && !isnan(this->LastValue)) {
650 in->AddValue(this->Strings[0],this->LastValue);
651 if(!ShortNamesFilled) {
652 char* name = new char[strlen(Strings[0])];
653 strcpy(name, Strings[0]);
654 this->ShortNames.push_back(name);
656 this->Strings.pop_back();
657 this->LastValue = NAN;
662 //---------------------------------------------------
663 void vtkJSONParser::processCharacter(const char ch) {
664 if (this->InsideQuotes)
669 if(this->ExpectedCharacters.empty())
672 std::vector<char>::const_iterator it = std::find(this->ExpectedCharacters.begin(),
673 this->ExpectedCharacters.end(),
676 // Unexpected character is found
677 if(it == this->ExpectedCharacters.end()) {
678 std::string s("unexpected character '");
681 throwException(s.c_str());
686 //---------------------------------------------------
687 char* vtkJSONParser::getString(long b, long e) {
690 long old_pos = ftell(this->File);
691 fseek(this->File, b, SEEK_SET);
693 result = new char[data_s];
695 size_t nb_read = fread(result, sizeof(char), data_s, this->File);
696 result[nb_read] = '\0';
697 fseek(this->File, old_pos, SEEK_SET);
701 //---------------------------------------------------
702 void vtkJSONParser::allowsDigits() {
703 for(char c = '.'; c <= '9'; c++) {
704 ExpectedCharacters.push_back(c);
706 ExpectedCharacters.push_back('-');
707 ExpectedCharacters.push_back('+');
708 ExpectedCharacters.push_back('e');
711 //---------------------------------------------------
712 bool vtkJSONParser::isDigitsAllowed() {
713 std::vector<char>::const_iterator it = std::find(this->ExpectedCharacters.begin(),
714 this->ExpectedCharacters.end(),
716 return (it != this->ExpectedCharacters.end());
719 //---------------------------------------------------
720 void vtkJSONParser::readDoubleValue() {
721 long b = ftell(this->File);
724 char ch = fgetc(this->File);
725 if(!isDigitOrDot(ch)) {
730 long e = ftell(this->File);
731 fseek(this->File, b-1, SEEK_SET);
733 char* result = new char[data_s];
735 size_t nb_read = fread(result, sizeof(char), data_s, this->File);
736 result[nb_read] = '\0';
737 this->ExpectedCharacters.clear();
738 this->ExpectedCharacters.push_back(COMMA);
739 this->ExpectedCharacters.push_back(CCB);
740 this->LastValue = atof(result);
742 std::cout<<"Read number : "<<this->LastValue<<std::endl;
746 //---------------------------------------------------
747 void vtkJSONParser::checkShortName(const char* name) {
748 size_t ln = strlen(name);
750 for( size_t i = 0; i < ln; i++ ) {
752 if(!(name[i] >= 'a' && name[i] <= 'z') &&
754 !(name[i] >= 'A' && name[i] <= 'Z') ) {
755 std::string s("wrong short name '");
758 throwException(s.c_str(), this->LineNumber);
764 void vtkJSONParser::clean() {
765 std::vector<vtkJSONNode*>::iterator it = this->Nodes.begin();
766 for( ; it != this->Nodes.end(); it++ ) {
772 //---------------------------------------------------
773 void vtkJSONParser::throwException(const char* message) {
775 s << "File : "<< this->FileName;
776 s << ", line "<<this->LineNumber;
777 s << ", column " << this->ColumnNumber<<" : ";
780 throw vtkJSONException(s.str().c_str());
783 //---------------------------------------------------
784 void vtkJSONParser::throwException(const char* message, int ln, int cn) {
786 s << "File : "<< this->FileName;
788 s << ", column :" << cn << " ";
791 throw vtkJSONException(s.str().c_str());
793 //---------------------------------------------------
794 void vtkJSONParser::throwException(const char* message, int ln) {
796 s << "File "<< this->FileName;
797 s << ", line "<<ln <<" : ";
800 throw vtkJSONException(s.str().c_str());
803 //---------------------------------------------------
804 void vtkJSONParser::throwSimpleException(const char* message) {
806 throw vtkJSONException(message);