1 // Copyright (C) 2015-2020 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 <vtkDoubleArray.h>
24 #include <vtkInformation.h>
25 #include <vtkObjectFactory.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"
69 #define addInfo(info) \
72 I.ln = this->LineNumber; \
73 I.cn = this->ColumnNumber; \
74 I.pos = ftell(this->File); \
75 this->CInfoVector.push_back(I);
77 //---------------------------------------------------
78 bool isBlankOrEnd(const char c)
80 return c == SPS || c == ENDL || c == TAB || c == EOF;
83 bool isDigitOrDot(const char c)
85 return (c >= '.' && c <= '9') || c == '+' || c == '-' || c == 'e';
89 //---------------------------------------------------
90 vtkJSONException::vtkJSONException(const char* reason)
95 //---------------------------------------------------
96 vtkJSONException::~vtkJSONException() noexcept
100 //---------------------------------------------------
101 const char* vtkJSONException::what() const noexcept
103 return Reason.c_str();
106 // Containers to store information about nodes:
109 //---------------------------------------------------
113 vtkJSONNode() { Name = 0; }
114 virtual ~vtkJSONNode() {}
115 const char* GetName() { return this->Name; }
116 void SetName(const char* name) { this->Name = name; }
122 class vtkJSONMetaNode : public vtkJSONNode
131 this->TableDescription = 0;
135 virtual ~vtkJSONMetaNode()
137 delete this->Comment;
139 delete this->TableName;
143 delete this->TableDescription;
144 this->TableDescription = 0;
145 for (int i = 0; i < this->ShortNames.size(); i++)
147 delete this->ShortNames[i];
148 this->ShortNames[i] = 0;
150 for (int i = 0; i < this->LongNames.size(); i++)
152 delete this->LongNames[i];
153 this->LongNames[i] = 0;
155 for (int i = 0; i < this->Units.size(); i++)
157 delete this->Units[i];
162 void SetComment(const char* comment) { this->Comment = comment; }
163 const char* GetComment() { return this->Comment; }
165 void SetTableName(const char* name) { this->TableName = name; }
166 const char* GetTableName() { return this->TableName; }
168 void SetDate(const char* name) { this->Date = name; }
169 const char* GetDate() { return this->Date; }
171 void SetTableDescription(const char* description) { this->TableDescription = description; }
172 const char* GetDescription() { return this->TableDescription; }
174 void SetShortNames(std::vector<const char*> names) { this->ShortNames = names; }
175 std::vector<const char*> GetShortNames() { return this->ShortNames; }
177 void SetLongNames(std::vector<const char*> names) { this->LongNames = names; }
178 std::vector<const char*> GetLongNames() { return this->LongNames; }
180 void SetUnits(std::vector<const char*> units) { this->Units = units; }
181 std::vector<const char*> GetUnits() { return this->Units; }
185 const char* TableName;
186 const char* TableDescription;
188 std::vector<const char*> ShortNames;
189 std::vector<const char*> LongNames;
190 std::vector<const char*> Units;
195 bool operator()(const char* a, const char* b) const { return strcmp(a, b) < 0; }
198 typedef std::map<const char*, double, char_cmp> vtkJSONMap;
200 class vtkJSONInfoNode : public vtkJSONNode
203 vtkJSONInfoNode(const char* name)
208 virtual ~vtkJSONInfoNode()
210 vtkJSONMap::iterator it = this->Values.begin();
211 for (; it != this->Values.end(); it++)
214 const char* c = it->first;
218 void AddValue(const char* key, const double value)
220 this->Values.insert(std::pair<const char*, double>(key, value));
222 vtkJSONMap& GetValues() { return this->Values; }
228 //---------------------------------------------------
229 vtkStandardNewMacro(vtkJSONParser);
231 //---------------------------------------------------
232 vtkJSONParser::vtkJSONParser()
234 this->FileName = nullptr;
235 this->LineNumber = 1;
236 this->ColumnNumber = 0;
238 this->InsideQuotes = false;
239 this->LastString = 0;
240 this->CurrentNode = 0;
241 this->ParseList = false;
242 this->ParseObjectList = false;
243 this->LastValue = NAN;
244 this->ShortNamesFilled = false;
247 //---------------------------------------------------
248 vtkJSONParser::~vtkJSONParser()
250 delete this->FileName;
251 this->FileName = nullptr;
254 //---------------------------------------------------
255 int vtkJSONParser::Parse(vtkTable* theTable)
259 vtkErrorMacro("The name of the file is not defined");
262 this->File = fopen(this->FileName, "r");
266 std::string message = std::string("Can't open file: ") + std::string(this->FileName);
267 throwSimpleException(message.c_str());
272 this->ExpectedCharacters.push_back(OCB);
276 ch = fgetc(this->File);
277 processCharacter(ch);
278 if (isDigitsAllowed() && isDigitOrDot(ch))
316 this->ColumnNumber += nb;
320 if (this->CInfoVector.size() > 0)
323 "braket is not closed ", this->CInfoVector.back().ln, this->CInfoVector.back().cn);
331 //---------------------------------------------------
332 void vtkJSONParser::finalize(vtkTable* t)
334 std::vector<vtkJSONNode*>::iterator it = this->Nodes.begin();
335 vtkJSONMetaNode* mn = 0;
336 for (; it != this->Nodes.end(); it++)
338 mn = dynamic_cast<vtkJSONMetaNode*>(*it);
342 std::vector<const char*> units;
345 if (!mn->GetShortNames().empty())
347 this->ShortNames.clear();
348 this->ShortNames = mn->GetShortNames();
350 t->GetInformation()->Set(
351 vtkDataObject::FIELD_NAME(), mn->GetTableName() ? mn->GetTableName() : "");
352 units = mn->GetUnits();
355 long nbRow = mn ? (this->Nodes.size() - 1) : this->Nodes.size();
356 for (long col = 0; col < this->ShortNames.size(); col++)
358 vtkDoubleArray* newCol = vtkDoubleArray::New();
359 newCol->SetNumberOfValues(nbRow);
360 vtkJSONInfoNode* in = 0;
361 std::string name = this->ShortNames[col];
363 if (col < units.size())
372 newCol->SetName(name.c_str());
373 it = this->Nodes.begin();
375 for (; it != this->Nodes.end(); it++)
377 in = dynamic_cast<vtkJSONInfoNode*>(*it);
380 vtkJSONMap& vl = in->GetValues();
381 vtkJSONMap::iterator mit = vl.find(this->ShortNames[col]);
384 newCol->SetValue(row, mit->second);
385 const char* c = mit->first;
393 std::string s("Item with name '");
395 s += "' has no key (or not a numerical value for key) '";
396 s += this->ShortNames[col];
397 s += "'! Value set to 0.0.";
398 // throwSimpleException(s.c_str());
399 std::ostringstream oss;
400 oss << "vtkJSONParser::finalize(): " << s << std::endl;
401 if (this->HasObserver("ErrorEvent"))
402 this->InvokeEvent("ErrorEvent", const_cast<char*>(oss.str().c_str()));
404 vtkOutputWindowDisplayErrorText(const_cast<char*>(oss.str().c_str()));
405 vtkObject::BreakOnError();
407 newCol->SetValue(row, 0.0);
411 t->AddColumn(newCol);
413 it = this->Nodes.begin();
414 vtkJSONInfoNode* in = 0;
415 for (; it != this->Nodes.end(); it++)
417 in = dynamic_cast<vtkJSONInfoNode*>(*it);
420 vtkJSONMap& vl = in->GetValues();
423 std::string s("Item with name '");
425 s += "' has unexpected key '";
426 s += vl.begin()->first;
428 throwSimpleException(s.c_str());
434 //---------------------------------------------------
435 void vtkJSONParser::processQTS()
437 this->InsideQuotes = !this->InsideQuotes;
438 if (this->InsideQuotes)
444 // Quotes is closed, get content
445 Info i = this->CInfoVector.back();
446 this->CInfoVector.pop_back();
450 long end = ftell(this->File) - 1;
451 this->LastString = getString(begin, end);
452 bool parse_list = (this->CInfoVector.size() >= 1 && this->CInfoVector.back().type == OSB);
455 this->CurrentList.push_back(this->LastString);
459 this->Strings.push_back(this->LastString);
463 std::cout << "String : " << this->LastString << std::endl;
466 this->ExpectedCharacters.clear();
467 this->ExpectedCharacters.push_back(COLON);
468 this->ExpectedCharacters.push_back(COMMA);
469 this->ExpectedCharacters.push_back(CCB);
470 this->ExpectedCharacters.push_back(CSB);
475 //---------------------------------------------------
476 void vtkJSONParser::processCOLON()
478 if (this->InsideQuotes)
480 this->ExpectedCharacters.clear();
481 this->ExpectedCharacters.push_back(OCB);
482 this->ExpectedCharacters.push_back(QTS);
483 this->ExpectedCharacters.push_back(OSB);
484 if (GetInfoNode() && Strings.size() == 1)
490 //---------------------------------------------------
491 void vtkJSONParser::processOCB()
493 if (this->InsideQuotes)
495 this->ExpectedCharacters.clear();
496 this->ExpectedCharacters.push_back(QTS);
497 this->ExpectedCharacters.push_back(CCB);
500 if (this->CInfoVector.size() >= 1)
502 if (!GetMetaNode() && this->Strings.size() > 0 && this->Strings.back() &&
503 strcmp(this->Strings.back(), MD) == 0)
506 std::cout << "Create new Meta Node !!!" << std::endl;
508 this->CurrentNode = new vtkJSONMetaNode();
509 delete this->Strings.back();
510 this->Strings.back() = 0;
511 this->Strings.pop_back();
515 if (this->CInfoVector.back().type == OSB)
517 this->ParseObjectList = true;
520 std::cout << "Create new Node with name '"
521 << (this->Strings.size() == 0 ? "" : this->Strings.back()) << "' !!!" << std::endl;
524 new vtkJSONInfoNode(this->Strings.size() == 0 ? "" : this->Strings.back());
525 if (!this->ParseObjectList && this->Strings.size() == 1)
527 this->Strings.pop_back();
534 //---------------------------------------------------
535 vtkJSONMetaNode* vtkJSONParser::GetMetaNode()
537 vtkJSONMetaNode* mnode = 0;
538 if (this->CurrentNode)
540 mnode = dynamic_cast<vtkJSONMetaNode*>(this->CurrentNode);
545 //---------------------------------------------------
546 vtkJSONInfoNode* vtkJSONParser::GetInfoNode()
548 vtkJSONInfoNode* mnode = 0;
549 if (this->CurrentNode)
551 mnode = dynamic_cast<vtkJSONInfoNode*>(this->CurrentNode);
556 //---------------------------------------------------
557 void vtkJSONParser::processENDL()
559 if (this->InsideQuotes)
562 throwException("quote is not closed !");
565 this->ColumnNumber = 0;
568 //---------------------------------------------------
569 void vtkJSONParser::processCSB()
571 if (this->InsideQuotes)
574 if (this->CInfoVector.back().type == OSB)
578 this->ParseList = false;
580 if (this->ParseObjectList)
582 this->ParseObjectList = false;
584 this->CInfoVector.pop_back();
587 this->ExpectedCharacters.clear();
588 this->ExpectedCharacters.push_back(COMMA);
589 this->ExpectedCharacters.push_back(OCB);
590 this->ExpectedCharacters.push_back(CCB);
593 //---------------------------------------------------
594 void vtkJSONParser::processOSB()
596 if (this->InsideQuotes)
601 Info i = CInfoVector.back();
605 "list, which has been opened in this place, has not been closed !", i.ln, i.cn);
610 this->ParseList = true;
614 if (this->Strings.size() > 0)
616 delete this->Strings[Strings.size() - 1];
617 this->Strings[Strings.size() - 1] = 0;
618 this->Strings.pop_back();
622 this->ExpectedCharacters.clear();
623 this->ExpectedCharacters.push_back(QTS);
624 this->ExpectedCharacters.push_back(OCB);
627 //---------------------------------------------------
628 void vtkJSONParser::processCCB()
630 if (this->InsideQuotes)
633 this->ExpectedCharacters.clear();
634 this->ExpectedCharacters.push_back(COMMA);
635 this->ExpectedCharacters.push_back(CCB);
636 if (this->ParseObjectList)
638 this->ExpectedCharacters.push_back(CSB);
644 if (this->CurrentNode)
645 this->Nodes.push_back(this->CurrentNode);
646 if (!this->ShortNamesFilled)
648 vtkJSONInfoNode* n = dynamic_cast<vtkJSONInfoNode*>(this->CurrentNode);
651 this->ShortNamesFilled = true;
656 if (this->CurrentNode)
657 std::cout << "End parsing node with name '" << this->CurrentNode->GetName() << "' !!!!"
661 if (this->CInfoVector.size() > 0 && this->CInfoVector.back().type == OCB)
663 this->CInfoVector.pop_back();
667 throwException("unexpected closed braket '}' !");
670 this->CurrentNode = 0;
673 //---------------------------------------------------
674 void vtkJSONParser::processCOMMA()
676 if (this->InsideQuotes)
678 this->ExpectedCharacters.clear();
679 this->ExpectedCharacters.push_back(QTS);
680 this->ExpectedCharacters.push_back(OCB);
685 void vtkJSONParser::processMetaNode()
687 vtkJSONMetaNode* mn = GetMetaNode();
690 bool strings = this->Strings.size() == 2 && !this->ParseList;
692 (this->Strings.size() == 1 && this->CurrentList.size() > 0 && !this->ParseList);
696 if (strcmp(this->Strings[0], CMT) == 0)
698 mn->SetComment(this->Strings[1]);
700 std::cout << "Table Comment : " << this->Strings[1] << std::endl;
703 else if (strcmp(this->Strings[0], TBN) == 0)
705 mn->SetTableName(this->Strings[1]);
707 std::cout << "Table Name : " << this->Strings[1] << std::endl;
710 else if (strcmp(this->Strings[0], TBD) == 0)
712 mn->SetTableDescription(this->Strings[1]);
714 std::cout << "Table Description : " << this->Strings[1] << std::endl;
717 else if (strcmp(this->Strings[0], DT) == 0)
719 mn->SetDate(this->Strings[1]);
721 std::cout << "Date : " << this->Strings[1] << std::endl;
727 s << "File : " << this->FileName;
728 s << ", line " << this->LineNumber;
729 s << " unexpected key word: '" << this->Strings[0] << "'";
731 delete this->Strings[0];
732 this->Strings[0] = 0;
736 else if (str_and_list)
738 if (strcmp(this->Strings[0], SHT) == 0)
740 std::vector<const char*>::const_iterator it = this->CurrentList.begin();
741 for (; it != this->CurrentList.end(); it++)
745 mn->SetShortNames(this->CurrentList);
747 std::cout << "Short Names : " << std::endl;
750 else if (strcmp(this->Strings[0], LNG) == 0)
752 mn->SetLongNames(this->CurrentList);
754 std::cout << "Long Names : " << std::endl;
757 else if (strcmp(this->Strings[0], UNT) == 0)
759 mn->SetUnits(this->CurrentList);
761 std::cout << "Units : ";
767 s << "File : " << this->FileName;
768 s << ", line " << this->LineNumber;
769 s << " unexpected key word: '" << this->Strings[0] << "'";
771 delete this->Strings[0];
772 this->Strings[0] = 0;
775 std::vector<const char*>::const_iterator it = this->CurrentList.begin();
777 for (; it != this->CurrentList.end(); it++)
779 std::cout << "'" << *it << "'";
780 if (it + 1 != this->CurrentList.end())
783 std::cout << " ]" << std::endl;
785 this->CurrentList.clear();
789 //---------------------------------------------------
790 void vtkJSONParser::processInfoNode()
792 vtkJSONInfoNode* in = GetInfoNode();
795 if (this->Strings.size() == 1 && !isnan(this->LastValue))
797 in->AddValue(this->Strings[0], this->LastValue);
798 if (!ShortNamesFilled)
800 char* name = new char[strlen(Strings[0])];
801 strcpy(name, Strings[0]);
802 this->ShortNames.push_back(name);
804 this->Strings.pop_back();
805 this->LastValue = NAN;
807 if (this->Strings.size() == 2)
809 std::string s("Item with name '");
811 s += "' has not a numerical value for key '";
813 s += "'! Value set to 0.0.";
814 // throwSimpleException(s.c_str());
815 std::ostringstream oss;
816 oss << "vtkJSONParser::processInfoNode(): " << s << std::endl;
817 if (this->HasObserver("ErrorEvent"))
818 this->InvokeEvent("ErrorEvent", const_cast<char*>(oss.str().c_str()));
820 vtkOutputWindowDisplayErrorText(const_cast<char*>(oss.str().c_str()));
821 vtkObject::BreakOnError();
823 in->AddValue(this->Strings[0], 0.0);
824 if (!ShortNamesFilled)
826 char* name = new char[strlen(Strings[0])];
827 strcpy(name, Strings[0]);
828 this->ShortNames.push_back(name);
830 this->Strings.clear();
831 this->LastValue = NAN;
836 //---------------------------------------------------
837 void vtkJSONParser::processCharacter(const char ch)
839 if (this->InsideQuotes)
841 if (isBlankOrEnd(ch))
844 if (this->ExpectedCharacters.empty())
847 std::vector<char>::const_iterator it =
848 std::find(this->ExpectedCharacters.begin(), this->ExpectedCharacters.end(), ch);
850 // Unexpected character is found
851 if (it == this->ExpectedCharacters.end())
853 std::string s("unexpected character '");
856 throwException(s.c_str());
860 //---------------------------------------------------
861 char* vtkJSONParser::getString(long b, long e)
865 long old_pos = ftell(this->File);
866 fseek(this->File, b, SEEK_SET);
868 result = new char[data_s + 1]; // + 1 for the '\0' symbol
870 size_t nb_read = fread(result, sizeof(char), data_s, this->File);
871 result[nb_read] = '\0';
872 fseek(this->File, old_pos, SEEK_SET);
876 //---------------------------------------------------
877 void vtkJSONParser::allowsDigits()
879 for (char c = '.'; c <= '9'; c++)
881 ExpectedCharacters.push_back(c);
883 ExpectedCharacters.push_back('-');
884 ExpectedCharacters.push_back('+');
885 ExpectedCharacters.push_back('e');
888 //---------------------------------------------------
889 bool vtkJSONParser::isDigitsAllowed()
891 std::vector<char>::const_iterator it =
892 std::find(this->ExpectedCharacters.begin(), this->ExpectedCharacters.end(), '0');
893 return (it != this->ExpectedCharacters.end());
896 //---------------------------------------------------
897 void vtkJSONParser::readDoubleValue()
899 long b = ftell(this->File);
903 char ch = fgetc(this->File);
904 if (!isDigitOrDot(ch))
910 long e = ftell(this->File);
911 fseek(this->File, b - 1, SEEK_SET);
913 char* result = new char[data_s];
915 size_t nb_read = fread(result, sizeof(char), data_s, this->File);
916 result[nb_read] = '\0';
917 this->ExpectedCharacters.clear();
918 this->ExpectedCharacters.push_back(COMMA);
919 this->ExpectedCharacters.push_back(CCB);
920 this->LastValue = atof(result);
922 std::cout << "Read number : " << this->LastValue << std::endl;
926 //---------------------------------------------------
927 void vtkJSONParser::checkShortName(const char* name)
929 size_t ln = strlen(name);
932 for (size_t i = 0; i < ln; i++)
935 if (!(name[i] >= 'a' && name[i] <= 'z') &&
937 !(name[i] >= 'A' && name[i] <= 'Z'))
939 std::string s("wrong short name '");
942 throwException(s.c_str(), this->LineNumber);
948 void vtkJSONParser::clean()
950 std::vector<vtkJSONNode*>::iterator it = this->Nodes.begin();
951 for (; it != this->Nodes.end(); it++)
958 //---------------------------------------------------
959 void vtkJSONParser::throwException(const char* message)
962 s << "File : " << this->FileName;
963 s << ", line " << this->LineNumber;
964 s << ", column " << this->ColumnNumber << " : ";
967 throw vtkJSONException(s.str().c_str());
970 //---------------------------------------------------
971 void vtkJSONParser::throwException(const char* message, int ln, int cn)
974 s << "File : " << this->FileName;
975 s << ", line " << ln;
976 s << ", column :" << cn << " ";
979 throw vtkJSONException(s.str().c_str());
981 //---------------------------------------------------
982 void vtkJSONParser::throwException(const char* message, int ln)
985 s << "File " << this->FileName;
986 s << ", line " << ln << " : ";
989 throw vtkJSONException(s.str().c_str());
992 //---------------------------------------------------
993 void vtkJSONParser::throwSimpleException(const char* message)
996 throw vtkJSONException(message);