2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/builder/json-parser-state.h>
37 // true if character represent a digit
38 inline bool IsDigit(char c)
40 return (c >= '0' && c <= '9');
43 // convert string to integer
44 bool StringToInteger(const char *first, const char *last, int& out)
54 else if (*first == '+')
60 // json error for int starting with zero
61 if( 0 == (*first - '0') && (first+1 != last))
67 for (; first != last && IsDigit(*first); ++first)
69 result = 10 * result + (*first - '0');
83 // convert hexadecimal string to unsigned integer
84 bool HexStringToUnsignedInteger(const char *first, const char *last, unsigned int& out)
86 unsigned int result = 0;
87 for (; first != last; ++first)
94 else if (*first >= 'a' && *first <= 'f')
96 digit = *first - 'a' + 10;
98 else if (*first >= 'A' && *first <= 'F')
100 digit = *first - 'A' + 10;
106 result = 16 * result + digit;
120 // convert string to floating point
121 bool StringToFloat(const char* first, const char* last, float& out)
132 else if (*first == '+')
140 for (; first != last && IsDigit(*first); ++first)
142 result = 10 * result + (*first - '0');
146 if (first != last && *first == '.')
150 float inv_base = 0.1f;
151 for (; first != last && IsDigit(*first); ++first)
153 result += (*first - '0') * inv_base;
158 // result w\o exponent
162 bool exponent_negative = false;
164 if (first != last && (*first == 'e' || *first == 'E'))
170 exponent_negative = true;
173 else if (*first == '+')
178 if(first == last || !IsDigit(*first))
183 for (; first != last && IsDigit(*first); ++first)
185 exponent = 10 * exponent + (*first - '0');
191 float power_of_ten = 10;
192 for (; exponent > 1; exponent--)
197 if (exponent_negative)
199 result /= power_of_ten;
203 result *= power_of_ten;
220 bool IsNumber(char c)
250 JsonParserState::JsonParserState(TreeNode* _root)
251 : mRoot(_root), mCurrent(_root),
252 mErrorDescription(nullptr), mErrorNewLine(0), mErrorColumn(0), mErrorPosition(0),
253 mNumberOfParsedChars(0), mNumberOfCreatedNodes(0), mFirstParse(false),
262 TreeNode* JsonParserState::CreateNewNode(const char* name, TreeNode::NodeType type)
264 TreeNode* node = nullptr;
266 node = TreeNodeManipulator::NewTreeNode();
267 TreeNodeManipulator modifyNew(node);
268 modifyNew.SetType(type);
269 modifyNew.SetName(name);
273 mCurrent = TreeNodeManipulator(mRoot);
277 mCurrent.AddChild(node);
278 mCurrent = modifyNew;
281 ++mNumberOfCreatedNodes;
287 TreeNode* JsonParserState::NewNode(const char* name, TreeNode::NodeType type)
289 TreeNode* node = nullptr;
293 node = CreateNewNode(name, type);
301 const TreeNode* found = mCurrent.GetChild(name);
302 if( nullptr != found )
304 node = const_cast<TreeNode*>(found);
310 if( mCurrent.GetParent() == nullptr )
318 // walk tree and deallocate children as were replacing this node
319 TreeNodeManipulator modify(node);
321 modify.SetName(name);
323 // Set the type of the existing node.
324 // Where the new type is different, then any children of this node will
326 // When the type is an array of numbers, then this will also remove any children
327 // When the type is an object or other array, then the children will not be removed,
328 // but will instead follow these replace rules.
329 modify.SetType(type);
335 // if not found then create new
336 node = CreateNewNode(name, type);
343 TreeNode* JsonParserState::GetRoot()
348 bool JsonParserState::Error(const char* description)
350 mErrorDescription = description;
354 bool JsonParserState::ParseWhiteSpace()
356 bool c_comment = false;
357 bool cpp_comment = false;
390 continue; // rather than carry on as comments may be back to back
393 else if( !c_comment && (c == '/' && nextChar == '/') )
400 if( c == '*' && nextChar == '/' )
407 else if( !cpp_comment && (c == '/' && nextChar == '*') )
412 if( ! (c_comment || cpp_comment) )
414 if( ! (c == '\x20' || c == '\x9' || c == '\xD' || c == '\xA' ) )
420 if( AdvanceEnded(1) )
430 bool JsonParserState::ParseSymbol(const std::string& symbol)
432 if( AtLeast( symbol.size() ) )
434 for(int i = 0; i < static_cast<int>( symbol.size() ); ++i)
436 if(*mIter != symbol[i])
450 bool JsonParserState::ParseTrue()
452 if( ParseSymbol("true") )
454 mCurrent.SetInteger(1);
455 mCurrent.SetType(TreeNode::BOOLEAN);
460 return Error("Unexpected character; expected symbol ie 'true'");
464 bool JsonParserState::ParseFalse()
466 if( ParseSymbol("false") )
468 mCurrent.SetInteger(0);
469 mCurrent.SetType(TreeNode::BOOLEAN);
474 return Error("Unexpected character; expected symbol ie 'false'");
478 bool JsonParserState::ParseNULL()
480 if( ParseSymbol("null") )
482 mCurrent.SetType(TreeNode::IS_NULL);
487 return Error("Unexpected character; expected symbol ie 'null'");
491 bool JsonParserState::ParseNumber()
493 mCurrent.SetType( TreeNode::INTEGER );
495 VectorCharIter first = mIter;
498 if( !(c == '-' || IsNumber(c) ) )
500 return Error("Number must start with '-' or 0-9");
503 while ( IsNumber(c) || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-' )
505 if (c == '.' || c == 'e' || c == 'E')
507 mCurrent.SetType( TreeNode::FLOAT );
513 if( mCurrent.GetType() == TreeNode::INTEGER )
516 if( StringToInteger(&(*first), &(*mIter), i ) )
518 mCurrent.SetInteger(i);
522 return Error("Bad integer number");
526 if(mCurrent.GetType() == TreeNode::FLOAT)
529 if( StringToFloat(&(*first), &(*mIter), f) )
531 mCurrent.SetFloat(f);
535 return Error("Bad float number");
539 return (mCurrent.GetType() == TreeNode::INTEGER) || (mCurrent.GetType() == TreeNode::FLOAT);
542 char* JsonParserState::EncodeString()
544 int substitution = 0;
545 VectorCharIter first = mIter;
546 VectorCharIter last = mIter;
550 if (static_cast<unsigned char>(*mIter) < '\x20')
552 static_cast<void>( Error("Control characters not allowed in strings") );
555 else if (*mIter == '\\' && AtLeast(2))
601 unsigned int codepoint;
604 static_cast<void>( Error("Bad unicode codepoint; not enough characters") );
607 if ( !HexStringToUnsignedInteger(&(*(mIter + 2)), &(*(mIter + 6)), codepoint) )
609 static_cast<void>( Error("Bad unicode codepoint") );
613 if (codepoint <= 0x7F)
615 *last = (char)codepoint;
617 else if (codepoint <= 0x7FF)
619 *last++ = (char)(0xC0 | (codepoint >> 6));
620 *last = (char)(0x80 | (codepoint & 0x3F));
622 else if (codepoint <= 0xFFFF)
624 *last++ = (char)(0xE0 | (codepoint >> 12));
625 *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
626 *last = (char)(0x80 | (codepoint & 0x3F));
631 } // case 'u' unicode
635 static_cast<void>( Error("Unrecognized escape sequence") );
643 else if (*mIter == '{')
645 if((0 == substitution) && (*last != '\\'))
652 else if (*mIter == '}')
661 else if (*mIter == '"')
675 mNumberOfParsedChars += last - first;
676 mNumberOfParsedChars += 1 ; // null terminator
678 mCurrent.SetSubstitution( substitution > 1 );
685 bool JsonParserState::HandleStartState(const char* name, const char currentChar)
687 if( '{' == currentChar )
689 NewNode(name, TreeNode::OBJECT);
690 mState = STATE_OBJECT;
692 else if( '[' == currentChar )
694 NewNode(name, TreeNode::ARRAY);
695 mState = STATE_VALUE;
699 return Error("Json must start with object {} or array []");
702 AdvanceSkipWhiteSpace(1);
706 bool JsonParserState::HandleObjectState(const char currentChar, const char lastCharacter)
708 if( '}' == currentChar )
710 if(',' == lastCharacter)
712 return Error("Unexpected comma");
719 mState = STATE_VALUE;
721 else if ( '"' == currentChar )
727 return Error("Unexpected character");
730 AdvanceSkipWhiteSpace(1);
734 bool JsonParserState::HandleKeyState(char*& name)
736 name = EncodeString();
737 if( nullptr == name )
741 if( !ParseWhiteSpace() )
747 return Error("Expected ':'");
749 if( !ParseWhiteSpace() )
753 mState = STATE_VALUE;
755 AdvanceSkipWhiteSpace(1);
759 bool JsonParserState::HandleCharacterQuote(char*& name)
762 NewNode(name, TreeNode::STRING);
763 if( char* value = EncodeString() )
765 mCurrent.SetString(value);
775 AdvanceSkipWhiteSpace(0);
779 bool JsonParserState::HandleCharacterNumberOrHyphen(const char* name)
781 NewNode(name, TreeNode::IS_NULL);
790 AdvanceSkipWhiteSpace(0);
794 bool JsonParserState::HandleValueState(char*& name, const char currentChar, const char lastCharacter)
798 if( '"' == currentChar )
800 handled = HandleCharacterQuote(name);
802 else if( IsNumber(currentChar) || currentChar == '-' )
804 handled = HandleCharacterNumberOrHyphen(name);
806 else if( '{' == currentChar )
808 handled = HandleCharacterBracesStart(name, lastCharacter);
810 else if( '}' == currentChar )
812 handled = HandleCharacterBracesEnd(lastCharacter);
814 else if( '[' == currentChar )
816 handled = HandleCharacterSquareBracketStart(name);
818 else if( ']' == currentChar )
820 handled = HandleCharacterSquareBracketEnd(lastCharacter);
822 else if( 't' == currentChar )
824 handled = HandleCharacterLowercaseT(name);
826 else if( 'n' == currentChar )
828 handled = HandleCharacterLowercaseN(name);
830 else if( 'f' == currentChar)
832 handled = HandleCharacterLowercaseF(name);
834 else if( ',' == currentChar )
836 handled = HandleCharacterComma(name);
840 handled = Error("Unexpected character");
851 bool JsonParserState::ParseJson(VectorChar& source)
855 if( 0 == source.size() )
857 return Error("Empty source buffer to parse");
860 mIter = source.begin();
863 char* name = nullptr;
864 char currentChar = 0;
865 char lastCharacter = 0;
867 if( !ParseWhiteSpace() )
874 lastCharacter = currentChar;
875 currentChar = Char();
881 if(!HandleStartState(name, currentChar))
889 if(!HandleObjectState(currentChar, lastCharacter))
897 if(!HandleKeyState(name))
905 if(!HandleValueState(name, currentChar, lastCharacter))
910 } // case STATE_VALUE
913 return Error("Unexpected character. Json must have one object or array at its root");
921 if( mState != STATE_END )
923 return Error("Unexpected termination character");
926 mIter = source.end();
932 void JsonParserState::Reset()
934 mCurrent = TreeNodeManipulator(mRoot);
936 mErrorDescription = nullptr;
942 bool JsonParserState::HandleCharacterBracesStart(const char* name, const char lastCharacter)
944 if( '}' == lastCharacter )
946 return Error("Expected a comma");
950 NewNode(name, TreeNode::OBJECT);
951 mState = STATE_OBJECT;
952 AdvanceSkipWhiteSpace(1);
957 bool JsonParserState::HandleCharacterBracesEnd(const char lastCharacter)
959 if(',' == lastCharacter)
961 return Error("Expected another value");
964 if(mCurrent.GetType() != TreeNode::OBJECT)
966 return Error("Mismatched array definition");
969 if(mCurrent.GetParent() == nullptr)
980 AdvanceSkipWhiteSpace(1);
984 bool JsonParserState::HandleCharacterSquareBracketStart(const char* name)
986 NewNode(name, TreeNode::ARRAY);
987 mState = STATE_VALUE;
988 AdvanceSkipWhiteSpace(1);
992 bool JsonParserState::HandleCharacterSquareBracketEnd(const char lastCharacter)
994 if(',' == lastCharacter)
996 return Error("Expected a value");
999 if(mCurrent.GetType() != TreeNode::ARRAY)
1001 return Error("Mismatched braces in object definition");
1004 if(mCurrent.GetParent() == nullptr)
1015 AdvanceSkipWhiteSpace(1);
1019 bool JsonParserState::HandleCharacterLowercaseT(const char* name)
1021 NewNode(name, TreeNode::BOOLEAN);
1030 AdvanceSkipWhiteSpace(0);
1034 bool JsonParserState::HandleCharacterLowercaseN(const char* name)
1036 NewNode(name, TreeNode::IS_NULL);
1045 AdvanceSkipWhiteSpace(0);
1049 bool JsonParserState::HandleCharacterLowercaseF(const char* name)
1051 NewNode(name, TreeNode::BOOLEAN);
1060 AdvanceSkipWhiteSpace(0);
1064 bool JsonParserState::HandleCharacterComma(const char* name)
1066 if( 0 == mCurrent.Size() )
1068 return Error("Missing Value");
1071 if(mCurrent.GetType() == TreeNode::OBJECT)
1073 mState = STATE_OBJECT; // to get '"' in '"key":val'
1075 else if(mCurrent.GetType() == TreeNode::ARRAY)
1077 mState = STATE_VALUE; // array so just get next value
1081 return Error("Unexpected character");
1083 AdvanceSkipWhiteSpace(1);
1087 } // namespace Internal
1089 } // namespace Toolkit