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 CollectNodes collector;
167 DepthFirst(mNode, collector);
169 for(CollectNodes::iterator iter = collector.nodes.begin(); iter != collector.nodes.end(); ++iter)
177 mNode->mFirstChild = NULL;
178 mNode->mLastChild = NULL;
181 TreeNode* TreeNodeManipulator::Copy(const TreeNode& tree, int& numberNodes, int& numberChars)
183 TreeNode* root = NewTreeNode();
185 ShallowCopy(&tree, root);
189 numberChars += std::strlen(tree.mName) + 1;
192 if(TreeNode::STRING == tree.mType)
194 numberChars += std::strlen(tree.mStringValue) + 1;
199 CopyChildren(&tree, root, numberNodes, numberChars);
204 void TreeNodeManipulator::CopyChildren(const TreeNode* from, TreeNode* to, int& numberNodes, int& numberChars)
206 DALI_ASSERT_DEBUG(from && "Operation on NULL JSON node");
207 DALI_ASSERT_DEBUG(to);
209 for(TreeNode::ConstIterator iter = from->CBegin(); iter != from->CEnd(); ++iter)
211 const TreeNode* child = &((*iter).second);
214 numberChars += std::strlen(child->mName) + 1;
217 if(TreeNode::STRING == child->mType)
219 numberChars += std::strlen(child->mStringValue) + 1;
222 TreeNode* newNode = NewTreeNode();
224 ShallowCopy(child, newNode);
226 TreeNodeManipulator modify(to);
228 modify.AddChild(newNode);
232 CopyChildren(child, newNode, numberNodes, numberChars);
236 TreeNode* TreeNodeManipulator::AddChild(TreeNode* rhs)
238 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
240 rhs->mParent = mNode;
241 if(mNode->mLastChild)
243 mNode->mLastChild = mNode->mLastChild->mNextSibling = rhs;
247 mNode->mFirstChild = mNode->mLastChild = rhs;
252 TreeNode::NodeType TreeNodeManipulator::GetType() const
254 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
256 return mNode->GetType();
259 size_t TreeNodeManipulator::Size() const
261 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
263 return mNode->Size();
266 void TreeNodeManipulator::SetType(TreeNode::NodeType type)
268 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
270 if(mNode->mType != type)
274 if(NULL != mNode->mFirstChild)
276 // value types have no children
277 bool removeChildren = !(TreeNode::OBJECT == type || TreeNode::ARRAY == type);
279 // ie if swapping array for object
280 removeChildren = (removeChildren == true) ? true : type != mNode->mType;
282 // so remove any children
283 if(removeChildren && NULL != mNode->mFirstChild)
289 else if(TreeNode::ARRAY == mNode->mType)
291 if(mNode->mFirstChild != NULL)
293 TreeNode::NodeType type = mNode->mFirstChild->GetType();
295 if(TreeNode::FLOAT == type || TreeNode::INTEGER == type)
297 // Arrays of numbers should be replaced, not appended to.
304 void TreeNodeManipulator::SetName(const char* name)
306 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
310 void TreeNodeManipulator::SetSubstitution(bool b)
312 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
313 mNode->mSubstituion = b;
316 TreeNode* TreeNodeManipulator::GetParent() const
318 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
319 return NULL == mNode ? NULL : mNode->mParent;
322 const TreeNode* TreeNodeManipulator::GetChild(const std::string& name) const
324 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
325 return NULL == mNode ? NULL : mNode->GetChild(name);
328 void TreeNodeManipulator::SetString(const char* string)
330 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
331 SetType(TreeNode::STRING);
332 mNode->mStringValue = string;
335 void TreeNodeManipulator::SetInteger(int i)
337 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
338 SetType(TreeNode::INTEGER);
339 mNode->mIntValue = i;
342 void TreeNodeManipulator::SetFloat(float f)
344 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
345 SetType(TreeNode::FLOAT);
346 mNode->mFloatValue = f;
349 void TreeNodeManipulator::SetBoolean(bool b)
351 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
352 SetType(TreeNode::BOOLEAN);
353 mNode->mIntValue = b == true ? 1 : 0;
356 void TreeNodeManipulator::Write(std::ostream& output, int indent) const
358 DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
359 DoWrite(mNode, output, 0, indent, false);
362 void TreeNodeManipulator::DoWrite(const TreeNode* value, std::ostream& output, int level, int indentWidth, bool groupChildren) const
364 DALI_ASSERT_DEBUG(value && "Operation on NULL JSON node");
368 Indent(output, level, indentWidth);
373 output << "\"" << value->GetName() << "\":";
376 switch(value->GetType())
378 case TreeNode::IS_NULL:
381 if(NULL != value->mNextSibling)
391 case TreeNode::OBJECT:
392 case TreeNode::ARRAY:
394 bool groupMyChildren = false;
396 if(TreeNode::ARRAY == value->GetType() && value->mFirstChild &&
397 (TreeNode::INTEGER == value->mFirstChild->GetType() ||
398 TreeNode::FLOAT == value->mFirstChild->GetType()))
400 groupMyChildren = true;
403 if(value->GetType() == TreeNode::OBJECT)
406 Indent(output, level, indentWidth);
414 Indent(output, level, indentWidth);
428 for(TreeNode::ConstIterator it = value->CBegin(); it != value->CEnd(); ++it)
430 DoWrite(&((*it).second), output, level + 1, indentWidth, groupMyChildren);
435 Indent(output, level, indentWidth);
438 if(value->GetType() == TreeNode::OBJECT)
447 if(NULL != value->mNextSibling)
457 groupChildren = false;
460 case TreeNode::STRING:
462 std::string escapedString = EscapeQuotes(value->GetString());
463 output << "\"" << escapedString << "\"";
464 if(NULL != value->mNextSibling)
479 case TreeNode::INTEGER:
481 output << value->GetInteger();
482 if(NULL != value->mNextSibling)
497 case TreeNode::FLOAT:
499 output.setf(std::ios::floatfield);
500 output << value->GetFloat();
501 output.unsetf(std::ios::floatfield);
502 if(NULL != value->mNextSibling)
517 case TreeNode::BOOLEAN:
519 if(value->GetInteger())
528 if(NULL != value->mNextSibling)
547 const TreeNode* FindIt(std::string_view childName, const TreeNode* node)
549 DALI_ASSERT_DEBUG(node);
551 const TreeNode* found = NULL;
555 if(NULL != (found = node->GetChild(childName)))
561 for(TreeNode::ConstIterator iter = node->CBegin(); iter != node->CEnd(); ++iter)
563 if(NULL != (found = FindIt(childName, &((*iter).second))))
573 char* CopyString(const char* fromString, VectorCharIter& iter, const VectorCharIter& sentinel)
575 DALI_ASSERT_DEBUG(fromString);
576 DALI_ASSERT_DEBUG(iter != sentinel);
578 char* start = &(*iter);
579 const char* ptr = fromString;
585 DALI_ASSERT_DEBUG(iter != sentinel);
594 } // namespace Internal
596 } // namespace Toolkit