1 /*-----------------------------------------------------------------------------------------------
2 The MIT License (MIT)
3 
4 Copyright (c) 2014-2015 Kim Kulling
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy of
7 this software and associated documentation files (the "Software"), to deal in
8 the Software without restriction, including without limitation the rights to
9 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10 the Software, and to permit persons to whom the Software is furnished to do so,
11 subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 -----------------------------------------------------------------------------------------------*/
23 #include <openddlparser/OpenDDLExport.h>
24 #include <openddlparser/DDLNode.h>
25 #include <openddlparser/Value.h>
26 #include <openddlparser/OpenDDLParser.h>
27 
28 #include <sstream>
29 
30 BEGIN_ODDLPARSER_NS
31 
32 struct DDLNodeIterator {
33     const DDLNode::DllNodeList &m_childs;
34     size_t m_idx;
35 
DDLNodeIteratorDDLNodeIterator36     DDLNodeIterator( const DDLNode::DllNodeList &childs )
37     : m_childs( childs )
38     , m_idx( 0 ) {
39         // empty
40     }
41 
~DDLNodeIteratorDDLNodeIterator42     ~DDLNodeIterator() {
43         // empty
44     }
45 
getNextDDLNodeIterator46     bool getNext( DDLNode **node ) {
47         if( m_childs.size() > (m_idx+1) ) {
48             m_idx++;
49             *node = m_childs[ m_idx ];
50             return true;
51         }
52 
53         return false;
54     }
55 
56 private:
57     DDLNodeIterator() ddl_no_copy;
58     DDLNodeIterator &operator = ( const DDLNodeIterator & ) ddl_no_copy;
59 };
60 
writeLineEnd(std::string & statement)61 static void writeLineEnd( std::string &statement ) {
62     statement += "\n";
63 }
64 
OpenDDLExport(IOStreamBase * stream)65 OpenDDLExport::OpenDDLExport( IOStreamBase *stream )
66 : m_stream( stream ) {
67     if (ddl_nullptr == m_stream) {
68         m_stream = new IOStreamBase();
69     }
70 }
71 
~OpenDDLExport()72 OpenDDLExport::~OpenDDLExport() {
73     if (ddl_nullptr != m_stream) {
74         m_stream->close();
75     }
76     delete m_stream;
77 }
78 
exportContext(Context * ctx,const std::string & filename)79 bool OpenDDLExport::exportContext( Context *ctx, const std::string &filename ) {
80     if( ddl_nullptr == ctx ) {
81         return false;
82     }
83 
84     DDLNode *root( ctx->m_root );
85     if ( ddl_nullptr == root ) {
86         return true;
87     }
88 
89     if (!filename.empty()) {
90         if (!m_stream->open( filename )) {
91             return false;
92         }
93     }
94 
95     const bool retValue( handleNode( root ) );
96 
97     return retValue;
98 }
99 
handleNode(DDLNode * node)100 bool OpenDDLExport::handleNode( DDLNode *node ) {
101     if( ddl_nullptr == node ) {
102         return true;
103     }
104 
105     const DDLNode::DllNodeList &childs = node->getChildNodeList();
106     if( childs.empty() ) {
107         return true;
108     }
109     DDLNode *current( ddl_nullptr );
110     DDLNodeIterator it( childs );
111     std::string statement;
112     bool success( true );
113     while( it.getNext( &current ) ) {
114         if( ddl_nullptr != current ) {
115             success |= writeNode( current, statement );
116             if( !handleNode( current ) ) {
117                 success = false;
118             }
119         }
120     }
121 
122     return success;
123 }
124 
writeToStream(const std::string & statement)125 bool OpenDDLExport::writeToStream( const std::string &statement ) {
126     if (ddl_nullptr == m_stream ) {
127         return false;
128     }
129 
130     if ( !statement.empty()) {
131         m_stream->write( statement );
132     }
133 
134     return true;
135 }
136 
writeNode(DDLNode * node,std::string & statement)137 bool OpenDDLExport::writeNode( DDLNode *node, std::string &statement ) {
138     writeNodeHeader( node, statement );
139     if (node->hasProperties()) {
140         writeProperties( node, statement );
141     }
142     writeLineEnd( statement );
143 
144     statement = "}";
145     DataArrayList *al( node->getDataArrayList() );
146     if ( ddl_nullptr != al ) {
147         writeValueType( al->m_dataList->m_type, al->m_numItems, statement );
148         writeValueArray( al, statement );
149     }
150     Value *v( node->getValue() );
151     if (ddl_nullptr != v ) {
152         writeValueType( v->m_type, 1, statement );
153         statement = "{";
154         writeLineEnd( statement );
155         writeValue( v, statement );
156         statement = "}";
157         writeLineEnd( statement );
158     }
159     statement = "}";
160     writeLineEnd( statement );
161 
162     writeToStream( statement );
163 
164     return true;
165 }
166 
writeNodeHeader(DDLNode * node,std::string & statement)167 bool OpenDDLExport::writeNodeHeader( DDLNode *node, std::string &statement ) {
168     if (ddl_nullptr == node) {
169         return false;
170     }
171 
172     statement += node->getType();
173     const std::string &name( node->getName() );
174     if ( !name.empty() ) {
175         statement += " ";
176         statement += "$";
177         statement += name;
178     }
179 
180     return true;
181 }
182 
writeProperties(DDLNode * node,std::string & statement)183 bool OpenDDLExport::writeProperties( DDLNode *node, std::string &statement ) {
184     if ( ddl_nullptr == node ) {
185         return false;
186     }
187 
188     Property *prop( node->getProperties() );
189     // if no properties are there, return
190     if ( ddl_nullptr == prop ) {
191         return true;
192     }
193 
194     if ( ddl_nullptr != prop ) {
195         // for instance (attrib = "position", bla=2)
196         statement += "(";
197         bool first( true );
198         while ( ddl_nullptr != prop ) {
199             if (!first) {
200                 statement += ", ";
201             } else {
202                 first = false;
203             }
204             statement += std::string( prop->m_key->m_buffer );
205             statement += " = ";
206             writeValue( prop->m_value, statement );
207             prop = prop->m_next;
208         }
209 
210         statement += ")";
211     }
212 
213     return true;
214 }
215 
writeValueType(Value::ValueType type,size_t numItems,std::string & statement)216 bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std::string &statement ) {
217     if ( Value::ddl_types_max == type) {
218         return false;
219     }
220 
221     const std::string typeStr( getTypeToken( type ) );
222     statement += typeStr;
223     // if we have an array to write
224     if ( numItems > 1 ) {
225         statement += "[";
226         char buffer[ 256 ];
227         ::memset( buffer, '\0', 256 * sizeof( char ) );
228         sprintf( buffer, "%d", static_cast<int>( numItems ) );
229         statement += buffer;
230         statement += "]";
231     }
232 
233     return true;
234 }
235 
writeValue(Value * val,std::string & statement)236 bool OpenDDLExport::writeValue( Value *val, std::string &statement ) {
237     if (ddl_nullptr == val) {
238         return false;
239     }
240 
241     switch ( val->m_type ) {
242         case Value::ddl_bool:
243             if ( true == val->getBool() ) {
244                 statement += "true";
245             } else {
246                 statement += "false";
247             }
248             break;
249         case Value::ddl_int8:
250             {
251                 std::stringstream stream;
252                 const int i = static_cast<int>( val->getInt8() );
253                 stream << i;
254                 statement += stream.str();
255             }
256             break;
257         case Value::ddl_int16:
258             {
259                 std::stringstream stream;
260                 char buffer[ 256 ];
261                 ::memset( buffer, '\0', 256 * sizeof( char ) );
262                 sprintf( buffer, "%d", val->getInt16() );
263                 statement += buffer;
264         }
265             break;
266         case Value::ddl_int32:
267             {
268                 std::stringstream stream;
269                 char buffer[ 256 ];
270                 ::memset( buffer, '\0', 256 * sizeof( char ) );
271                 const int i = static_cast< int >( val->getInt32() );
272                 sprintf( buffer, "%d", i );
273                 statement += buffer;
274             }
275             break;
276         case Value::ddl_int64:
277             {
278                 std::stringstream stream;
279                 const int i = static_cast< int >( val->getInt64() );
280                 stream << i;
281                 statement += stream.str();
282             }
283             break;
284         case Value::ddl_unsigned_int8:
285             {
286                 std::stringstream stream;
287                 const int i = static_cast< unsigned int >( val->getUnsignedInt8() );
288                 stream << i;
289                 statement += stream.str();
290             }
291             break;
292         case Value::ddl_unsigned_int16:
293             {
294                 std::stringstream stream;
295                 const int i = static_cast< unsigned int >( val->getUnsignedInt16() );
296                 stream << i;
297                 statement += stream.str();
298             }
299             break;
300         case Value::ddl_unsigned_int32:
301             {
302                 std::stringstream stream;
303                 const int i = static_cast< unsigned int >( val->getUnsignedInt32() );
304                 stream << i;
305                 statement += stream.str();
306             }
307             break;
308         case Value::ddl_unsigned_int64:
309             {
310                 std::stringstream stream;
311                 const int i = static_cast< unsigned int >( val->getUnsignedInt64() );
312                 stream << i;
313                 statement += stream.str();
314             }
315             break;
316         case Value::ddl_half:
317             break;
318         case Value::ddl_float:
319             {
320                 std::stringstream stream;
321                 stream << val->getFloat();
322                 statement += stream.str();
323             }
324             break;
325         case Value::ddl_double:
326             {
327                 std::stringstream stream;
328                 stream << val->getDouble();
329                 statement += stream.str();
330             }
331             break;
332         case Value::ddl_string:
333             {
334                 std::stringstream stream;
335                 stream << val->getString();
336                 statement += "\"";
337                 statement += stream.str();
338                 statement += "\"";
339              }
340             break;
341         case Value::ddl_ref:
342             break;
343         case Value::ddl_none:
344         case Value::ddl_types_max:
345         default:
346             break;
347     }
348 
349     return true;
350 }
351 
writeValueArray(DataArrayList * al,std::string & statement)352 bool OpenDDLExport::writeValueArray( DataArrayList *al, std::string &statement ) {
353     if (ddl_nullptr == al) {
354         return false;
355     }
356 
357     if (0 == al->m_numItems) {
358         return true;
359     }
360 
361     DataArrayList *nextDataArrayList = al ;
362     while (ddl_nullptr != nextDataArrayList) {
363         if (ddl_nullptr != nextDataArrayList) {
364             statement += "{ ";
365             Value *nextValue( nextDataArrayList->m_dataList );
366             size_t idx( 0 );
367             while (ddl_nullptr != nextValue) {
368                 if (idx > 0) {
369                     statement += ", ";
370                 }
371                 writeValue( nextValue, statement );
372                 nextValue = nextValue->m_next;
373                 idx++;
374             }
375             statement += " }";
376         }
377         nextDataArrayList = nextDataArrayList->m_next;
378     }
379 
380     return true;
381 }
382 
383 END_ODDLPARSER_NS
384 
385