root/trunk/libffado/src/libutil/serialize_expat.cpp

Revision 1154, 10.7 kB (checked in by ppalmers, 14 years ago)

add expat based parsing of the device cache. add compile-time selection between libxml++ and expat. will allow to get rid of the libxml++ dependency on the long run. scons SERIALIZE_USE_EXPAT=0Only compile testedscons SERIALIZE_USE_EXPAT=0

Line 
1 /*
2  * Copyright (C) 2005-2008 by Daniel Wagner
3  * Copyright (C) 2005-2008 by Pieter Palmers
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB.
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) version 3 of the License.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24 #include "config.h" // FOR CACHE_VERSION
25
26 #include "serialize.h"
27
28 using namespace std;
29
30
31 IMPL_DEBUG_MODULE( Util::XMLSerialize,   XMLSerialize,   DEBUG_LEVEL_NORMAL );
32 IMPL_DEBUG_MODULE( Util::XMLDeserialize, XMLDeserialize, DEBUG_LEVEL_NORMAL );
33
34 Util::XMLSerialize::XMLSerialize( std::string fileName )
35     : IOSerialize()
36     , m_filepath( fileName )
37     , m_verboseLevel( DEBUG_LEVEL_NORMAL )
38 {
39     setDebugLevel( DEBUG_LEVEL_NORMAL );
40     try {
41         m_doc.create_root_node( "ffado_cache" );
42         writeVersion();
43     } catch ( const exception& ex ) {
44         cout << "Exception caught: " << ex.what();
45     }
46 }
47
48 Util::XMLSerialize::XMLSerialize( std::string fileName, int verboseLevel )
49     : IOSerialize()
50     , m_filepath( fileName )
51     , m_verboseLevel( verboseLevel )
52 {
53     setDebugLevel(verboseLevel);
54     try {
55         m_doc.create_root_node( "ffado_cache" );
56         writeVersion();
57     } catch ( const exception& ex ) {
58         cout << "Exception caught: " << ex.what();
59     }
60 }
61
62 Util::XMLSerialize::~XMLSerialize()
63 {
64     try {
65         m_doc.write_to_file_formatted( m_filepath );
66     } catch ( const exception& ex ) {
67         cout << "Exception caugth: " << ex.what();
68     }
69
70 }
71
72 void
73 Util::XMLSerialize::writeVersion()
74 {
75     Xml::Node* pNode = m_doc.get_root_node();
76     if(pNode) {
77         char* valstr;
78         asprintf( &valstr, "%s", CACHE_VERSION );
79
80         // check whether we already have a version node
81         Xml::Nodes versionfields = (*pNode)["CacheVersion"];
82
83         if(versionfields.size()) { // set the value
84             versionfields.at(0)->set_child_text( valstr );
85         } else {
86             // make a new field
87             Xml::Node &n = pNode->add( Xml::Node("CacheVersion", NULL) );
88             n.set_child_text( valstr );
89         }
90         free( valstr );
91     } else {
92         debugError("No root node\n");
93     }
94 }
95
96 bool
97 Util::XMLSerialize::write( std::string strMemberName,
98                            long long value )
99
100 {
101     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "write %s = %d\n",
102                  strMemberName.c_str(), value );
103
104     std::vector<std::string> tokens;
105     tokenize( strMemberName, tokens, "/" );
106
107     if ( tokens.size() == 0 ) {
108         debugWarning( "token size is 0\n" );
109         return false;
110     }
111
112     Xml::Node* pNode = m_doc.get_root_node();
113     if(pNode) {
114         pNode = getNodePath( pNode, tokens );
115         if(pNode) {
116             // element to be added
117             Xml::Node& n = pNode->add( Xml::Node(tokens[tokens.size() - 1].c_str(), NULL) );
118             char* valstr;
119             asprintf( &valstr, "%lld", value );
120             n.set_child_text( valstr );
121             free( valstr );
122         } else {
123             return false;
124         }
125     } else {
126         return false;
127     }
128     return true;
129 }
130
131 bool
132 Util::XMLSerialize::write( std::string strMemberName,
133                            std::string str)
134 {
135     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "write %s = %s\n",
136                  strMemberName.c_str(), str.c_str() );
137
138     std::vector<std::string> tokens;
139     tokenize( strMemberName, tokens, "/" );
140
141     if ( tokens.size() == 0 ) {
142         debugWarning( "token size is 0\n" );
143         return false;
144     }
145
146     Xml::Node* pNode = m_doc.get_root_node();
147     if(pNode) {
148         pNode = getNodePath( pNode, tokens );
149         if(pNode) {
150             // element to be added
151             Xml::Node& n = pNode->add( Xml::Node(tokens[tokens.size() - 1].c_str(), NULL) );
152             n.set_child_text( str );
153         } else {
154             return false;
155         }
156     } else {
157         return false;
158     }
159     return true;
160
161 }
162
163 Util::Xml::Node*
164 Util::XMLSerialize::getNodePath( Util::Xml::Node* pRootNode,
165                                  std::vector<string>& tokens )
166 {
167     // returns the correct node on which the new element has to be added.
168     // if the path does not exist, it will be created.
169
170     if ( tokens.size() == 1 ) {
171         return pRootNode;
172     }
173
174     unsigned int iTokenIdx = 0;
175     Xml::Node* pCurNode = pRootNode;
176     for (bool bFound = false;
177          ( iTokenIdx < tokens.size() - 1 );
178          bFound = false, iTokenIdx++ )
179     {
180         Xml::Node::Children& nodeList = pCurNode->children;
181         for ( Xml::Node::Children::iterator it = nodeList.begin();
182               it != nodeList.end();
183               ++it )
184         {
185             Xml::Node* thisNode = &( *it );
186             if ( thisNode->name.compare(tokens[iTokenIdx]) == 0 ) {
187                 pCurNode = thisNode;
188                 bFound = true;
189                 break;
190             }
191         }
192         if ( !bFound ) {
193             break;
194         }
195     }
196
197     for ( unsigned int i = iTokenIdx; i < tokens.size() - 1; i++, iTokenIdx++ ) {
198         Xml::Node& n = pCurNode->add( Xml::Node(tokens[iTokenIdx].c_str(), NULL) );
199         pCurNode = &n;
200     }
201     return pCurNode;
202 }
203
204 /***********************************/
205
206 Util::XMLDeserialize::XMLDeserialize( std::string fileName )
207     : IODeserialize()
208     , m_filepath( fileName )
209     , m_verboseLevel( DEBUG_LEVEL_NORMAL )
210 {
211     setDebugLevel(DEBUG_LEVEL_NORMAL);
212     try {
213 //         m_parser.set_substitute_entities(); //We just want the text to
214                                             //be resolved/unescaped
215                                             //automatically.
216         m_doc.load_from_file(m_filepath);
217     } catch ( const exception& ex ) {
218         cout << "Exception caught: " << ex.what();
219     }
220 }
221
222 Util::XMLDeserialize::XMLDeserialize( std::string fileName, int verboseLevel )
223     : IODeserialize()
224     , m_filepath( fileName )
225     , m_verboseLevel( verboseLevel )
226 {
227     setDebugLevel(verboseLevel);
228     try {
229 //         m_parser.set_substitute_entities(); //We just want the text to
230                                             //be resolved/unescaped
231                                             //automatically.
232         m_doc.load_from_file(m_filepath);
233     } catch ( const exception& ex ) {
234         cout << "Exception caught: " << ex.what();
235     }
236 }
237
238 Util::XMLDeserialize::~XMLDeserialize()
239 {
240 }
241
242 bool
243 Util::XMLDeserialize::isValid()
244 {
245     return checkVersion();
246 }
247
248 bool
249 Util::XMLDeserialize::checkVersion()
250 {
251     std::string savedVersion;
252     if (read( "CacheVersion", savedVersion )) {
253         std::string expectedVersion = CACHE_VERSION;
254         debugOutput( DEBUG_LEVEL_NORMAL, "Cache version: %s, expected: %s.\n", savedVersion.c_str(), expectedVersion.c_str() );
255         if (expectedVersion == savedVersion) {
256             debugOutput( DEBUG_LEVEL_VERBOSE, "Cache version OK.\n" );
257             return true;
258         } else {
259             debugOutput( DEBUG_LEVEL_VERBOSE, "Cache version not OK.\n" );
260             return false;
261         }
262     } else return false;
263 }
264
265 bool
266 Util::XMLDeserialize::read( std::string strMemberName,
267                             long long& value )
268
269 {
270     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "lookup %s\n", strMemberName.c_str() );
271
272     Xml::Node* pNode = m_doc.get_root_node();
273
274     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "pNode = %s\n", pNode->name.c_str() );
275     if(pNode) {
276         Xml::Nodes nodeSet = pNode->find( strMemberName );
277         for ( Xml::Nodes::iterator it = nodeSet.begin();
278             it != nodeSet.end();
279             ++it )
280         {
281             Xml::Node *n = *it;
282             if(n && n->has_child_text() ) {
283                 char* tail;
284                 value = strtoll( n->get_child_text().c_str(),
285                                 &tail, 0 );
286                 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "found %s = %d\n",
287                             strMemberName.c_str(), value );
288                 return true;
289             }
290             debugWarning( "no such a node %s\n", strMemberName.c_str() );
291             return false;
292         }
293    
294         debugWarning( "no such a node %s\n", strMemberName.c_str() );
295         return false;
296     } else {
297         debugError("No root node\n");
298         return false;
299     }
300 }
301
302 bool
303 Util::XMLDeserialize::read( std::string strMemberName,
304                             std::string& str )
305 {
306     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "lookup %s\n", strMemberName.c_str() );
307
308     Xml::Node* pNode = m_doc.get_root_node();
309
310     debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "pNode = %s\n", pNode->name.c_str() );
311     if(pNode) {
312         Xml::Nodes nodeSet = pNode->find( strMemberName );
313         for ( Xml::Nodes::iterator it = nodeSet.begin();
314             it != nodeSet.end();
315             ++it )
316         {
317             Xml::Node *n = *it;
318             if(n) {
319                 if(n->has_child_text() ) {
320                     str = n->get_child_text();
321                 } else {
322                     str = "";
323                 }
324                 debugOutput( DEBUG_LEVEL_VERY_VERBOSE, "found %s = %s\n",
325                             strMemberName.c_str(), str.c_str() );
326                 return true;
327             }
328             debugWarning( "no such a node %s\n", strMemberName.c_str() );
329             return false;
330         }
331    
332         debugWarning( "no such a node %s\n", strMemberName.c_str() );
333         return false;
334     } else {
335         debugError("No root node\n");
336         return false;
337     }
338 }
339
340 bool
341 Util::XMLDeserialize::isExisting( std::string strMemberName )
342 {
343     Xml::Node* pNode = m_doc.get_root_node();
344     if(pNode) {
345         Xml::Nodes nodeSet = pNode->find( strMemberName );
346         return nodeSet.size() > 0;
347     } else return false;
348 }
349
350 void
351 tokenize(const string& str,
352          vector<string>& tokens,
353          const string& delimiters)
354 {
355     // Skip delimiters at beginning.
356     string::size_type lastPos = str.find_first_not_of(delimiters, 0);
357     // Find first "non-delimiter".
358     string::size_type pos     = str.find_first_of(delimiters, lastPos);
359
360     while (string::npos != pos || string::npos != lastPos)
361     {
362         // Found a token, add it to the vector.
363         tokens.push_back(str.substr(lastPos, pos - lastPos));
364         // Skip delimiters.  Note the "not_of"
365         lastPos = str.find_first_not_of(delimiters, pos);
366         // Find next "non-delimiter"
367         pos = str.find_first_of(delimiters, lastPos);
368     }
369 }
Note: See TracBrowser for help on using the browser.