Add post processor
[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   CollectNodes collector;
166
167   DepthFirst(mNode, collector);
168
169   for(CollectNodes::iterator iter = collector.nodes.begin(); iter != collector.nodes.end(); ++iter)
170   {
171     if(*iter != mNode)
172     {
173       delete *iter;
174     }
175   }
176
177   mNode->mFirstChild = NULL;
178   mNode->mLastChild  = NULL;
179 }
180
181 TreeNode* TreeNodeManipulator::Copy(const TreeNode& tree, int& numberNodes, int& numberChars)
182 {
183   TreeNode* root = NewTreeNode();
184
185   ShallowCopy(&tree, root);
186
187   if(tree.mName)
188   {
189     numberChars += std::strlen(tree.mName) + 1;
190   }
191
192   if(TreeNode::STRING == tree.mType)
193   {
194     numberChars += std::strlen(tree.mStringValue) + 1;
195   }
196
197   ++numberNodes;
198
199   CopyChildren(&tree, root, numberNodes, numberChars);
200
201   return root;
202 }
203
204 void TreeNodeManipulator::CopyChildren(const TreeNode* from, TreeNode* to, int& numberNodes, int& numberChars)
205 {
206   DALI_ASSERT_DEBUG(from && "Operation on NULL JSON node");
207   DALI_ASSERT_DEBUG(to);
208
209   for(TreeNode::ConstIterator iter = from->CBegin(); iter != from->CEnd(); ++iter)
210   {
211     const TreeNode* child = &((*iter).second);
212     if(child->mName)
213     {
214       numberChars += std::strlen(child->mName) + 1;
215     }
216
217     if(TreeNode::STRING == child->mType)
218     {
219       numberChars += std::strlen(child->mStringValue) + 1;
220     }
221
222     TreeNode* newNode = NewTreeNode();
223
224     ShallowCopy(child, newNode);
225
226     TreeNodeManipulator modify(to);
227
228     modify.AddChild(newNode);
229
230     ++numberNodes;
231
232     CopyChildren(child, newNode, numberNodes, numberChars);
233   }
234 }
235
236 TreeNode* TreeNodeManipulator::AddChild(TreeNode* rhs)
237 {
238   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
239
240   rhs->mParent = mNode;
241   if(mNode->mLastChild)
242   {
243     mNode->mLastChild = mNode->mLastChild->mNextSibling = rhs;
244   }
245   else
246   {
247     mNode->mFirstChild = mNode->mLastChild = rhs;
248   }
249   return rhs;
250 }
251
252 TreeNode::NodeType TreeNodeManipulator::GetType() const
253 {
254   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
255
256   return mNode->GetType();
257 }
258
259 size_t TreeNodeManipulator::Size() const
260 {
261   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
262
263   return mNode->Size();
264 }
265
266 void TreeNodeManipulator::SetType(TreeNode::NodeType type)
267 {
268   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
269
270   if(mNode->mType != type)
271   {
272     mNode->mType = type;
273
274     if(NULL != mNode->mFirstChild)
275     {
276       // value types have no children
277       bool removeChildren = !(TreeNode::OBJECT == type || TreeNode::ARRAY == type);
278
279       // ie if swapping array for object
280       removeChildren = (removeChildren == true) ? true : type != mNode->mType;
281
282       // so remove any children
283       if(removeChildren && NULL != mNode->mFirstChild)
284       {
285         RemoveChildren();
286       }
287     }
288   }
289   else if(TreeNode::ARRAY == mNode->mType)
290   {
291     if(mNode->mFirstChild != NULL)
292     {
293       TreeNode::NodeType type = mNode->mFirstChild->GetType();
294
295       if(TreeNode::FLOAT == type || TreeNode::INTEGER == type)
296       {
297         // Arrays of numbers should be replaced, not appended to.
298         RemoveChildren();
299       }
300     }
301   }
302 }
303
304 void TreeNodeManipulator::SetName(const char* name)
305 {
306   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
307   mNode->mName = name;
308 }
309
310 void TreeNodeManipulator::SetSubstitution(bool b)
311 {
312   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
313   mNode->mSubstituion = b;
314 }
315
316 TreeNode* TreeNodeManipulator::GetParent() const
317 {
318   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
319   return NULL == mNode ? NULL : mNode->mParent;
320 }
321
322 const TreeNode* TreeNodeManipulator::GetChild(const std::string& name) const
323 {
324   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
325   return NULL == mNode ? NULL : mNode->GetChild(name);
326 }
327
328 void TreeNodeManipulator::SetString(const char* string)
329 {
330   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
331   SetType(TreeNode::STRING);
332   mNode->mStringValue = string;
333 }
334
335 void TreeNodeManipulator::SetInteger(int i)
336 {
337   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
338   SetType(TreeNode::INTEGER);
339   mNode->mIntValue = i;
340 }
341
342 void TreeNodeManipulator::SetFloat(float f)
343 {
344   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
345   SetType(TreeNode::FLOAT);
346   mNode->mFloatValue = f;
347 }
348
349 void TreeNodeManipulator::SetBoolean(bool b)
350 {
351   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
352   SetType(TreeNode::BOOLEAN);
353   mNode->mIntValue = b == true ? 1 : 0;
354 }
355
356 void TreeNodeManipulator::Write(std::ostream& output, int indent) const
357 {
358   DALI_ASSERT_DEBUG(mNode && "Operation on NULL JSON node");
359   DoWrite(mNode, output, 0, indent, false);
360 }
361
362 void TreeNodeManipulator::DoWrite(const TreeNode* value, std::ostream& output, int level, int indentWidth, bool groupChildren) const
363 {
364   DALI_ASSERT_DEBUG(value && "Operation on NULL JSON node");
365
366   if(!groupChildren)
367   {
368     Indent(output, level, indentWidth);
369   }
370
371   if(value->GetName())
372   {
373     output << "\"" << value->GetName() << "\":";
374   }
375
376   switch(value->GetType())
377   {
378     case TreeNode::IS_NULL:
379     {
380       output << "null";
381       if(NULL != value->mNextSibling)
382       {
383         output << ", ";
384       }
385       if(!groupChildren)
386       {
387         output << std::endl;
388       }
389       break;
390     }
391     case TreeNode::OBJECT:
392     case TreeNode::ARRAY:
393     {
394       bool groupMyChildren = false;
395
396       if(TreeNode::ARRAY == value->GetType() && value->mFirstChild &&
397          (TreeNode::INTEGER == value->mFirstChild->GetType() ||
398           TreeNode::FLOAT == value->mFirstChild->GetType()))
399       {
400         groupMyChildren = true;
401       }
402
403       if(value->GetType() == TreeNode::OBJECT)
404       {
405         output << std::endl;
406         Indent(output, level, indentWidth);
407         output << "{";
408       }
409       else
410       {
411         if(!groupMyChildren)
412         {
413           output << std::endl;
414           Indent(output, level, indentWidth);
415         }
416         output << "[";
417       }
418
419       if(groupMyChildren)
420       {
421         output << " ";
422       }
423       else
424       {
425         output << std::endl;
426       }
427
428       for(TreeNode::ConstIterator it = value->CBegin(); it != value->CEnd(); ++it)
429       {
430         DoWrite(&((*it).second), output, level + 1, indentWidth, groupMyChildren);
431       }
432
433       if(!groupMyChildren)
434       {
435         Indent(output, level, indentWidth);
436       }
437
438       if(value->GetType() == TreeNode::OBJECT)
439       {
440         output << "}";
441       }
442       else
443       {
444         output << "]";
445       }
446
447       if(NULL != value->mNextSibling)
448       {
449         output << ",";
450       }
451
452       if(!groupChildren)
453       {
454         output << std::endl;
455       }
456
457       groupChildren = false;
458       break;
459     }
460     case TreeNode::STRING:
461     {
462       std::string escapedString = EscapeQuotes(value->GetString());
463       output << "\"" << escapedString << "\"";
464       if(NULL != value->mNextSibling)
465       {
466         output << ",";
467       }
468
469       if(groupChildren)
470       {
471         output << " ";
472       }
473       else
474       {
475         output << std::endl;
476       }
477       break;
478     }
479     case TreeNode::INTEGER:
480     {
481       output << value->GetInteger();
482       if(NULL != value->mNextSibling)
483       {
484         output << ",";
485       }
486
487       if(groupChildren)
488       {
489         output << " ";
490       }
491       else
492       {
493         output << std::endl;
494       }
495       break;
496     }
497     case TreeNode::FLOAT:
498     {
499       output.setf(std::ios::floatfield);
500       output << value->GetFloat();
501       output.unsetf(std::ios::floatfield);
502       if(NULL != value->mNextSibling)
503       {
504         output << ",";
505       }
506
507       if(groupChildren)
508       {
509         output << " ";
510       }
511       else
512       {
513         output << std::endl;
514       }
515       break;
516     }
517     case TreeNode::BOOLEAN:
518     {
519       if(value->GetInteger())
520       {
521         output << "true";
522       }
523       else
524       {
525         output << "false";
526       }
527
528       if(NULL != value->mNextSibling)
529       {
530         output << ",";
531       }
532
533       if(groupChildren)
534       {
535         output << " ";
536       }
537       else
538       {
539         output << std::endl;
540       }
541
542       break;
543     }
544   } // switch
545 } // DoWrite
546
547 const TreeNode* FindIt(std::string_view childName, const TreeNode* node)
548 {
549   DALI_ASSERT_DEBUG(node);
550
551   const TreeNode* found = NULL;
552
553   if(node)
554   {
555     if(NULL != (found = node->GetChild(childName)))
556     {
557       return found;
558     }
559     else
560     {
561       for(TreeNode::ConstIterator iter = node->CBegin(); iter != node->CEnd(); ++iter)
562       {
563         if(NULL != (found = FindIt(childName, &((*iter).second))))
564         {
565           return found;
566         }
567       }
568     }
569   }
570   return found;
571 }
572
573 char* CopyString(const char* fromString, VectorCharIter& iter, const VectorCharIter& sentinel)
574 {
575   DALI_ASSERT_DEBUG(fromString);
576   DALI_ASSERT_DEBUG(iter != sentinel);
577
578   char*       start = &(*iter);
579   const char* ptr   = fromString;
580
581   if(ptr)
582   {
583     while(*ptr != 0)
584     {
585       DALI_ASSERT_DEBUG(iter != sentinel);
586       *iter++ = *ptr++;
587     }
588
589     *iter++ = 0;
590   }
591   return start;
592 }
593
594 } // namespace Internal
595
596 } // namespace Toolkit
597
598 } // namespace Dali