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>
33 // true if character represent a digit
34 inline bool IsDigit(char c)
36 return (c >= '0' && c <= '9');
39 // convert string to integer
40 bool StringToInteger(const char* first, const char* last, int& out)
50 else if(*first == '+')
56 // json error for int starting with zero
57 if(0 == (*first - '0') && (first + 1 != last))
63 for(; first != last && IsDigit(*first); ++first)
65 result = 10 * result + (*first - '0');
79 // convert hexadecimal string to unsigned integer
80 bool HexStringToUnsignedInteger(const char* first, const char* last, unsigned int& out)
82 unsigned int result = 0;
83 for(; first != last; ++first)
90 else if(*first >= 'a' && *first <= 'f')
92 digit = *first - 'a' + 10;
94 else if(*first >= 'A' && *first <= 'F')
96 digit = *first - 'A' + 10;
102 result = 16 * result + digit;
116 // convert string to floating point
117 bool StringToFloat(const char* first, const char* last, float& out)
128 else if(*first == '+')
136 for(; first != last && IsDigit(*first); ++first)
138 result = 10 * result + (*first - '0');
142 if(first != last && *first == '.')
146 float inv_base = 0.1f;
147 for(; first != last && IsDigit(*first); ++first)
149 result += (*first - '0') * inv_base;
154 // result w\o exponent
158 bool exponent_negative = false;
160 if(first != last && (*first == 'e' || *first == 'E'))
166 exponent_negative = true;
169 else if(*first == '+')
174 if(first == last || !IsDigit(*first))
179 for(; first != last && IsDigit(*first); ++first)
181 exponent = 10 * exponent + (*first - '0');
187 float power_of_ten = 10;
188 for(; exponent > 1; exponent--)
193 if(exponent_negative)
195 result /= power_of_ten;
199 result *= power_of_ten;
215 bool IsNumber(char c)
244 JsonParserState::JsonParserState(TreeNode* _root)
247 mErrorDescription(nullptr),
251 mNumberOfParsedChars(0),
252 mNumberOfCreatedNodes(0),
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;
286 TreeNode* JsonParserState::NewNode(const char* name, TreeNode::NodeType type)
288 TreeNode* node = nullptr;
292 node = CreateNewNode(name, type);
300 const TreeNode* found = mCurrent.GetChild(name);
303 node = const_cast<TreeNode*>(found);
309 if(mCurrent.GetParent() == nullptr)
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'))
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::HandleStartState(const char* name, const char currentChar)
686 if('{' == currentChar)
688 NewNode(name, TreeNode::OBJECT);
689 mState = STATE_OBJECT;
691 else if('[' == currentChar)
693 NewNode(name, TreeNode::ARRAY);
694 mState = STATE_VALUE;
698 return Error("Json must start with object {} or array []");
701 AdvanceSkipWhiteSpace(1);
705 bool JsonParserState::HandleObjectState(const char currentChar, const char lastCharacter)
707 if('}' == currentChar)
709 if(',' == lastCharacter)
711 return Error("Unexpected comma");
718 mState = STATE_VALUE;
720 else if('"' == currentChar)
726 return Error("Unexpected character");
729 AdvanceSkipWhiteSpace(1);
733 bool JsonParserState::HandleKeyState(char*& name)
735 name = EncodeString();
740 if(!ParseWhiteSpace())
746 return Error("Expected ':'");
748 if(!ParseWhiteSpace())
752 mState = STATE_VALUE;
754 AdvanceSkipWhiteSpace(1);
758 bool JsonParserState::HandleCharacterQuote(char*& name)
761 NewNode(name, TreeNode::STRING);
762 if(char* value = EncodeString())
764 mCurrent.SetString(value);
774 AdvanceSkipWhiteSpace(0);
778 bool JsonParserState::HandleCharacterNumberOrHyphen(const char* name)
780 NewNode(name, TreeNode::IS_NULL);
789 AdvanceSkipWhiteSpace(0);
793 bool JsonParserState::HandleValueState(char*& name, const char currentChar, const char lastCharacter)
797 if('"' == currentChar)
799 handled = HandleCharacterQuote(name);
801 else if(IsNumber(currentChar) || currentChar == '-')
803 handled = HandleCharacterNumberOrHyphen(name);
805 else if('{' == currentChar)
807 handled = HandleCharacterBracesStart(name, lastCharacter);
809 else if('}' == currentChar)
811 handled = HandleCharacterBracesEnd(lastCharacter);
813 else if('[' == currentChar)
815 handled = HandleCharacterSquareBracketStart(name);
817 else if(']' == currentChar)
819 handled = HandleCharacterSquareBracketEnd(lastCharacter);
821 else if('t' == currentChar)
823 handled = HandleCharacterLowercaseT(name);
825 else if('n' == currentChar)
827 handled = HandleCharacterLowercaseN(name);
829 else if('f' == currentChar)
831 handled = HandleCharacterLowercaseF(name);
833 else if(',' == currentChar)
835 handled = HandleCharacterComma(name);
839 handled = Error("Unexpected character");
850 bool JsonParserState::ParseJson(VectorChar& source)
854 if(0 == source.size())
856 return Error("Empty source buffer to parse");
859 mIter = source.begin();
862 char* name = nullptr;
863 char currentChar = 0;
864 char lastCharacter = 0;
866 if(!ParseWhiteSpace())
873 lastCharacter = currentChar;
874 currentChar = Char();
880 if(!HandleStartState(name, currentChar))
888 if(!HandleObjectState(currentChar, lastCharacter))
896 if(!HandleKeyState(name))
904 if(!HandleValueState(name, currentChar, lastCharacter))
909 } // case STATE_VALUE
912 return Error("Unexpected character. Json must have one object or array at its root");
920 if(mState != STATE_END)
922 return Error("Unexpected termination character");
925 mIter = source.end();
931 void JsonParserState::Reset()
933 mCurrent = TreeNodeManipulator(mRoot);
935 mErrorDescription = nullptr;
941 bool JsonParserState::HandleCharacterBracesStart(const char* name, const char lastCharacter)
943 if('}' == lastCharacter)
945 return Error("Expected a comma");
949 NewNode(name, TreeNode::OBJECT);
950 mState = STATE_OBJECT;
951 AdvanceSkipWhiteSpace(1);
956 bool JsonParserState::HandleCharacterBracesEnd(const char lastCharacter)
958 if(',' == lastCharacter)
960 return Error("Expected another value");
963 if(mCurrent.GetType() != TreeNode::OBJECT)
965 return Error("Mismatched array definition");
968 if(mCurrent.GetParent() == nullptr)
979 AdvanceSkipWhiteSpace(1);
983 bool JsonParserState::HandleCharacterSquareBracketStart(const char* name)
985 NewNode(name, TreeNode::ARRAY);
986 mState = STATE_VALUE;
987 AdvanceSkipWhiteSpace(1);
991 bool JsonParserState::HandleCharacterSquareBracketEnd(const char lastCharacter)
993 if(',' == lastCharacter)
995 return Error("Expected a value");
998 if(mCurrent.GetType() != TreeNode::ARRAY)
1000 return Error("Mismatched braces in object definition");
1003 if(mCurrent.GetParent() == nullptr)
1014 AdvanceSkipWhiteSpace(1);
1018 bool JsonParserState::HandleCharacterLowercaseT(const char* name)
1020 NewNode(name, TreeNode::BOOLEAN);
1029 AdvanceSkipWhiteSpace(0);
1033 bool JsonParserState::HandleCharacterLowercaseN(const char* name)
1035 NewNode(name, TreeNode::IS_NULL);
1044 AdvanceSkipWhiteSpace(0);
1048 bool JsonParserState::HandleCharacterLowercaseF(const char* name)
1050 NewNode(name, TreeNode::BOOLEAN);
1059 AdvanceSkipWhiteSpace(0);
1063 bool JsonParserState::HandleCharacterComma(const char* name)
1065 if(0 == mCurrent.Size())
1067 return Error("Missing Value");
1070 if(mCurrent.GetType() == TreeNode::OBJECT)
1072 mState = STATE_OBJECT; // to get '"' in '"key":val'
1074 else if(mCurrent.GetType() == TreeNode::ARRAY)
1076 mState = STATE_VALUE; // array so just get next value
1080 return Error("Unexpected character");
1082 AdvanceSkipWhiteSpace(1);
1086 } // namespace Internal
1088 } // namespace Toolkit