483e86ec5e6e2a1ac1a602d017be4d9760f09266
[anna.git] / source / xml / Compiler.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <anna/core/mt/Guard.hpp>
10
11 #include <anna/xml/Compiler.hpp>
12 #include <anna/xml/Node.hpp>
13 #include <anna/xml/Attribute.hpp>
14 #include <anna/xml/Text.hpp>
15 #include <anna/xml/internal/sccs.hpp>
16 #include <anna/xml/Document.hpp>
17 #include <anna/xml/Namespace.hpp>
18
19 using namespace anna;
20 using namespace anna::xml;
21
22 Compiler::Compiler() {
23   sccs::activate();
24 }
25
26 const char* Compiler::apply(const Node* node, const int flags)
27 throw(RuntimeException) {
28   Guard guard(this, "xml::Compiler::apply");
29   a_result.clear();
30
31   if(flags & Mode::Compact)
32     apply(node, a_result, flags);
33   else
34     apply(node, a_result, 0, flags);
35
36   return a_result.c_str();
37 }
38
39 const char* Compiler::apply(const Document& document, const Node* node, const int flags)
40 throw(RuntimeException) {
41   Guard guard(this, "xml::Compiler::apply");
42   a_result.clear();
43   const char* version = document.getVersion();
44   a_result += "<?xml";
45
46   if(version != NULL) {
47     a_result += " version='";
48     a_result += version;
49     a_result += "'";
50   }
51
52   const char* encoding = document.getEncoding();
53
54   if(encoding != NULL) {
55     a_result += " encoding='";
56     a_result += encoding;
57     a_result += "'";
58   }
59
60   a_result += "?>\n";
61
62   if(flags & Mode::Compact)
63     apply(node, a_result, flags);
64   else
65     apply(node, a_result, 0, flags);
66
67   return a_result.c_str();
68 }
69
70 //------------------------------------------------------------------------------------
71 // (1) Si tiene nodos hijos => ignora el texto, porque no se como representar
72 // nodos + texto.
73 //------------------------------------------------------------------------------------
74 void Compiler::apply(const Node* node, Result& result, const int level, const int flags)
75 throw(RuntimeException) {
76   const bool hasText(node->getText() != NULL);
77   Node::const_child_iterator ii = node->child_begin();
78   Node::const_child_iterator maxii = node->child_end();
79   const bool hasChildren(ii != maxii);
80
81   if(hasChildren == false && hasText == false)
82     open(node, result, level, true, true, flags);
83   else if(hasChildren == false && hasText == true) {
84     open(node, result, level, false, false, flags);
85     result += node->getText()->getValue();
86     close(node, result, 0, flags);
87   } else if(hasChildren == true) {                    // (1)
88     open(node, result, level, false, true, flags);
89
90     for(; ii != maxii; ii ++)
91       apply(Node::node(ii), result, level + 1, flags);
92
93     close(node, result, level, flags);
94   }
95 }
96
97 //------------------------------------------------------------------------------------
98 // (1) Si tiene nodos hijos => ignora el texto, porque no se como representar
99 // nodos + texto.
100 //------------------------------------------------------------------------------------
101 void Compiler::apply(const Node* node, Result& result, const int flags)
102 throw(RuntimeException) {
103   static const int level = 0;
104   const bool hasText(node->getText() != NULL);
105   Node::const_child_iterator ii = node->child_begin();
106   Node::const_child_iterator maxii = node->child_end();
107   const bool hasChildren(ii != maxii);
108
109   if(hasChildren == false && hasText == false)
110     open(node, result, level, true, false, flags);
111   else if(hasChildren == false && hasText == true) {
112     open(node, result, level, false, false, flags);
113     result += node->getText()->getValue();
114     result += "</";
115     writeFullName(node, result, flags);
116     result += ">";
117   } else if(hasChildren == true) {                    // (1)
118     open(node, result, level, false, false, flags);
119
120     for(; ii != maxii; ii ++)
121       apply(Node::node(ii), result, flags);
122
123     result += "</";
124     writeFullName(node, result, flags);
125     result += ">";
126   }
127 }
128
129 /*static*/
130 void Compiler::open(const Node* node, Result& result, const int level, const bool quickClose, const bool newline, const int flags)
131 throw(RuntimeException) {
132   const Attribute* attribute;
133   const Namespace* ns;
134
135   for(int i = 0; i < level; i ++)
136     result += ANNA_XML_COMPILER_TAB;
137
138   result += '<';
139   writeFullName(node, result, flags);
140
141   // Si es el nodo ROOT => Tenemos que representar la deficiĆ³n de los namespaces
142   if(node->getParent() == NULL && node->namespace_size() != 0) {
143     for(xml::Node::const_namespace_iterator ii = node->namespace_begin(), maxii = node->namespace_end(); ii != maxii; ii ++) {
144       ns = xml::Node::xnamespace(ii);
145       result += " xmlns:";
146       result += ns->getName();
147       result += "=\"";
148       result += ns->getReference();
149       result += "\"";
150     }
151   }
152
153   for(Node::const_attribute_iterator ii = node->attribute_begin(), maxii = node->attribute_end(); ii != maxii; ii ++) {
154     attribute = Node::attribute(ii);
155     result += ' ';
156     writeFullName(attribute, result, flags);
157     const std::string& value = attribute->getValue();
158
159     if(value.length() > 0) {
160       result += "=\"";
161       result += attribute->getValue();
162       result += "\"";
163     } else if(flags & Mode::ShowNullAttribute)
164       result += "=\"\"";
165   }
166
167   if(quickClose == true)
168     result += '/';
169
170   result += '>';
171
172   if(newline == true)
173     result += '\n';
174 }
175
176 /*static*/
177 void Compiler::writeFullName(const Node* node, Result& result, const int flags)
178 throw(RuntimeException) {
179   const Namespace* ns;
180
181   if((flags & Mode::NoNamespaces) == 0 && (ns = node->getNamespace()) != NULL) {
182     result += ns->getName();
183     result += ':';
184   }
185
186   result += node->getName();
187 }
188
189 /*static*/
190 void Compiler::writeFullName(const Attribute* attr, Result& result, const int flags)
191 throw(RuntimeException) {
192   const Namespace* ns;
193
194   if((flags & Mode::NoNamespaces) == 0 && (ns = attr->getNamespace()) != NULL) {
195     result += ns->getName();
196     result += ':';
197   }
198
199   result += attr->getName();
200 }
201
202 /*static*/
203 void Compiler::close(const Node* node, Result& result, const int level, const int flags)
204 throw(RuntimeException) {
205   for(int i = 0; i < level; i ++)
206     result += ANNA_XML_COMPILER_TAB;
207
208   result += "</";
209   writeFullName(node, result, flags);
210   result += ">\n";
211 }
212
213 void Compiler::Result::extend(const int nbytes)
214 throw(RuntimeException) {
215   if((a_size + nbytes) >= a_maxSize) {
216     int newSize = ((a_size + nbytes) << 1) - ((a_size + nbytes)  >> 1);
217     char* newBuffer = new char [newSize];
218
219     if(newBuffer == NULL)
220       throw RuntimeException("Insufficient memory", ANNA_FILE_LOCATION);
221
222     if(a_size > 0)
223       anna_memcpy(newBuffer, a_buffer, a_size);
224
225     delete [] a_buffer;
226     a_buffer = newBuffer;
227     a_maxSize = newSize;
228   }
229 }
230