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.
23 #include <dali-toolkit/internal/builder/tree-node-manipulator.h>
25 #include <dali-toolkit/devel-api/builder/tree-node.h>
35 void Indent(std::ostream& o, int level, int indentWidth)
37 for(int i = 0; i < level * indentWidth; ++i)
43 std::string EscapeQuotes(const char* aString)
45 std::string escapedString;
46 int length = strlen(aString);
47 escapedString.reserve(length);
49 const char* end = aString + length;
50 for(const char* iter = aString; iter != end; ++iter)
54 escapedString.push_back(*iter);
58 escapedString.append("\\\"");
64 } // anonymous namespace
66 TreeNodeManipulator::TreeNodeManipulator(TreeNode* node)
71 TreeNode* TreeNodeManipulator::NewTreeNode()
73 return new TreeNode();
76 void TreeNodeManipulator::ShallowCopy(const TreeNode* from, TreeNode* to)
78 DALI_ASSERT_DEBUG(from);
79 DALI_ASSERT_DEBUG(to);
83 to->mName = from->mName;
84 to->mType = from->mType;
85 to->mSubstituion = from->mSubstituion;
88 case TreeNode::INTEGER:
90 to->mIntValue = from->mIntValue;
95 to->mFloatValue = from->mFloatValue;
98 case TreeNode::STRING:
100 to->mStringValue = from->mStringValue;
103 case TreeNode::BOOLEAN:
105 to->mIntValue = from->mIntValue;
108 case TreeNode::IS_NULL:
109 case TreeNode::OBJECT:
110 case TreeNode::ARRAY:
118 void TreeNodeManipulator::MoveNodeStrings(VectorCharIter& start, const VectorCharIter& sentinel)
120 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
123 mNode->mName = CopyString(mNode->mName, start, sentinel);
126 if(TreeNode::STRING == mNode->mType)
128 mNode->mStringValue = CopyString(mNode->mStringValue, start, sentinel);
132 void TreeNodeManipulator::MoveStrings(VectorCharIter& start, const VectorCharIter& sentinel)
134 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
135 TreeNodeManipulator modify(mNode);
136 modify.MoveNodeStrings(start, sentinel);
137 RecurseMoveChildStrings(start, sentinel);
140 void TreeNodeManipulator::RecurseMoveChildStrings(VectorCharIter& start, const VectorCharIter& sentinel)
142 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
144 TreeNode* child = mNode->mFirstChild;
147 TreeNodeManipulator manipChild(child);
148 manipChild.MoveNodeStrings(start, sentinel);
149 child = child->mNextSibling;
152 child = mNode->mFirstChild;
155 TreeNodeManipulator manipChild(child);
156 manipChild.RecurseMoveChildStrings(start, sentinel);
157 child = child->mNextSibling;
161 void TreeNodeManipulator::RemoveChildren()
163 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
165 DeleteNodesWithoutSelf otherDeletor(mNode);
167 DepthFirst(mNode, otherDeletor);
169 mNode->mFirstChild = NULL;
170 mNode->mLastChild = NULL;
173 TreeNode* TreeNodeManipulator::Copy(const TreeNode& tree, int& numberNodes, int& numberChars)
175 TreeNode* root = NewTreeNode();
177 ShallowCopy(&tree, root);
181 numberChars += std::strlen(tree.mName) + 1;
184 if(TreeNode::STRING == tree.mType)
186 numberChars += std::strlen(tree.mStringValue) + 1;
191 CopyChildren(&tree, root, numberNodes, numberChars);
196 void TreeNodeManipulator::CopyChildren(const TreeNode* from, TreeNode* to, int& numberNodes, int& numberChars)
198 DALI_ASSERT_DEBUG(from && "Operation on NULL JSON node");
199 DALI_ASSERT_DEBUG(to);
201 for(TreeNode::ConstIterator iter = from->CBegin(); iter != from->CEnd(); ++iter)
203 const TreeNode* child = &((*iter).second);
206 numberChars += std::strlen(child->mName) + 1;
209 if(TreeNode::STRING == child->mType)
211 numberChars += std::strlen(child->mStringValue) + 1;
214 TreeNode* newNode = NewTreeNode();
216 ShallowCopy(child, newNode);
218 TreeNodeManipulator modify(to);
220 modify.AddChild(newNode);
224 CopyChildren(child, newNode, numberNodes, numberChars);
228 TreeNode* TreeNodeManipulator::AddChild(TreeNode* rhs)
230 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
232 rhs->mParent = mNode;
233 if(mNode->mLastChild)
235 mNode->mLastChild = mNode->mLastChild->mNextSibling = rhs;
239 mNode->mFirstChild = mNode->mLastChild = rhs;
244 TreeNode::NodeType TreeNodeManipulator::GetType() const
246 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
248 return mNode->GetType();
251 size_t TreeNodeManipulator::Size() const
253 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
255 return mNode->Size();
258 void TreeNodeManipulator::SetType(TreeNode::NodeType type)
260 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
262 if(mNode->mType != type)
266 if(NULL != mNode->mFirstChild)
268 // value types have no children
269 bool removeChildren = !(TreeNode::OBJECT == type || TreeNode::ARRAY == type);
271 // ie if swapping array for object
272 removeChildren = (removeChildren == true) ? true : type != mNode->mType;
274 // so remove any children
275 if(removeChildren && NULL != mNode->mFirstChild)
281 else if(TreeNode::ARRAY == mNode->mType)
283 if(mNode->mFirstChild != NULL)
285 TreeNode::NodeType firstChildType = mNode->mFirstChild->GetType();
287 if(TreeNode::FLOAT == firstChildType || TreeNode::INTEGER == firstChildType)
289 // Arrays of numbers should be replaced, not appended to.
296 void TreeNodeManipulator::SetName(const char* name)
298 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
302 void TreeNodeManipulator::SetSubstitution(bool b)
304 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
305 mNode->mSubstituion = b;
308 TreeNode* TreeNodeManipulator::GetParent() const
310 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
311 return NULL == mNode ? NULL : mNode->mParent;
314 const TreeNode* TreeNodeManipulator::GetChild(const std::string& name) const
316 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
317 return NULL == mNode ? NULL : mNode->GetChild(name);
320 void TreeNodeManipulator::SetString(const char* string)
322 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
323 SetType(TreeNode::STRING);
324 mNode->mStringValue = string;
327 void TreeNodeManipulator::SetInteger(int i)
329 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
330 SetType(TreeNode::INTEGER);
331 mNode->mIntValue = i;
334 void TreeNodeManipulator::SetFloat(float f)
336 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
337 SetType(TreeNode::FLOAT);
338 mNode->mFloatValue = f;
341 void TreeNodeManipulator::SetBoolean(bool b)
343 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
344 SetType(TreeNode::BOOLEAN);
345 mNode->mIntValue = b == true ? 1 : 0;
348 void TreeNodeManipulator::Write(std::ostream& output, int indent) const
350 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
351 DoWrite(mNode, output, 0, indent, false);
354 void TreeNodeManipulator::DoWrite(const TreeNode* value, std::ostream& output, int level, int indentWidth, bool groupChildren) const
356 DALI_ASSERT_DEBUG(value && "Operation on NULL JSON node");
360 Indent(output, level, indentWidth);
365 output << "\"" << value->GetName() << "\":";
368 switch(value->GetType())
370 case TreeNode::IS_NULL:
373 if(NULL != value->mNextSibling)
383 case TreeNode::OBJECT:
384 case TreeNode::ARRAY:
386 bool groupMyChildren = false;
388 if(TreeNode::ARRAY == value->GetType() && value->mFirstChild &&
389 (TreeNode::INTEGER == value->mFirstChild->GetType() ||
390 TreeNode::FLOAT == value->mFirstChild->GetType()))
392 groupMyChildren = true;
395 if(value->GetType() == TreeNode::OBJECT)
398 Indent(output, level, indentWidth);
406 Indent(output, level, indentWidth);
420 for(TreeNode::ConstIterator it = value->CBegin(); it != value->CEnd(); ++it)
422 DoWrite(&((*it).second), output, level + 1, indentWidth, groupMyChildren);
427 Indent(output, level, indentWidth);
430 if(value->GetType() == TreeNode::OBJECT)
439 if(NULL != value->mNextSibling)
449 groupChildren = false;
452 case TreeNode::STRING:
454 std::string escapedString = EscapeQuotes(value->GetString());
455 output << "\"" << escapedString << "\"";
456 if(NULL != value->mNextSibling)
471 case TreeNode::INTEGER:
473 output << value->GetInteger();
474 if(NULL != value->mNextSibling)
489 case TreeNode::FLOAT:
491 output.setf(std::ios::floatfield);
492 output << value->GetFloat();
493 output.unsetf(std::ios::floatfield);
494 if(NULL != value->mNextSibling)
509 case TreeNode::BOOLEAN:
511 if(value->GetInteger())
520 if(NULL != value->mNextSibling)
539 const TreeNode* FindIt(std::string_view childName, const TreeNode* node)
541 DALI_ASSERT_DEBUG(node);
543 const TreeNode* found = NULL;
547 if(NULL != (found = node->GetChild(childName)))
553 for(TreeNode::ConstIterator iter = node->CBegin(); iter != node->CEnd(); ++iter)
555 if(NULL != (found = FindIt(childName, &((*iter).second))))
565 char* CopyString(const char* fromString, VectorCharIter& iter, const VectorCharIter& sentinel)
567 DALI_ASSERT_DEBUG(fromString);
568 DALI_ASSERT_DEBUG(iter != sentinel);
570 char* start = &(*iter);
571 const char* ptr = fromString;
577 DALI_ASSERT_DEBUG(iter != sentinel);
586 } // namespace Internal
588 } // namespace Toolkit