[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / builder / tree-node-manipulator.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // EXTERNAL INCLUDES
19 #include <cstring>
20 #include <sstream>
21
22 // INTERNAL INCLUDES
23 #include <dali-toolkit/internal/builder/tree-node-manipulator.h>
24
25 #include <dali-toolkit/devel-api/builder/tree-node.h>
26
27 namespace Dali
28 {
29 namespace Toolkit
30 {
31 namespace Internal
32 {
33 namespace
34 {
35 void Indent(std::ostream& o, int level, int indentWidth)
36 {
37   for(int i = 0; i < level * indentWidth; ++i)
38   {
39     o << " ";
40   }
41 }
42
43 std::string EscapeQuotes(const char* aString)
44 {
45   std::string escapedString;
46   int         length = strlen(aString);
47   escapedString.reserve(length);
48
49   const char* end = aString + length;
50   for(const char* iter = aString; iter != end; ++iter)
51   {
52     if(*iter != '\"')
53     {
54       escapedString.push_back(*iter);
55     }
56     else
57     {
58       escapedString.append("\\\"");
59     }
60   }
61   return escapedString;
62 }
63
64 } // anonymous namespace
65
66 TreeNodeManipulator::TreeNodeManipulator(TreeNode* node)
67 : mNode(node)
68 {
69 }
70
71 TreeNode* TreeNodeManipulator::NewTreeNode()
72 {
73   return new TreeNode();
74 }
75
76 void TreeNodeManipulator::ShallowCopy(const TreeNode* from, TreeNode* to)
77 {
78   DALI_ASSERT_DEBUG(from);
79   DALI_ASSERT_DEBUG(to);
80
81   if(from)
82   {
83     to->mName        = from->mName;
84     to->mType        = from->mType;
85     to->mSubstituion = from->mSubstituion;
86     switch(from->mType)
87     {
88       case TreeNode::INTEGER:
89       {
90         to->mIntValue = from->mIntValue;
91         break;
92       }
93       case TreeNode::FLOAT:
94       {
95         to->mFloatValue = from->mFloatValue;
96         break;
97       }
98       case TreeNode::STRING:
99       {
100         to->mStringValue = from->mStringValue;
101         break;
102       }
103       case TreeNode::BOOLEAN:
104       {
105         to->mIntValue = from->mIntValue;
106         break;
107       }
108       case TreeNode::IS_NULL:
109       case TreeNode::OBJECT:
110       case TreeNode::ARRAY:
111       {
112         break;
113       }
114     }
115   }
116 }
117
118 void TreeNodeManipulator::MoveNodeStrings(VectorCharIter& start, const VectorCharIter& sentinel)
119 {
120   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
121   if(mNode->mName)
122   {
123     mNode->mName = CopyString(mNode->mName, start, sentinel);
124   }
125
126   if(TreeNode::STRING == mNode->mType)
127   {
128     mNode->mStringValue = CopyString(mNode->mStringValue, start, sentinel);
129   }
130 }
131
132 void TreeNodeManipulator::MoveStrings(VectorCharIter& start, const VectorCharIter& sentinel)
133 {
134   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
135   TreeNodeManipulator modify(mNode);
136   modify.MoveNodeStrings(start, sentinel);
137   RecurseMoveChildStrings(start, sentinel);
138 }
139
140 void TreeNodeManipulator::RecurseMoveChildStrings(VectorCharIter& start, const VectorCharIter& sentinel)
141 {
142   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
143
144   TreeNode* child = mNode->mFirstChild;
145   while(child)
146   {
147     TreeNodeManipulator manipChild(child);
148     manipChild.MoveNodeStrings(start, sentinel);
149     child = child->mNextSibling;
150   }
151
152   child = mNode->mFirstChild;
153   while(child)
154   {
155     TreeNodeManipulator manipChild(child);
156     manipChild.RecurseMoveChildStrings(start, sentinel);
157     child = child->mNextSibling;
158   }
159 }
160
161 void TreeNodeManipulator::RemoveChildren()
162 {
163   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
164
165   DeleteNodesWithoutSelf otherDeletor(mNode);
166
167   DepthFirst(mNode, otherDeletor);
168
169   mNode->mFirstChild = NULL;
170   mNode->mLastChild  = NULL;
171 }
172
173 TreeNode* TreeNodeManipulator::Copy(const TreeNode& tree, int& numberNodes, int& numberChars)
174 {
175   TreeNode* root = NewTreeNode();
176
177   ShallowCopy(&tree, root);
178
179   if(tree.mName)
180   {
181     numberChars += std::strlen(tree.mName) + 1;
182   }
183
184   if(TreeNode::STRING == tree.mType)
185   {
186     numberChars += std::strlen(tree.mStringValue) + 1;
187   }
188
189   ++numberNodes;
190
191   CopyChildren(&tree, root, numberNodes, numberChars);
192
193   return root;
194 }
195
196 void TreeNodeManipulator::CopyChildren(const TreeNode* from, TreeNode* to, int& numberNodes, int& numberChars)
197 {
198   DALI_ASSERT_DEBUG(from && "Operation on NULL JSON node");
199   DALI_ASSERT_DEBUG(to);
200
201   for(TreeNode::ConstIterator iter = from->CBegin(); iter != from->CEnd(); ++iter)
202   {
203     const TreeNode* child = &((*iter).second);
204     if(child->mName)
205     {
206       numberChars += std::strlen(child->mName) + 1;
207     }
208
209     if(TreeNode::STRING == child->mType)
210     {
211       numberChars += std::strlen(child->mStringValue) + 1;
212     }
213
214     TreeNode* newNode = NewTreeNode();
215
216     ShallowCopy(child, newNode);
217
218     TreeNodeManipulator modify(to);
219
220     modify.AddChild(newNode);
221
222     ++numberNodes;
223
224     CopyChildren(child, newNode, numberNodes, numberChars);
225   }
226 }
227
228 TreeNode* TreeNodeManipulator::AddChild(TreeNode* rhs)
229 {
230   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
231
232   rhs->mParent = mNode;
233   if(mNode->mLastChild)
234   {
235     mNode->mLastChild = mNode->mLastChild->mNextSibling = rhs;
236   }
237   else
238   {
239     mNode->mFirstChild = mNode->mLastChild = rhs;
240   }
241   return rhs;
242 }
243
244 TreeNode::NodeType TreeNodeManipulator::GetType() const
245 {
246   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
247
248   return mNode->GetType();
249 }
250
251 size_t TreeNodeManipulator::Size() const
252 {
253   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
254
255   return mNode->Size();
256 }
257
258 void TreeNodeManipulator::SetType(TreeNode::NodeType type)
259 {
260   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
261
262   if(mNode->mType != type)
263   {
264     mNode->mType = type;
265
266     if(NULL != mNode->mFirstChild)
267     {
268       // value types have no children
269       bool removeChildren = !(TreeNode::OBJECT == type || TreeNode::ARRAY == type);
270
271       // ie if swapping array for object
272       removeChildren = (removeChildren == true) ? true : type != mNode->mType;
273
274       // so remove any children
275       if(removeChildren && NULL != mNode->mFirstChild)
276       {
277         RemoveChildren();
278       }
279     }
280   }
281   else if(TreeNode::ARRAY == mNode->mType)
282   {
283     if(mNode->mFirstChild != NULL)
284     {
285       TreeNode::NodeType firstChildType = mNode->mFirstChild->GetType();
286
287       if(TreeNode::FLOAT == firstChildType || TreeNode::INTEGER == firstChildType)
288       {
289         // Arrays of numbers should be replaced, not appended to.
290         RemoveChildren();
291       }
292     }
293   }
294 }
295
296 void TreeNodeManipulator::SetName(const char* name)
297 {
298   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
299   mNode->mName = name;
300 }
301
302 void TreeNodeManipulator::SetSubstitution(bool b)
303 {
304   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
305   mNode->mSubstituion = b;
306 }
307
308 TreeNode* TreeNodeManipulator::GetParent() const
309 {
310   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
311   return NULL == mNode ? NULL : mNode->mParent;
312 }
313
314 const TreeNode* TreeNodeManipulator::GetChild(const std::string& name) const
315 {
316   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
317   return NULL == mNode ? NULL : mNode->GetChild(name);
318 }
319
320 void TreeNodeManipulator::SetString(const char* string)
321 {
322   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
323   SetType(TreeNode::STRING);
324   mNode->mStringValue = string;
325 }
326
327 void TreeNodeManipulator::SetInteger(int i)
328 {
329   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
330   SetType(TreeNode::INTEGER);
331   mNode->mIntValue = i;
332 }
333
334 void TreeNodeManipulator::SetFloat(float f)
335 {
336   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
337   SetType(TreeNode::FLOAT);
338   mNode->mFloatValue = f;
339 }
340
341 void TreeNodeManipulator::SetBoolean(bool b)
342 {
343   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
344   SetType(TreeNode::BOOLEAN);
345   mNode->mIntValue = b == true ? 1 : 0;
346 }
347
348 void TreeNodeManipulator::Write(std::ostream& output, int indent) const
349 {
350   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
351   DoWrite(mNode, output, 0, indent, false);
352 }
353
354 void TreeNodeManipulator::DoWrite(const TreeNode* value, std::ostream& output, int level, int indentWidth, bool groupChildren) const
355 {
356   DALI_ASSERT_DEBUG(value && "Operation on NULL JSON node");
357
358   if(!groupChildren)
359   {
360     Indent(output, level, indentWidth);
361   }
362
363   if(value->GetName())
364   {
365     output << "\"" << value->GetName() << "\":";
366   }
367
368   switch(value->GetType())
369   {
370     case TreeNode::IS_NULL:
371     {
372       output << "null";
373       if(NULL != value->mNextSibling)
374       {
375         output << ", ";
376       }
377       if(!groupChildren)
378       {
379         output << std::endl;
380       }
381       break;
382     }
383     case TreeNode::OBJECT:
384     case TreeNode::ARRAY:
385     {
386       bool groupMyChildren = false;
387
388       if(TreeNode::ARRAY == value->GetType() && value->mFirstChild &&
389          (TreeNode::INTEGER == value->mFirstChild->GetType() ||
390           TreeNode::FLOAT == value->mFirstChild->GetType()))
391       {
392         groupMyChildren = true;
393       }
394
395       if(value->GetType() == TreeNode::OBJECT)
396       {
397         output << std::endl;
398         Indent(output, level, indentWidth);
399         output << "{";
400       }
401       else
402       {
403         if(!groupMyChildren)
404         {
405           output << std::endl;
406           Indent(output, level, indentWidth);
407         }
408         output << "[";
409       }
410
411       if(groupMyChildren)
412       {
413         output << " ";
414       }
415       else
416       {
417         output << std::endl;
418       }
419
420       for(TreeNode::ConstIterator it = value->CBegin(); it != value->CEnd(); ++it)
421       {
422         DoWrite(&((*it).second), output, level + 1, indentWidth, groupMyChildren);
423       }
424
425       if(!groupMyChildren)
426       {
427         Indent(output, level, indentWidth);
428       }
429
430       if(value->GetType() == TreeNode::OBJECT)
431       {
432         output << "}";
433       }
434       else
435       {
436         output << "]";
437       }
438
439       if(NULL != value->mNextSibling)
440       {
441         output << ",";
442       }
443
444       if(!groupChildren)
445       {
446         output << std::endl;
447       }
448
449       groupChildren = false;
450       break;
451     }
452     case TreeNode::STRING:
453     {
454       std::string escapedString = EscapeQuotes(value->GetString());
455       output << "\"" << escapedString << "\"";
456       if(NULL != value->mNextSibling)
457       {
458         output << ",";
459       }
460
461       if(groupChildren)
462       {
463         output << " ";
464       }
465       else
466       {
467         output << std::endl;
468       }
469       break;
470     }
471     case TreeNode::INTEGER:
472     {
473       output << value->GetInteger();
474       if(NULL != value->mNextSibling)
475       {
476         output << ",";
477       }
478
479       if(groupChildren)
480       {
481         output << " ";
482       }
483       else
484       {
485         output << std::endl;
486       }
487       break;
488     }
489     case TreeNode::FLOAT:
490     {
491       output.setf(std::ios::floatfield);
492       output << value->GetFloat();
493       output.unsetf(std::ios::floatfield);
494       if(NULL != value->mNextSibling)
495       {
496         output << ",";
497       }
498
499       if(groupChildren)
500       {
501         output << " ";
502       }
503       else
504       {
505         output << std::endl;
506       }
507       break;
508     }
509     case TreeNode::BOOLEAN:
510     {
511       if(value->GetInteger())
512       {
513         output << "true";
514       }
515       else
516       {
517         output << "false";
518       }
519
520       if(NULL != value->mNextSibling)
521       {
522         output << ",";
523       }
524
525       if(groupChildren)
526       {
527         output << " ";
528       }
529       else
530       {
531         output << std::endl;
532       }
533
534       break;
535     }
536   } // switch
537 } // DoWrite
538
539 const TreeNode* FindIt(std::string_view childName, const TreeNode* node)
540 {
541   DALI_ASSERT_DEBUG(node);
542
543   const TreeNode* found = NULL;
544
545   if(node)
546   {
547     if(NULL != (found = node->GetChild(childName)))
548     {
549       return found;
550     }
551     else
552     {
553       for(TreeNode::ConstIterator iter = node->CBegin(); iter != node->CEnd(); ++iter)
554       {
555         if(NULL != (found = FindIt(childName, &((*iter).second))))
556         {
557           return found;
558         }
559       }
560     }
561   }
562   return found;
563 }
564
565 char* CopyString(const char* fromString, VectorCharIter& iter, const VectorCharIter& sentinel)
566 {
567   DALI_ASSERT_DEBUG(fromString);
568   DALI_ASSERT_DEBUG(iter != sentinel);
569
570   char*       start = &(*iter);
571   const char* ptr   = fromString;
572
573   if(ptr)
574   {
575     while(*ptr != 0)
576     {
577       DALI_ASSERT_DEBUG(iter != sentinel);
578       *iter++ = *ptr++;
579     }
580
581     *iter++ = 0;
582   }
583   return start;
584 }
585
586 } // namespace Internal
587
588 } // namespace Toolkit
589
590 } // namespace Dali