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>
36 // true if character represent a digit
37 inline bool IsDigit(char c)
39 return (c >= '0' && c <= '9');
42 // convert string to integer
43 bool StringToInteger(const char *first, const char *last, int& out)
53 else if (*first == '+')
59 // json error for int starting with zero
60 if( 0 == (*first - '0') && (first+1 != last))
66 for (; first != last && IsDigit(*first); ++first)
68 result = 10 * result + (*first - '0');
82 // convert hexadecimal string to unsigned integer
83 bool HexStringToUnsignedInteger(const char *first, const char *last, unsigned int& out)
85 unsigned int result = 0;
86 for (; first != last; ++first)
93 else if (*first >= 'a' && *first <= 'f')
95 digit = *first - 'a' + 10;
97 else if (*first >= 'A' && *first <= 'F')
99 digit = *first - 'A' + 10;
105 result = 16 * result + digit;
119 // convert string to floating point
120 bool StringToFloat(const char* first, const char* last, float& out)
131 else if (*first == '+')
139 for (; first != last && IsDigit(*first); ++first)
141 result = 10 * result + (*first - '0');
145 if (first != last && *first == '.')
149 float inv_base = 0.1f;
150 for (; first != last && IsDigit(*first); ++first)
152 result += (*first - '0') * inv_base;
157 // result w\o exponent
161 bool exponent_negative = false;
163 if (first != last && (*first == 'e' || *first == 'E'))
169 exponent_negative = true;
172 else if (*first == '+')
177 if(first == last || !IsDigit(*first))
182 for (; first != last && IsDigit(*first); ++first)
184 exponent = 10 * exponent + (*first - '0');
190 float power_of_ten = 10;
191 for (; exponent > 1; exponent--)
196 if (exponent_negative)
198 result /= power_of_ten;
202 result *= power_of_ten;
219 bool IsNumber(char c)
249 JsonParserState::JsonParserState(TreeNode* _root)
250 : mRoot(_root), mCurrent(_root),
251 mErrorDescription(NULL), mErrorNewLine(0), mErrorColumn(0), mErrorPosition(0),
252 mNumberOfParsedChars(0), mNumberOfCreatedNodes(0), mFirstParse(false),
261 TreeNode* JsonParserState::CreateNewNode(const char* name, TreeNode::NodeType type)
263 TreeNode* node = NULL;
265 node = TreeNodeManipulator::NewTreeNode();
266 TreeNodeManipulator modifyNew(node);
267 modifyNew.SetType(type);
268 modifyNew.SetName(name);
272 mCurrent = TreeNodeManipulator(mRoot);
276 mCurrent.AddChild(node);
277 mCurrent = modifyNew;
280 ++mNumberOfCreatedNodes;
286 TreeNode* JsonParserState::NewNode(const char* name, TreeNode::NodeType type)
288 TreeNode* node = NULL;
292 node = CreateNewNode(name, type);
300 const TreeNode* found = mCurrent.GetChild(name);
303 node = const_cast<TreeNode*>(found);
309 if( mCurrent.GetParent() == NULL )
317 // walk tree and deallocate children as were replacing this node
318 TreeNodeManipulator modify(node);
320 modify.SetName(name);
322 // Set the type of the existing node.
323 // Where the new type is different, then any children of this node will
325 // When the type is an array of numbers, then this will also remove any children
326 // When the type is an object or other array, then the children will not be removed,
327 // but will instead follow these replace rules.
328 modify.SetType(type);
334 // if not found then create new
335 node = CreateNewNode(name, type);
342 TreeNode* JsonParserState::GetRoot()
347 bool JsonParserState::Error(const char* description)
349 mErrorDescription = description;
353 bool JsonParserState::ParseWhiteSpace()
355 bool c_comment = false;
356 bool cpp_comment = false;
389 continue; // rather than carry on as comments may be back to back
392 else if( !c_comment && (c == '/' && nextChar == '/') )
399 if( c == '*' && nextChar == '/' )
406 else if( !cpp_comment && (c == '/' && nextChar == '*') )
411 if( ! (c_comment || cpp_comment) )
413 if( ! (c == '\x20' || c == '\x9' || c == '\xD' || c == '\xA' ) )
419 if( AdvanceEnded(1) )
429 bool JsonParserState::ParseSymbol(const std::string& symbol)
431 if( AtLeast( symbol.size() ) )
433 for(int i = 0; i < static_cast<int>( symbol.size() ); ++i)
435 if(*mIter != symbol[i])
449 bool JsonParserState::ParseTrue()
451 if( ParseSymbol("true") )
453 mCurrent.SetInteger(1);
454 mCurrent.SetType(TreeNode::BOOLEAN);
459 return Error("Unexpected character; expected symbol ie 'true'");
463 bool JsonParserState::ParseFalse()
465 if( ParseSymbol("false") )
467 mCurrent.SetInteger(0);
468 mCurrent.SetType(TreeNode::BOOLEAN);
473 return Error("Unexpected character; expected symbol ie 'false'");
477 bool JsonParserState::ParseNULL()
479 if( ParseSymbol("null") )
481 mCurrent.SetType(TreeNode::IS_NULL);
486 return Error("Unexpected character; expected symbol ie 'null'");
490 bool JsonParserState::ParseNumber()
492 mCurrent.SetType( TreeNode::INTEGER );
494 VectorCharIter first = mIter;
497 if( !(c == '-' || IsNumber(c) ) )
499 return Error("Number must start with '-' or 0-9");
502 while ( IsNumber(c) || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-' )
504 if (c == '.' || c == 'e' || c == 'E')
506 mCurrent.SetType( TreeNode::FLOAT );
512 if( mCurrent.GetType() == TreeNode::INTEGER )
515 if( StringToInteger(&(*first), &(*mIter), i ) )
517 mCurrent.SetInteger(i);
521 return Error("Bad integer number");
525 if(mCurrent.GetType() == TreeNode::FLOAT)
528 if( StringToFloat(&(*first), &(*mIter), f) )
530 mCurrent.SetFloat(f);
534 return Error("Bad float number");
538 return (mCurrent.GetType() == TreeNode::INTEGER) || (mCurrent.GetType() == TreeNode::FLOAT);
541 char* JsonParserState::EncodeString()
543 int substitution = 0;
544 VectorCharIter first = mIter;
545 VectorCharIter last = mIter;
549 if (static_cast<unsigned char>(*mIter) < '\x20')
551 static_cast<void>( Error("Control characters not allowed in strings") );
554 else if (*mIter == '\\' && AtLeast(2))
600 unsigned int codepoint;
603 static_cast<void>( Error("Bad unicode codepoint; not enough characters") );
606 if ( !HexStringToUnsignedInteger(&(*(mIter + 2)), &(*(mIter + 6)), codepoint) )
608 static_cast<void>( Error("Bad unicode codepoint") );
612 if (codepoint <= 0x7F)
614 *last = (char)codepoint;
616 else if (codepoint <= 0x7FF)
618 *last++ = (char)(0xC0 | (codepoint >> 6));
619 *last = (char)(0x80 | (codepoint & 0x3F));
621 else if (codepoint <= 0xFFFF)
623 *last++ = (char)(0xE0 | (codepoint >> 12));
624 *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
625 *last = (char)(0x80 | (codepoint & 0x3F));
630 } // case 'u' unicode
634 static_cast<void>( Error("Unrecognized escape sequence") );
642 else if (*mIter == '{')
644 if((0 == substitution) && (*last != '\\'))
651 else if (*mIter == '}')
660 else if (*mIter == '"')
674 mNumberOfParsedChars += last - first;
675 mNumberOfParsedChars += 1 ; // null terminator
677 mCurrent.SetSubstitution( substitution > 1 );
684 bool JsonParserState::ParseJson(VectorChar& source)
688 if( 0 == source.size() )
690 return Error("Empty source buffer to parse");
693 mIter = source.begin();
697 char currentChar = 0;
698 char lastCharacter = 0;
700 if( !ParseWhiteSpace() )
707 lastCharacter = currentChar;
708 currentChar = Char();
714 if( '{' == currentChar )
716 NewNode(name, TreeNode::OBJECT);
717 mState = STATE_OBJECT;
719 else if( '[' == currentChar )
721 NewNode(name, TreeNode::ARRAY);
722 mState = STATE_VALUE;
726 return Error("Json must start with object {} or array []");
729 AdvanceSkipWhiteSpace(1);
734 if( '}' == currentChar )
736 if(',' == lastCharacter)
738 return Error("Unexpected comma");
745 mState = STATE_VALUE;
747 else if ( '"' == currentChar )
753 return Error("Unexpected character");
756 AdvanceSkipWhiteSpace(1);
761 name = EncodeString();
766 if( !ParseWhiteSpace() )
772 return Error("Expected ':'");
774 if( !ParseWhiteSpace() )
778 mState = STATE_VALUE;
780 AdvanceSkipWhiteSpace(1);
785 if( '"' == currentChar )
788 NewNode(name, TreeNode::STRING);
789 if( char* value = EncodeString() )
791 mCurrent.SetString(value);
801 AdvanceSkipWhiteSpace(0);
803 else if( IsNumber(currentChar) || currentChar == '-' )
805 NewNode(name, TreeNode::IS_NULL);
814 AdvanceSkipWhiteSpace(0);
816 else if( '{' == currentChar )
818 if( '}' == lastCharacter )
820 return Error("Expected a comma");
824 NewNode(name, TreeNode::OBJECT);
825 mState = STATE_OBJECT;
826 AdvanceSkipWhiteSpace(1);
829 else if( '}' == currentChar )
831 if(',' == lastCharacter)
833 return Error("Expected another value");
836 if(mCurrent.GetType() != TreeNode::OBJECT)
838 return Error("Mismatched array definition");
841 if(mCurrent.GetParent() == NULL)
852 AdvanceSkipWhiteSpace(1);
854 else if( '[' == currentChar )
856 NewNode(name, TreeNode::ARRAY);
857 mState = STATE_VALUE;
858 AdvanceSkipWhiteSpace(1);
860 else if( ']' == currentChar )
862 if(',' == lastCharacter)
864 return Error("Expected a value");
867 if(mCurrent.GetType() != TreeNode::ARRAY)
869 return Error("Mismatched braces in object definition");
872 if(mCurrent.GetParent() == NULL)
883 AdvanceSkipWhiteSpace(1);
885 else if( 't' == currentChar )
887 NewNode(name, TreeNode::BOOLEAN);
896 AdvanceSkipWhiteSpace(0);
898 else if( 'n' == currentChar )
900 NewNode(name, TreeNode::IS_NULL);
909 AdvanceSkipWhiteSpace(0);
911 else if( 'f' == currentChar)
913 NewNode(name, TreeNode::BOOLEAN);
922 AdvanceSkipWhiteSpace(0);
924 else if( ',' == currentChar )
926 if( 0 == mCurrent.Size() )
928 return Error("Missing Value");
931 if(mCurrent.GetType() == TreeNode::OBJECT)
933 mState = STATE_OBJECT; // to get '"' in '"key":val'
935 else if(mCurrent.GetType() == TreeNode::ARRAY)
937 mState = STATE_VALUE; // array so just get next value
941 return Error("Unexpected character");
943 AdvanceSkipWhiteSpace(1);
947 return Error("Unexpected character");
953 } // case STATE_VALUE
956 return Error("Unexpected character. Json must have one object or array at its root");
964 if( mState != STATE_END )
966 return Error("Unexpected termination character");
969 mIter = source.end();
976 void JsonParserState::Reset()
978 mCurrent = TreeNodeManipulator(mRoot);
980 mErrorDescription = NULL;
987 } // namespace Internal
989 } // namespace Toolkit