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 
StreamFormatterBase()32 StreamFormatterBase::StreamFormatterBase() {
33 
34 }
35 
~StreamFormatterBase()36 StreamFormatterBase::~StreamFormatterBase() {
37 
38 }
39 
format(const std::string & statement)40 std::string StreamFormatterBase::format( const std::string &statement ) {
41     std::string tmp( statement );
42     return tmp;
43 }
44 
IOStreamBase(StreamFormatterBase * formatter)45 IOStreamBase::IOStreamBase( StreamFormatterBase *formatter )
46 : m_formatter( formatter )
47 , m_file( ddl_nullptr ) {
48     if (ddl_nullptr == m_formatter) {
49         m_formatter = new StreamFormatterBase;
50     }
51 }
52 
~IOStreamBase()53 IOStreamBase::~IOStreamBase() {
54     delete m_formatter;
55     m_formatter = ddl_nullptr;
56 }
57 
open(const std::string & name)58 bool IOStreamBase::open( const std::string &name ) {
59     m_file = ::fopen( name.c_str(), "a" );
60     if (m_file == ddl_nullptr) {
61         return false;
62     }
63 
64     return true;
65 }
66 
close()67 bool IOStreamBase::close() {
68     if (ddl_nullptr == m_file) {
69         return false;
70     }
71 
72     ::fclose( m_file );
73     m_file = ddl_nullptr;
74 
75     return true;
76 }
77 
write(const std::string & statement)78 size_t IOStreamBase::write( const std::string &statement ) {
79     if (ddl_nullptr == m_file) {
80         return 0;
81     }
82     std::string formatStatement = m_formatter->format( statement );
83     return ::fwrite( formatStatement.c_str(), sizeof( char ), formatStatement.size(), m_file );
84 }
85 
86 struct DDLNodeIterator {
87     const DDLNode::DllNodeList &m_childs;
88     size_t m_idx;
89 
DDLNodeIteratorDDLNodeIterator90     DDLNodeIterator( const DDLNode::DllNodeList &childs )
91     : m_childs( childs )
92     , m_idx( 0 ) {
93         // empty
94     }
95 
~DDLNodeIteratorDDLNodeIterator96     ~DDLNodeIterator() {
97         // empty
98     }
99 
getNextDDLNodeIterator100     bool getNext( DDLNode **node ) {
101         if( m_childs.size() > (m_idx+1) ) {
102             m_idx++;
103             *node = m_childs[ m_idx ];
104             return true;
105         }
106 
107         return false;
108     }
109 
110 private:
111     DDLNodeIterator() ddl_no_copy;
112     DDLNodeIterator &operator = ( const DDLNodeIterator & ) ddl_no_copy;
113 };
114 
writeLineEnd(std::string & statement)115 static void writeLineEnd( std::string &statement ) {
116     statement += "\n";
117 }
118 
OpenDDLExport(IOStreamBase * stream)119 OpenDDLExport::OpenDDLExport( IOStreamBase *stream )
120 : m_stream( stream ) {
121     if (ddl_nullptr == m_stream) {
122         m_stream = new IOStreamBase();
123     }
124 }
125 
~OpenDDLExport()126 OpenDDLExport::~OpenDDLExport() {
127     if (ddl_nullptr != m_stream) {
128         m_stream->close();
129     }
130     delete m_stream;
131 }
132 
exportContext(Context * ctx,const std::string & filename)133 bool OpenDDLExport::exportContext( Context *ctx, const std::string &filename ) {
134     if( ddl_nullptr == ctx ) {
135         return false;
136     }
137 
138     DDLNode *root( ctx->m_root );
139     if ( ddl_nullptr == root ) {
140         return true;
141     }
142 
143     if (!filename.empty()) {
144         if (!m_stream->open( filename )) {
145             return false;
146         }
147     }
148 
149     const bool retValue( handleNode( root ) );
150 
151     return retValue;
152 }
153 
handleNode(DDLNode * node)154 bool OpenDDLExport::handleNode( DDLNode *node ) {
155     if( ddl_nullptr == node ) {
156         return true;
157     }
158 
159     const DDLNode::DllNodeList &childs = node->getChildNodeList();
160     if( childs.empty() ) {
161         return true;
162     }
163     DDLNode *current( ddl_nullptr );
164     DDLNodeIterator it( childs );
165     std::string statement;
166     bool success( true );
167     while( it.getNext( &current ) ) {
168         if( ddl_nullptr != current ) {
169             success |= writeNode( current, statement );
170             if( !handleNode( current ) ) {
171                 success = false;
172             }
173         }
174     }
175 
176     return success;
177 }
178 
writeToStream(const std::string & statement)179 bool OpenDDLExport::writeToStream( const std::string &statement ) {
180     if (ddl_nullptr == m_stream ) {
181         return false;
182     }
183 
184     if ( !statement.empty()) {
185         m_stream->write( statement );
186     }
187 
188     return true;
189 }
190 
writeNode(DDLNode * node,std::string & statement)191 bool OpenDDLExport::writeNode( DDLNode *node, std::string &statement ) {
192     bool success( true );
193     writeNodeHeader( node, statement );
194     if (node->hasProperties()) {
195         success |= writeProperties( node, statement );
196     }
197     writeLineEnd( statement );
198 
199     statement = "}";
200     DataArrayList *al( node->getDataArrayList() );
201     if ( ddl_nullptr != al ) {
202         writeValueType( al->m_dataList->m_type, al->m_numItems, statement );
203         writeValueArray( al, statement );
204     }
205     Value *v( node->getValue() );
206     if (ddl_nullptr != v ) {
207         writeValueType( v->m_type, 1, statement );
208         statement = "{";
209         writeLineEnd( statement );
210         writeValue( v, statement );
211         statement = "}";
212         writeLineEnd( statement );
213     }
214     statement = "}";
215     writeLineEnd( statement );
216 
217     writeToStream( statement );
218 
219     return true;
220 }
221 
writeNodeHeader(DDLNode * node,std::string & statement)222 bool OpenDDLExport::writeNodeHeader( DDLNode *node, std::string &statement ) {
223     if (ddl_nullptr == node) {
224         return false;
225     }
226 
227     statement += node->getType();
228     const std::string &name( node->getName() );
229     if ( !name.empty() ) {
230         statement += " ";
231         statement += "$";
232         statement += name;
233     }
234 
235     return true;
236 }
237 
writeProperties(DDLNode * node,std::string & statement)238 bool OpenDDLExport::writeProperties( DDLNode *node, std::string &statement ) {
239     if ( ddl_nullptr == node ) {
240         return false;
241     }
242 
243     Property *prop( node->getProperties() );
244     // if no properties are there, return
245     if ( ddl_nullptr == prop ) {
246         return true;
247     }
248 
249     if ( ddl_nullptr != prop ) {
250         // for instance (attrib = "position", bla=2)
251         statement += "(";
252         bool first( true );
253         while ( ddl_nullptr != prop ) {
254             if (!first) {
255                 statement += ", ";
256             } else {
257                 first = false;
258             }
259             statement += std::string( prop->m_key->m_buffer );
260             statement += " = ";
261             writeValue( prop->m_value, statement );
262             prop = prop->m_next;
263         }
264 
265         statement += ")";
266     }
267 
268     return true;
269 }
270 
writeValueType(Value::ValueType type,size_t numItems,std::string & statement)271 bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std::string &statement ) {
272     if ( Value::ddl_types_max == type) {
273         return false;
274     }
275 
276     const std::string typeStr( getTypeToken( type ) );
277     statement += typeStr;
278     // if we have an array to write
279     if ( numItems > 1 ) {
280         statement += "[";
281         char buffer[ 256 ];
282         ::memset( buffer, '\0', 256 * sizeof( char ) );
283         sprintf( buffer, "%d", numItems );
284         statement += buffer;
285         statement += "]";
286     }
287 
288     return true;
289 }
290 
writeValue(Value * val,std::string & statement)291 bool OpenDDLExport::writeValue( Value *val, std::string &statement ) {
292     if (ddl_nullptr == val) {
293         return false;
294     }
295 
296     switch ( val->m_type ) {
297         case Value::ddl_bool:
298             if ( true == val->getBool() ) {
299                 statement += "true";
300             } else {
301                 statement += "false";
302             }
303             break;
304         case Value::ddl_int8:
305             {
306                 std::stringstream stream;
307                 const int i = static_cast<int>( val->getInt8() );
308                 stream << i;
309                 statement += stream.str();
310             }
311             break;
312         case Value::ddl_int16:
313             {
314                 std::stringstream stream;
315                 char buffer[ 256 ];
316                 ::memset( buffer, '\0', 256 * sizeof( char ) );
317                 sprintf( buffer, "%d", val->getInt16() );
318                 statement += buffer;
319         }
320             break;
321         case Value::ddl_int32:
322             {
323                 std::stringstream stream;
324                 char buffer[ 256 ];
325                 ::memset( buffer, '\0', 256 * sizeof( char ) );
326                 const int i = static_cast< int >( val->getInt32() );
327                 sprintf( buffer, "%d", i );
328                 statement += buffer;
329             }
330             break;
331         case Value::ddl_int64:
332             {
333                 std::stringstream stream;
334                 const int i = static_cast< int >( val->getInt64() );
335                 stream << i;
336                 statement += stream.str();
337             }
338             break;
339         case Value::ddl_unsigned_int8:
340             {
341                 std::stringstream stream;
342                 const int i = static_cast< unsigned int >( val->getUnsignedInt8() );
343                 stream << i;
344                 statement += stream.str();
345             }
346             break;
347         case Value::ddl_unsigned_int16:
348             {
349                 std::stringstream stream;
350                 const int i = static_cast< unsigned int >( val->getUnsignedInt16() );
351                 stream << i;
352                 statement += stream.str();
353             }
354             break;
355         case Value::ddl_unsigned_int32:
356             {
357                 std::stringstream stream;
358                 const int i = static_cast< unsigned int >( val->getUnsignedInt32() );
359                 stream << i;
360                 statement += stream.str();
361             }
362             break;
363         case Value::ddl_unsigned_int64:
364             {
365                 std::stringstream stream;
366                 const int i = static_cast< unsigned int >( val->getUnsignedInt64() );
367                 stream << i;
368                 statement += stream.str();
369             }
370             break;
371         case Value::ddl_half:
372             break;
373         case Value::ddl_float:
374             {
375                 std::stringstream stream;
376                 stream << val->getFloat();
377                 statement += stream.str();
378             }
379             break;
380         case Value::ddl_double:
381             {
382                 std::stringstream stream;
383                 stream << val->getDouble();
384                 statement += stream.str();
385             }
386             break;
387         case Value::ddl_string:
388             {
389                 std::stringstream stream;
390                 stream << val->getString();
391                 statement += "\"";
392                 statement += stream.str();
393                 statement += "\"";
394              }
395             break;
396         case Value::ddl_ref:
397             break;
398         case Value::ddl_none:
399         case Value::ddl_types_max:
400         default:
401             break;
402     }
403 
404     return true;
405 }
406 
writeValueArray(DataArrayList * al,std::string & statement)407 bool OpenDDLExport::writeValueArray( DataArrayList *al, std::string &statement ) {
408     if (ddl_nullptr == al) {
409         return false;
410     }
411 
412     if (0 == al->m_numItems) {
413         return true;
414     }
415 
416     DataArrayList *nextDataArrayList = al ;
417     Value *nextValue( nextDataArrayList->m_dataList );
418     while (ddl_nullptr != nextDataArrayList) {
419         if (ddl_nullptr != nextDataArrayList) {
420             statement += "{ ";
421             nextValue = nextDataArrayList->m_dataList;
422             size_t idx( 0 );
423             while (ddl_nullptr != nextValue) {
424                 if (idx > 0) {
425                     statement += ", ";
426                 }
427                 writeValue( nextValue, statement );
428                 nextValue = nextValue->m_next;
429                 idx++;
430             }
431             statement += " }";
432         }
433         nextDataArrayList = nextDataArrayList->m_next;
434     }
435 
436     return true;
437 }
438 
439 END_ODDLPARSER_NS
440 
441