]> git.saurik.com Git - wxWidgets.git/blame - src/common/xtixml.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / xtixml.cpp
CommitLineData
9c8046dd 1/////////////////////////////////////////////////////////////////////////////
8e3f3880 2// Name: src/common/xtixml.cpp
2abce515 3// Purpose: streaming runtime metadata information
9c8046dd 4// Author: Stefan Csomor
2abce515 5// Modified by:
9c8046dd
SC
6// Created: 27/07/03
7// RCS-ID: $Id$
8// Copyright: (c) 2003 Stefan Csomor
65571936 9// Licence: wxWindows licence
9c8046dd
SC
10/////////////////////////////////////////////////////////////////////////////
11
9c8046dd
SC
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
e765d7ee 16#pragma hdrstop
9c8046dd
SC
17#endif
18
8e3f3880
WS
19#if wxUSE_EXTENDED_RTTI
20
e765d7ee 21#include "wx/xtistrm.h"
d5da0ce7 22
9c8046dd 23#ifndef WX_PRECOMP
8e3f3880
WS
24 #include "wx/object.h"
25 #include "wx/hash.h"
d5da0ce7 26 #include "wx/event.h"
9c8046dd
SC
27#endif
28
29#include "wx/xml/xml.h"
30#include "wx/tokenzr.h"
9c8046dd 31#include "wx/txtstrm.h"
8347b97a 32#include "wx/xtistrm.h"
e765d7ee 33#include "wx/xtixml.h"
8347b97a 34
5e8b5272
SC
35// STL headers
36
9c8046dd
SC
37#include "wx/beforestd.h"
38#include <map>
39#include <vector>
40#include <string>
41#include "wx/afterstd.h"
42
5e8b5272
SC
43using namespace std;
44
9c8046dd 45
5e8b5272
SC
46
47
48// ----------------------------------------------------------------------------
49// wxObjectXmlWriter
50// ----------------------------------------------------------------------------
9c8046dd
SC
51
52// convenience functions
53
5e8b5272 54void wxXmlAddContentToNode( wxXmlNode* node, const wxString& data )
9c8046dd 55{
63691d4f 56 node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxT("value"), data ) );
9c8046dd
SC
57}
58
59wxString wxXmlGetContentFromNode( wxXmlNode *node )
60{
61 if ( node->GetChildren() )
5e8b5272 62 return node->GetChildren()->GetContent();
9c8046dd 63 else
5e8b5272 64 return wxEmptyString;
9c8046dd
SC
65}
66
5e8b5272 67struct wxObjectXmlWriter::wxObjectXmlWriterInternal
9c8046dd 68{
5e8b5272
SC
69 wxXmlNode *m_root;
70 wxXmlNode *m_current;
71 vector< wxXmlNode * > m_objectStack;
9c8046dd
SC
72
73 void Push( wxXmlNode *newCurrent )
74 {
5e8b5272
SC
75 m_objectStack.push_back( m_current );
76 m_current = newCurrent;
9c8046dd
SC
77 }
78
79 void Pop()
80 {
5e8b5272
SC
81 m_current = m_objectStack.back();
82 m_objectStack.pop_back();
9c8046dd 83 }
5e8b5272 84};
9c8046dd 85
5e8b5272 86wxObjectXmlWriter::wxObjectXmlWriter( wxXmlNode * rootnode )
9c8046dd 87{
5e8b5272
SC
88 m_data = new wxObjectXmlWriterInternal();
89 m_data->m_root = rootnode;
90 m_data->m_current = rootnode;
9c8046dd
SC
91}
92
5e8b5272 93wxObjectXmlWriter::~wxObjectXmlWriter()
9c8046dd 94{
5e8b5272 95 delete m_data;
9c8046dd
SC
96}
97
5e8b5272 98void wxObjectXmlWriter::DoBeginWriteTopLevelEntry( const wxString &name )
9c8046dd
SC
99{
100 wxXmlNode *pnode;
101 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("entry"));
5e8b5272
SC
102 pnode->AddProperty(wxString(wxT("name")), name);
103 m_data->m_current->AddChild(pnode);
104 m_data->Push( pnode );
9c8046dd
SC
105}
106
5e8b5272 107void wxObjectXmlWriter::DoEndWriteTopLevelEntry( const wxString &WXUNUSED(name) )
9c8046dd 108{
5e8b5272 109 m_data->Pop();
9c8046dd
SC
110}
111
5e8b5272
SC
112void wxObjectXmlWriter::DoBeginWriteObject(const wxObject *WXUNUSED(object),
113 const wxClassInfo *classInfo,
e765d7ee 114 int objectID, const wxStringToAnyHashMap &metadata )
9c8046dd
SC
115{
116 wxXmlNode *pnode;
117 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
5e8b5272
SC
118 pnode->AddProperty(wxT("class"), wxString(classInfo->GetClassName()));
119 pnode->AddProperty(wxT("id"), wxString::Format( wxT("%d"), objectID ) );
9c8046dd 120
e765d7ee
SC
121 wxStringToAnyHashMap::const_iterator it, en;
122 for( it = metadata.begin(), en = metadata.end(); it != en; ++it )
9c8046dd 123 {
e765d7ee 124 pnode->AddProperty( it->first, wxAnyGetAsString(it->second) );
9c8046dd 125 }
e765d7ee 126
5e8b5272
SC
127 m_data->m_current->AddChild(pnode);
128 m_data->Push( pnode );
9c8046dd
SC
129}
130
5e8b5272
SC
131void wxObjectXmlWriter::DoEndWriteObject(const wxObject *WXUNUSED(object),
132 const wxClassInfo *WXUNUSED(classInfo),
133 int WXUNUSED(objectID) )
9c8046dd 134{
5e8b5272 135 m_data->Pop();
9c8046dd
SC
136}
137
e765d7ee 138void wxObjectXmlWriter::DoWriteSimpleType( const wxAny &value )
9c8046dd 139{
e765d7ee 140 wxXmlAddContentToNode( m_data->m_current,wxAnyGetAsString(value) );
9c8046dd
SC
141}
142
5e8b5272 143void wxObjectXmlWriter::DoBeginWriteElement()
9c8046dd
SC
144{
145 wxXmlNode *pnode;
63691d4f 146 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("element") );
5e8b5272
SC
147 m_data->m_current->AddChild(pnode);
148 m_data->Push( pnode );
9c8046dd
SC
149}
150
5e8b5272 151void wxObjectXmlWriter::DoEndWriteElement()
9c8046dd 152{
5e8b5272 153 m_data->Pop();
9c8046dd
SC
154}
155
5e8b5272 156void wxObjectXmlWriter::DoBeginWriteProperty(const wxPropertyInfo *pi )
9c8046dd
SC
157{
158 wxXmlNode *pnode;
63691d4f 159 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("prop") );
5e8b5272
SC
160 pnode->AddProperty(wxT("name"), pi->GetName() );
161 m_data->m_current->AddChild(pnode);
162 m_data->Push( pnode );
9c8046dd
SC
163}
164
5e8b5272 165void wxObjectXmlWriter::DoEndWriteProperty(const wxPropertyInfo *WXUNUSED(propInfo) )
9c8046dd 166{
5e8b5272 167 m_data->Pop();
9c8046dd
SC
168}
169
5e8b5272 170void wxObjectXmlWriter::DoWriteRepeatedObject( int objectID )
9c8046dd
SC
171{
172 wxXmlNode *pnode;
173 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
5e8b5272
SC
174 pnode->AddProperty(wxString(wxT("href")), wxString::Format( wxT("%d"), objectID ) );
175 m_data->m_current->AddChild(pnode);
9c8046dd
SC
176}
177
5e8b5272 178void wxObjectXmlWriter::DoWriteNullObject()
9c8046dd
SC
179{
180 wxXmlNode *pnode;
181 pnode = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("object"));
5e8b5272 182 m_data->m_current->AddChild(pnode);
9c8046dd
SC
183}
184
5e8b5272
SC
185void wxObjectXmlWriter::DoWriteDelegate( const wxObject *WXUNUSED(object),
186 const wxClassInfo* WXUNUSED(classInfo),
187 const wxPropertyInfo *WXUNUSED(pi),
188 const wxObject *eventSink, int sinkObjectID,
189 const wxClassInfo* WXUNUSED(eventSinkClassInfo),
190 const wxHandlerInfo* handlerInfo )
9c8046dd
SC
191{
192 if ( eventSink != NULL && handlerInfo != NULL )
193 {
5e8b5272
SC
194 wxXmlAddContentToNode( m_data->m_current,
195 wxString::Format(wxT("%d.%s"), sinkObjectID, handlerInfo->GetName().c_str()) );
9c8046dd
SC
196 }
197}
198
9c8046dd
SC
199
200// ----------------------------------------------------------------------------
5e8b5272 201// wxObjectXmlReader
9c8046dd
SC
202// ----------------------------------------------------------------------------
203
2abce515 204/*
9c8046dd
SC
205Reading components has not to be extended for components
206as properties are always sought by typeinfo over all levels
207and create params are always toplevel class only
208*/
209
e765d7ee 210int wxObjectXmlReader::ReadComponent(wxXmlNode *node, wxObjectReaderCallback *callbacks)
9c8046dd 211{
5e8b5272 212 wxASSERT_MSG( callbacks, wxT("Does not support reading without a Depersistor") );
9c8046dd
SC
213 wxString className;
214 wxClassInfo *classInfo;
215
e765d7ee 216 wxAny *createParams;
5e8b5272
SC
217 int *createParamOids;
218 const wxClassInfo** createClassInfos;
9c8046dd
SC
219 wxXmlNode *children;
220 int objectID;
5e8b5272 221 wxString ObjectIdString;
9c8046dd
SC
222
223 children = node->GetChildren();
224 if (!children)
225 {
226 // check for a null object or href
e765d7ee 227 if (node->GetAttribute(wxT("href"), &ObjectIdString ) )
9c8046dd 228 {
5e8b5272 229 objectID = atoi( ObjectIdString.ToAscii() );
8f2b1cfd
SC
230 if ( HasObjectClassInfo( objectID ) )
231 {
5e8b5272 232 return objectID;
8f2b1cfd
SC
233 }
234 else
235 {
5e8b5272
SC
236 wxLogError( _("Forward hrefs are not supported") );
237 return wxInvalidObjectID;
8f2b1cfd 238 }
9c8046dd 239 }
e765d7ee 240 if ( !node->GetAttribute(wxT("id"), &ObjectIdString ) )
9c8046dd
SC
241 {
242 return wxNullObjectID;
243 }
244 }
e765d7ee 245 if (!node->GetAttribute(wxT("class"), &className))
9c8046dd
SC
246 {
247 // No class name. Eek. FIXME: error handling
248 return wxInvalidObjectID;
249 }
5e8b5272 250
9c8046dd 251 classInfo = wxClassInfo::FindClass(className);
8f2b1cfd
SC
252 if ( classInfo == NULL )
253 {
5e8b5272
SC
254 wxLogError( wxString::Format(_("unknown class %s"),className ) );
255 return wxInvalidObjectID;
8f2b1cfd
SC
256 }
257
258 if ( children != NULL && children->GetType() == wxXML_TEXT_NODE )
259 {
5e8b5272 260 wxLogError(_("objects cannot have XML Text Nodes") );
8f2b1cfd
SC
261 return wxInvalidObjectID;
262 }
e765d7ee 263 if (!node->GetAttribute(wxT("id"), &ObjectIdString))
9c8046dd 264 {
5e8b5272 265 wxLogError(_("Objects must have an id attribute") );
9c8046dd
SC
266 // No object id. Eek. FIXME: error handling
267 return wxInvalidObjectID;
268 }
5e8b5272
SC
269 objectID = atoi( ObjectIdString.ToAscii() );
270
9c8046dd 271 // is this object already has been streamed in, return it here
8f2b1cfd
SC
272 if ( HasObjectClassInfo( objectID ) )
273 {
5e8b5272
SC
274 wxLogError ( wxString::Format(_("Doubly used id : %d"), objectID ) );
275 return wxInvalidObjectID;
8f2b1cfd 276 }
9c8046dd
SC
277
278 // new object, start with allocation
279 // first make the object know to our internal registry
5e8b5272 280 SetObjectClassInfo( objectID, classInfo );
9c8046dd 281
e765d7ee
SC
282 wxStringToAnyHashMap metadata;
283 wxXmlProperty *xp = node->GetAttributes();
9c8046dd
SC
284 while ( xp )
285 {
5e8b5272
SC
286 if ( xp->GetName() != wxString(wxT("class")) &&
287 xp->GetName() != wxString(wxT("id")) )
9c8046dd 288 {
e765d7ee 289 metadata[xp->GetName()] = wxAny( xp->GetValue() );
9c8046dd 290 }
5e8b5272 291 xp = xp->GetNext();
9c8046dd 292 }
ed45345e
SC
293 if ( !classInfo->NeedsDirectConstruction() )
294 callbacks->AllocateObject(objectID, classInfo, metadata);
9c8046dd 295
2abce515 296 //
9c8046dd 297 // stream back the Create parameters first
e765d7ee 298 createParams = new wxAny[ classInfo->GetCreateParamCount() ];
5e8b5272
SC
299 createParamOids = new int[classInfo->GetCreateParamCount() ];
300 createClassInfos = new const wxClassInfo*[classInfo->GetCreateParamCount() ];
9c8046dd 301
63691d4f 302#if wxUSE_UNICODE
5e8b5272
SC
303 typedef map<wstring, wxXmlNode *> PropertyNodes;
304 typedef vector<wstring> PropertyNames;
63691d4f 305#else
5e8b5272
SC
306 typedef map<string, wxXmlNode *> PropertyNodes;
307 typedef vector<string> PropertyNames;
63691d4f 308#endif
5e8b5272
SC
309 PropertyNodes propertyNodes;
310 PropertyNames propertyNames;
9c8046dd
SC
311
312 while( children )
313 {
5e8b5272 314 wxString name;
e765d7ee 315 children->GetAttribute( wxT("name"), &name );
5e8b5272
SC
316 propertyNames.push_back( (const wxChar*)name.c_str() );
317 propertyNodes[(const wxChar*)name.c_str()] = children->GetChildren();
318 children = children->GetNext();
9c8046dd
SC
319 }
320
5e8b5272 321 for ( int i = 0; i <classInfo->GetCreateParamCount(); ++i )
9c8046dd 322 {
5e8b5272
SC
323 const wxChar* paramName = classInfo->GetCreateParamName(i);
324 PropertyNodes::iterator propiter = propertyNodes.find( paramName );
325 const wxPropertyInfo* pi = classInfo->FindPropertyInfo( paramName );
8f2b1cfd
SC
326 if ( pi == 0 )
327 {
758cdca1 328 wxLogError( wxString::Format(_("Unknown Property %s"),paramName) );
8f2b1cfd 329 }
9c8046dd
SC
330 // if we don't have the value of a create param set in the xml
331 // we use the default value
332 if ( propiter != propertyNodes.end() )
333 {
5e8b5272 334 wxXmlNode* prop = propiter->second;
9c8046dd
SC
335 if ( pi->GetTypeInfo()->IsObjectType() )
336 {
5e8b5272
SC
337 createParamOids[i] = ReadComponent( prop, callbacks );
338 createClassInfos[i] =
339 wx_dynamic_cast(const wxClassTypeInfo*, pi->GetTypeInfo())->GetClassInfo();
9c8046dd
SC
340 }
341 else
342 {
5e8b5272
SC
343 createParamOids[i] = wxInvalidObjectID;
344 createParams[i] = ReadValue( prop, pi->GetTypeInfo() );
9c8046dd
SC
345 if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
346 {
5e8b5272
SC
347 const wxEnumTypeInfo *eti =
348 wx_dynamic_cast(const wxEnumTypeInfo*, pi->GetTypeInfo() );
8f2b1cfd
SC
349 if ( eti )
350 {
5e8b5272
SC
351 long realval;
352 eti->ConvertToLong( createParams[i], realval );
e765d7ee 353 createParams[i] = wxAny( realval );
8f2b1cfd
SC
354 }
355 else
356 {
5e8b5272 357 wxLogError( _("Type must have enum - long conversion") );
8f2b1cfd 358 }
9c8046dd 359 }
5e8b5272 360 createClassInfos[i] = NULL;
9c8046dd
SC
361 }
362
5e8b5272 363 for ( size_t j = 0; j < propertyNames.size(); ++j )
9c8046dd
SC
364 {
365 if ( propertyNames[j] == paramName )
366 {
5e8b5272
SC
367 propertyNames[j] = wxEmptyString;
368 break;
9c8046dd
SC
369 }
370 }
371 }
372 else
373 {
ed45345e
SC
374 if ( pi->GetTypeInfo()->IsObjectType() )
375 {
5e8b5272
SC
376 createParamOids[i] = wxNullObjectID;
377 createClassInfos[i] =
378 wx_dynamic_cast(const wxClassTypeInfo*, pi->GetTypeInfo())->GetClassInfo();
ed45345e
SC
379 }
380 else
381 {
5e8b5272
SC
382 createParams[i] = pi->GetDefaultValue();
383 createParamOids[i] = wxInvalidObjectID;
ed45345e 384 }
9c8046dd
SC
385 }
386 }
387
388 // got the parameters. Call the Create method
ed45345e
SC
389 if ( classInfo->NeedsDirectConstruction() )
390 callbacks->ConstructObject(objectID, classInfo,
391 classInfo->GetCreateParamCount(),
392 createParams, createParamOids, createClassInfos, metadata );
393 else
394 callbacks->CreateObject(objectID, classInfo,
395 classInfo->GetCreateParamCount(),
396 createParams, createParamOids, createClassInfos, metadata );
9c8046dd 397
5e8b5272
SC
398 // now stream in the rest of the properties, in the sequence their
399 // properties were written in the xml
400 for ( size_t j = 0; j < propertyNames.size(); ++j )
9c8046dd 401 {
6636ef8d 402 if ( !propertyNames[j].empty() )
9c8046dd 403 {
5e8b5272 404 PropertyNodes::iterator propiter = propertyNodes.find( propertyNames[j] );
9c8046dd
SC
405 if ( propiter != propertyNodes.end() )
406 {
5e8b5272
SC
407 wxXmlNode* prop = propiter->second;
408 const wxPropertyInfo* pi =
409 classInfo->FindPropertyInfo( propertyNames[j].c_str() );
9c8046dd
SC
410 if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION )
411 {
5e8b5272
SC
412 const wxCollectionTypeInfo* collType =
413 wx_dynamic_cast( const wxCollectionTypeInfo*, pi->GetTypeInfo() );
414 const wxTypeInfo * elementType = collType->GetElementType();
9c8046dd
SC
415 while( prop )
416 {
8f2b1cfd
SC
417 if ( prop->GetName() != wxT("element") )
418 {
5e8b5272
SC
419 wxLogError( _("A non empty collection must consist of 'element' nodes" ) );
420 break;
8f2b1cfd 421 }
5e8b5272
SC
422
423 wxXmlNode* elementContent = prop->GetChildren();
9c8046dd
SC
424 if ( elementContent )
425 {
426 // we skip empty elements
427 if ( elementType->IsObjectType() )
428 {
5e8b5272 429 int valueId = ReadComponent( elementContent, callbacks );
9c8046dd
SC
430 if ( valueId != wxInvalidObjectID )
431 {
432 if ( pi->GetAccessor()->HasAdder() )
5e8b5272 433 callbacks->AddToPropertyCollectionAsObject( objectID, classInfo, pi, valueId );
2abce515 434 // TODO for collections we must have a notation on taking over ownership or not
9c8046dd 435 if ( elementType->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
5e8b5272 436 callbacks->DestroyObject( valueId, GetObjectClassInfo( valueId ) );
9c8046dd
SC
437 }
438 }
439 else
440 {
e765d7ee 441 wxAny elementValue = ReadValue( elementContent, elementType );
9c8046dd 442 if ( pi->GetAccessor()->HasAdder() )
5e8b5272 443 callbacks->AddToPropertyCollection( objectID, classInfo,pi, elementValue );
9c8046dd
SC
444 }
445 }
5e8b5272 446 prop = prop->GetNext();
9c8046dd
SC
447 }
448 }
449 else if ( pi->GetTypeInfo()->IsObjectType() )
450 {
ed45345e
SC
451 // and object can either be streamed out a string or as an object
452 // in case we have no node, then the object's streaming out has been vetoed
453 if ( prop )
9c8046dd 454 {
ed45345e
SC
455 if ( prop->GetName() == wxT("object") )
456 {
5e8b5272 457 int valueId = ReadComponent( prop, callbacks );
ed45345e
SC
458 if ( valueId != wxInvalidObjectID )
459 {
5e8b5272 460 callbacks->SetPropertyAsObject( objectID, classInfo, pi, valueId );
ed45345e 461 if ( pi->GetTypeInfo()->GetKind() == wxT_OBJECT && valueId != wxNullObjectID )
5e8b5272 462 callbacks->DestroyObject( valueId, GetObjectClassInfo( valueId ) );
ed45345e
SC
463 }
464 }
465 else
466 {
5e8b5272 467 wxASSERT( pi->GetTypeInfo()->HasStringConverters() );
e765d7ee 468 wxAny nodeval = ReadValue( prop, pi->GetTypeInfo() );
5e8b5272 469 callbacks->SetProperty( objectID, classInfo,pi, nodeval );
ed45345e 470 }
9c8046dd
SC
471 }
472 }
473 else if ( pi->GetTypeInfo()->IsDelegateType() )
474 {
475 if ( prop )
476 {
5e8b5272
SC
477 wxString resstring = prop->GetContent();
478 wxInt32 pos = resstring.Find('.');
8f2b1cfd
SC
479 if ( pos != wxNOT_FOUND )
480 {
5e8b5272
SC
481 int sinkOid = atol(resstring.Left(pos).ToAscii());
482 wxString handlerName = resstring.Mid(pos+1);
483 wxClassInfo* sinkClassInfo = GetObjectClassInfo( sinkOid );
9c8046dd 484
5e8b5272 485 callbacks->SetConnect( objectID, classInfo, pi, sinkClassInfo,
44a00712 486 sinkClassInfo->FindHandlerInfo(handlerName.c_str()), sinkOid );
8f2b1cfd
SC
487 }
488 else
489 {
5e8b5272 490 wxLogError( _("incorrect event handler string, missing dot") );
8f2b1cfd 491 }
9c8046dd
SC
492 }
493
494 }
495 else
496 {
e765d7ee 497 wxAny nodeval = ReadValue( prop, pi->GetTypeInfo() );
499a9a62
SC
498 if( pi->GetFlags() & wxPROP_ENUM_STORE_LONG )
499 {
5e8b5272
SC
500 const wxEnumTypeInfo *eti =
501 wx_dynamic_cast(const wxEnumTypeInfo*, pi->GetTypeInfo() );
8f2b1cfd
SC
502 if ( eti )
503 {
5e8b5272
SC
504 long realval;
505 eti->ConvertToLong( nodeval, realval );
e765d7ee 506 nodeval = wxAny( realval );
8f2b1cfd
SC
507 }
508 else
509 {
5e8b5272 510 wxLogError( _("Type must have enum - long conversion") );
8f2b1cfd 511 }
499a9a62 512 }
5e8b5272 513 callbacks->SetProperty( objectID, classInfo,pi, nodeval );
9c8046dd
SC
514 }
515 }
516 }
517 }
518
5e8b5272
SC
519 delete[] createParams;
520 delete[] createParamOids;
521 delete[] createClassInfos;
9c8046dd
SC
522
523 return objectID;
524}
525
e765d7ee 526wxAny wxObjectXmlReader::ReadValue(wxXmlNode *node,
9c8046dd
SC
527 const wxTypeInfo *type )
528{
5e8b5272 529 wxString content;
9c8046dd 530 if ( node )
5e8b5272 531 content = node->GetContent();
e765d7ee 532 wxAny result;
5e8b5272
SC
533 type->ConvertFromString( content, result );
534 return result;
9c8046dd
SC
535}
536
e765d7ee 537int wxObjectXmlReader::ReadObject( const wxString &name, wxObjectReaderCallback *callbacks)
9c8046dd 538{
5e8b5272 539 wxXmlNode *iter = m_parent->GetChildren();
9c8046dd
SC
540 while ( iter )
541 {
5e8b5272 542 wxString entryName;
e765d7ee 543 if ( iter->GetAttribute(wxT("name"), &entryName) )
9c8046dd
SC
544 {
545 if ( entryName == name )
5e8b5272 546 return ReadComponent( iter->GetChildren(), callbacks );
9c8046dd 547 }
5e8b5272 548 iter = iter->GetNext();
9c8046dd 549 }
5e8b5272 550 return wxInvalidObjectID;
9c8046dd
SC
551}
552
8e3f3880 553#endif // wxUSE_EXTENDED_RTTI