Logo ROOT   6.16/01
Reference Guide
TSchemaRuleSet.cxx
Go to the documentation of this file.
1// @(#)root/core:$Id$
2// author: Lukasz Janyst <ljanyst@cern.ch>
3
4#include "TSchemaRuleSet.h"
5#include "TSchemaRule.h"
6#include "TObjArray.h"
7#include "TObjString.h"
8#include "TClass.h"
9#include "TROOT.h"
10#include "Riostream.h"
11
14#include "TVirtualMutex.h"
15#include "TInterpreter.h" // For gInterpreterMutex
16#include "TStreamerElement.h"
17#include "TClassEdit.h"
18
20
21using namespace ROOT;
22using namespace ROOT::Detail;
23
24////////////////////////////////////////////////////////////////////////////////
25/// Default constructor.
26
27TSchemaRuleSet::TSchemaRuleSet(): fPersistentRules( 0 ), fRemainingRules( 0 ),
28 fAllRules( 0 ), fVersion(-3), fCheckSum( 0 )
29{
32 fAllRules = new TObjArray();
34}
35
36////////////////////////////////////////////////////////////////////////////////
37/// Destructor.
38
40{
41 delete fPersistentRules;
42 delete fRemainingRules;
43 delete fAllRules;
44}
45
46////////////////////////////////////////////////////////////////////////////////
47/// The ls function lists the contents of a class on stdout. Ls output
48/// is typically much less verbose then Dump().
49
51{
53 std::cout << "TSchemaRuleSet for " << fClassName << ":\n";
55 TObject *object = 0;
57 while ((object = next())) {
58 object->ls(fClassName);
59 }
61}
62
63////////////////////////////////////////////////////////////////////////////////
64
65Bool_t TSchemaRuleSet::AddRules( TSchemaRuleSet* /* rules */, EConsistencyCheck /* checkConsistency */, TString * /* errmsg */ )
66{
67 return kFALSE;
68}
69
70////////////////////////////////////////////////////////////////////////////////
71/// The consistency check always fails if the TClass object was not set!
72/// if checkConsistency is:
73/// kNoCheck: no check is done, register the rule as is
74/// kCheckConflict: check only for conflicting rules
75/// kCheckAll: check for conflict and check for rule about members that are not in the current class layout.
76/// return kTRUE if the layout is accepted, in which case we take ownership of
77/// the rule object.
78/// return kFALSE if the rule failed one of the test, the rule now needs to be deleted by the caller.
79
80Bool_t TSchemaRuleSet::AddRule( TSchemaRule* rule, EConsistencyCheck checkConsistency, TString *errmsg )
81{
82 //---------------------------------------------------------------------------
83 // Cannot verify the consistency if the TClass object is not present
84 /////////////////////////////////////////////////////////////////////////////
85
86 if( (checkConsistency != kNoCheck) && !fClass )
87 return kFALSE;
88
89 if( !rule->IsValid() )
90 return kFALSE;
91
92 //---------------------------------------------------------------------------
93 // If we don't check the consistency then we should just add the object
94 /////////////////////////////////////////////////////////////////////////////
95
96 if( checkConsistency == kNoCheck ) {
97 if( rule->GetEmbed() )
98 fPersistentRules->Add( rule );
99 else
100 fRemainingRules->Add( rule );
101 fAllRules->Add( rule );
102 return kTRUE;
103 }
104
105 //---------------------------------------------------------------------------
106 // Check if all of the target data members specified in the rule are
107 // present int the target class
108 /////////////////////////////////////////////////////////////////////////////
109
110 // Check only if we have some information about the class, otherwise we have
111 // nothing to check against
112 bool streamerInfosTest;
113 {
115 streamerInfosTest = (fClass->GetStreamerInfos()==0 || fClass->GetStreamerInfos()->GetEntries()==0);
116 }
117 if( rule->GetTarget() && !(fClass->TestBit(TClass::kIsEmulation) && streamerInfosTest) ) {
118 TObjArrayIter titer( rule->GetTarget() );
119 TObject* obj;
120 while( (obj = titer.Next()) ) {
121 TObjString* str = (TObjString*)obj;
122 if( !fClass->GetDataMember( str->GetString() ) && !fClass->GetBaseClass( str->GetString() ) ) {
123 if (checkConsistency == kCheckAll) {
124 if (errmsg) {
125 errmsg->Form("the target member (%s) is unknown",str->GetString().Data());
126 }
127 return kFALSE;
128 } else {
129 // We ignore the rules that do not apply ...
130 delete rule;
131 return kTRUE;
132 }
133 }
134 }
135 }
136
137 //---------------------------------------------------------------------------
138 // Check if there is a rule conflicting with this one
139 /////////////////////////////////////////////////////////////////////////////
140
141 std::vector<const TSchemaRule*> rules = FindRules( rule->GetSourceClass() );
142 //TObjArrayIter it( rules );
143 //TSchemaRule *r;
144
145 for(auto r : rules) { // while( (obj = it.Next()) ) {
146 if( rule->Conflicts( r ) ) {
147 //delete rules;
148 if ( *r == *rule) {
149 // The rules are duplicate from each other,
150 // just ignore the new ones.
151 if (errmsg) {
152 *errmsg = "it conflicts with one of the other rules";
153 }
154 delete rule;
155 return kTRUE;
156 }
157 if (errmsg) {
158 *errmsg = "The existing rule is:\n ";
159 r->AsString(*errmsg,"s");
160 *errmsg += "\nand the ignored rule is:\n ";
161 rule->AsString(*errmsg);
162 *errmsg += ".\n";
163 }
164 return kFALSE;
165 }
166 }
167
168 //---------------------------------------------------------------------------
169 // No conflicts - insert the rules
170 /////////////////////////////////////////////////////////////////////////////
171
172 if( rule->GetEmbed() )
173 fPersistentRules->Add( rule );
174 else
175 fRemainingRules->Add( rule );
176 fAllRules->Add( rule );
177
178 return kTRUE;
179}
180
181////////////////////////////////////////////////////////////////////////////////
182/// Fill the string 'out' with the string representation of the rule.
183
184void TSchemaRuleSet::AsString(TString &out) const
185{
187 TSchemaRule *rule;
188 while( (rule = (TSchemaRule*)it.Next()) ) {
189 rule->AsString(out);
190 out += "\n";
191 }
192}
193
194////////////////////////////////////////////////////////////////////////////////
195/// Return True if we have any rule whose source class is 'source'.
196
197Bool_t TSchemaRuleSet::HasRuleWithSourceClass( const TString &source ) const
198{
200 TObject *obj;
201 while( (obj = it.Next()) ) {
202 TSchemaRule* rule = (TSchemaRule*)obj;
203 if( rule->GetSourceClass() == source )
204 return kTRUE;
205 }
206 // There was no explicit rule, let's see we have implicit rules.
207 if (fClass->GetCollectionProxy()) {
208 if (fClass->GetCollectionProxy()->GetValueClass() == 0) {
209 // We have a numeric collection, let see if the target is
210 // also a numeric collection.
211 TClass *src = TClass::GetClass(source);
212 if (src && src->GetCollectionProxy() &&
215 if (proxy->GetValueClass() == 0) {
216 return kTRUE;
217 }
218 }
219 } else {
220 TClass *vTargetClass = fClass->GetCollectionProxy()->GetValueClass();
221 TClass *src = TClass::GetClass(source);
222 if (vTargetClass->GetSchemaRules()) {
223 if (src && src->GetCollectionProxy() &&
225 TClass *vSourceClass = src->GetCollectionProxy()->GetValueClass();
226 if (vSourceClass) {
227 return vTargetClass->GetSchemaRules()->HasRuleWithSourceClass( vSourceClass->GetName() );
228 }
229 }
230 }
231 }
232 } else if (!strncmp(fClass->GetName(),"std::pair<",10) || !strncmp(fClass->GetName(),"pair<",5)) {
233 if (!strncmp(source,"std::pair<",10) || !strncmp(source,"pair<",5)) {
234 // std::pair can be converted into each other if both its parameter can be converted into
235 // each other.
236 TClass *src = TClass::GetClass(source);
237 if (!src) {
238 Error("HasRuleWithSourceClass","Can not find the TClass for %s when matching with %s\n",source.Data(),fClass->GetName());
239 return kFALSE;
240 }
241 TVirtualStreamerInfo *sourceInfo = src->GetStreamerInfo();
243 if (!sourceInfo) {
244 Error("HasRuleWithSourceClass","Can not find the StreamerInfo for %s when matching with %s\n",source.Data(),fClass->GetName());
245 return kFALSE;
246 }
247 if (!targetInfo) {
248 Error("HasRuleWithSourceClass","Can not find the StreamerInfo for target class %s\n",fClass->GetName());
249 return kFALSE;
250 }
251 for(int i = 0 ; i<2 ; ++i) {
252 TStreamerElement *sourceElement = (TStreamerElement*)sourceInfo->GetElements()->At(i);
253 TStreamerElement *targetElement = (TStreamerElement*)targetInfo->GetElements()->At(i);
254 if (sourceElement->GetClass()) {
255 if (!targetElement->GetClass()) {
256 return kFALSE;
257 }
258 if (sourceElement->GetClass() == targetElement->GetClass()) {
259 continue;
260 }
261 TSchemaRuleSet *rules = sourceElement->GetClass()->GetSchemaRules();
262 if (!rules || !rules->HasRuleWithSourceClass( targetElement->GetClass()->GetName() ) ) {
263 return kFALSE;
264 }
265 } else if (targetElement->GetClass()) {
266 return kFALSE;
267 } else {
268 // both side are numeric element we can deal with it.
269 }
270 }
271 // Both side are pairs and have convertible types, let records this as a renaming rule
272 ROOT::TSchemaRule *ruleobj = new ROOT::TSchemaRule();
273 ruleobj->SetSourceClass(source);
274 ruleobj->SetTargetClass(fClass->GetName());
275 ruleobj->SetVersion("[1-]");
276 const_cast<TSchemaRuleSet*>(this)->AddRule(ruleobj);
277 return kTRUE;
278 }
279 }
280 return kFALSE;
281}
282
283////////////////////////////////////////////////////////////////////////////////
284/// Return all the rules that are about the given 'source' class.
285/// User has to delete the returned array
286
287const TSchemaRuleSet::TMatches TSchemaRuleSet::FindRules( const TString &source ) const
288{
289 TObject* obj;
291 TMatches arr;
292 // arr->SetOwner( kFALSE );
293
294 while( (obj = it.Next()) ) {
295 TSchemaRule* rule = (TSchemaRule*)obj;
296 if( rule->GetSourceClass() == source )
297 arr.push_back( rule );
298 }
299
300#if 0
301 // Le't's see we have implicit rules.
302 if (fClass->GetCollectionProxy()) {
306 // We have a numeric collection, let see if the target is
307 // also a numeric collection (humm just a vector for now)
308 TClass *src = TClass::GetClass(source);
309 if (src && src->GetCollectionProxy()) {
311 if (proxy->GetValueClass() == 0) {
312 // ... would need to check if we already have
313 // the rule (or any rule?)
314 }
315 }
316 }
317 }
318#endif
319 return arr;
320}
321
322////////////////////////////////////////////////////////////////////////////////
323/// Return all the rules that applies to the specified version of the given 'source' class.
324/// User has to delete the returned array
325
326const TSchemaRuleSet::TMatches TSchemaRuleSet::FindRules( const TString &source, Int_t version ) const
327{
328 TObject* obj;
330 TMatches arr;
331 // arr->SetOwner( kFALSE );
332
333 while( (obj = it.Next()) ) {
334 TSchemaRule* rule = (TSchemaRule*)obj;
335 if( rule->GetSourceClass() == source && rule->TestVersion( version ) )
336 arr.push_back( rule );
337 }
338
339 return arr;
340}
341
342////////////////////////////////////////////////////////////////////////////////
343/// Return all the rules that applies to the specified checksum of the given 'source' class.
344/// User has to delete the returned array
345
346const TSchemaRuleSet::TMatches TSchemaRuleSet::FindRules( const TString &source, UInt_t checksum ) const
347{
348 TObject* obj;
350 TMatches arr;
351 // arr->SetOwner( kFALSE );
352
353 while( (obj = it.Next()) ) {
354 TSchemaRule* rule = (TSchemaRule*)obj;
355 if( rule->GetSourceClass() == source && rule->TestChecksum( checksum ) )
356 arr.push_back( rule );
357 }
358
359 return arr;
360}
361
362////////////////////////////////////////////////////////////////////////////////
363/// Return all the rules that applies to the specified version OR checksum of the given 'source' class.
364/// User has to delete the returned array
365
366const TSchemaRuleSet::TMatches TSchemaRuleSet::FindRules( const TString &source, Int_t version, UInt_t checksum ) const
367{
368 TObject* obj;
370 TMatches arr;
371 // arr->SetOwner( kFALSE );
372
373 while( (obj = it.Next()) ) {
374 TSchemaRule* rule = (TSchemaRule*)obj;
375 if( rule->GetSourceClass() == source && ( rule->TestVersion( version ) || rule->TestChecksum( checksum ) ) )
376 arr.push_back( rule );
377 }
378
379 return arr;
380}
381
382////////////////////////////////////////////////////////////////////////////////
383
385{
386 return fClass;
387}
388
389////////////////////////////////////////////////////////////////////////////////
390
392{
393 if (fCheckSum == 0 && fClass) {
394 const_cast<TSchemaRuleSet*>(this)->fCheckSum = fClass->GetCheckSum();
395 }
396 return fCheckSum;
397}
398
399////////////////////////////////////////////////////////////////////////////////
400
402{
403 return fClassName;
404}
405
406////////////////////////////////////////////////////////////////////////////////
407
409{
410 return fVersion;
411}
412
413////////////////////////////////////////////////////////////////////////////////
414
416{
417 return fAllRules;
418}
419
420////////////////////////////////////////////////////////////////////////////////
421
423{
424 return fPersistentRules;
425}
426
427////////////////////////////////////////////////////////////////////////////////
428/// Remove given rule from the set - the rule is not being deleted!
429
431{
432 fPersistentRules->Remove( rule );
433 fRemainingRules->Remove( rule );
434 fAllRules->Remove( rule );
435}
436
437////////////////////////////////////////////////////////////////////////////////
438/// remove given array of rules from the set - the rules are not being deleted!
439
441{
442 TObject* obj;
443 TObjArrayIter it( rules );
444
445 while( (obj = it.Next()) ) {
446 fPersistentRules->Remove( obj );
447 fRemainingRules->Remove( obj );
448 fAllRules->Remove( obj );
449 }
450}
451
452////////////////////////////////////////////////////////////////////////////////
453/// Set the TClass associated with this rule set.
454
456{
457 fClass = cls;
458 fClassName = cls->GetName();
459 fVersion = cls->GetClassVersion();
460}
461
462
463////////////////////////////////////////////////////////////////////////////////
464/// Return the rule that has 'name' as a source.
465
467{
468 for( auto rule : *this ) {
469 if( rule->HasSource( name ) ) return rule;
470 }
471 return 0;
472}
473
474////////////////////////////////////////////////////////////////////////////////
475/// Return the rule that has 'name' as a target.
476
478{
479 for( auto rule : *this ) {
480 if( rule->HasTarget( name ) ) return rule;
481 }
482 return 0;
483}
484
485////////////////////////////////////////////////////////////////////////////////
486/// Return true if the set of rules has at least one rule that has the data
487/// member named 'name' as a source.
488/// If needingAlloc is true, only the rule that requires the data member to
489/// be cached will be taken in consideration.
490
492{
493 for( auto rule : *this ) {
494 if( rule->HasSource( name ) ) {
495 if (needingAlloc) {
496 const TObjArray *targets = rule->GetTarget();
497 if (targets && (targets->GetEntries() > 1 || targets->GetEntries()==0) ) {
498 return kTRUE;
499 }
500 if (targets && name != targets->UncheckedAt(0)->GetName() ) {
501 return kTRUE;
502 }
503 // If the rule has the same source and target and does not
504 // have any actions, then it does not need allocation.
505 if (rule->GetReadFunctionPointer() || rule->GetReadRawFunctionPointer()) {
506 return kTRUE;
507 }
508 } else {
509 return kTRUE;
510 }
511 }
512 }
513 return kFALSE;
514}
515
516////////////////////////////////////////////////////////////////////////////////
517/// Return true if the set of rules has at least one rule that has the data
518/// member named 'name' as a target.
519/// If willset is true, only the rule that will set the value of the data member.
520
522{
523 for(auto rule : *this) {
524 if( rule->HasTarget( name ) ) {
525 if (willset) {
526 const TObjArray *targets = rule->GetTarget();
527 if (targets && (targets->GetEntries() > 1 || targets->GetEntries()==0) ) {
528 return kTRUE;
529 }
530 const TObjArray *sources = rule->GetSource();
531 if (sources && (sources->GetEntries() > 1 || sources->GetEntries()==0) ) {
532 return kTRUE;
533 }
534 if (sources && name != sources->UncheckedAt(0)->GetName() ) {
535 return kTRUE;
536 }
537 // If the rule has the same source and target and does not
538 // have any actions, then it will not directly set the value.
539 if (rule->GetReadFunctionPointer() || rule->GetReadRawFunctionPointer()) {
540 return kTRUE;
541 }
542 } else {
543 return kTRUE;
544 }
545 }
546 }
547 return kFALSE;
548}
549
550////////////////////////////////////////////////////////////////////////////////
551/// Stream an object of class ROOT::TSchemaRuleSet.
552
553void TSchemaRuleSet::Streamer(TBuffer &R__b)
554{
555 if (R__b.IsReading()) {
557 fAllRules->Clear();
559 } else {
562 }
563}
564
void Class()
Definition: Class.C:29
ROOT::R::TRInterface & r
Definition: Object.C:4
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
const char Option_t
Definition: RtypesCore.h:62
#define ClassImp(name)
Definition: Rtypes.h:363
R__EXTERN TVirtualMutex * gInterpreterMutex
Definition: TInterpreter.h:40
#define R__LOCKGUARD(mutex)
const TSchemaRule * GetRuleWithSource(const TString &name) const
Return the rule that has 'name' as a source.
Bool_t HasRuleWithSource(const TString &name, Bool_t needingAlloc) const
Return true if the set of rules has at least one rule that has the data member named 'name' as a sour...
Bool_t HasRuleWithTarget(const TString &name, Bool_t willset) const
Return true if the set of rules has at least one rule that has the data member named 'name' as a targ...
const TSchemaRule * GetRuleWithTarget(const TString &name) const
Return the rule that has 'name' as a target.
Bool_t AddRules(TSchemaRuleSet *rules, EConsistencyCheck checkConsistency=kCheckAll, TString *errmsg=0)
TClassRef fClass
Array of all rules.
TString fClassName
Target class pointer (for consistency checking)
void RemoveRule(TSchemaRule *rule)
Remove given rule from the set - the rule is not being deleted!
const TMatches FindRules(const TString &source) const
Return all the rules that are about the given 'source' class.
const TObjArray * GetPersistentRules() const
void AsString(TString &out) const
Fill the string 'out' with the string representation of the rule.
void ls(Option_t *option="") const
The ls function lists the contents of a class on stdout.
Bool_t AddRule(TSchemaRule *rule, EConsistencyCheck checkConsistency=kCheckAll, TString *errmsg=0)
The consistency check always fails if the TClass object was not set! if checkConsistency is: kNoCheck...
TObjArray * fAllRules
Array of non-persisten rules - just for cleanup purposes - owns the elements.
void SetClass(TClass *cls)
Set the TClass associated with this rule set.
void RemoveRules(TObjArray *rules)
remove given array of rules from the set - the rules are not being deleted!
const TObjArray * GetRules() const
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is 'source'.
virtual ~TSchemaRuleSet()
Destructor.
void AsString(TString &out, const char *options="") const
Add to the string 'out' the string representation of the rule.
Bool_t TestVersion(Int_t version) const
Check if given version number is defined in this rule.
const TObjArray * GetTarget() const
Get the target data members of this rule (i.e. the in memory data member).
Bool_t Conflicts(const TSchemaRule *rule) const
Check if this rule conflicts with the given one.
void SetTargetClass(const TString &classname)
Set the target class of this rule (i.e. the in memory class).
const char * GetSourceClass() const
Get the source class of this rule (i.e. the onfile class).
Bool_t TestChecksum(UInt_t checksum) const
Check if given checksum is defined in this rule.
Bool_t SetVersion(const TString &version)
Set the version string - returns kFALSE if the format is incorrect.
Bool_t IsValid() const
Return kTRUE if this rule is valid.
Bool_t GetEmbed() const
Return true if this rule should be saved in the ROOT File.
void SetSourceClass(const TString &classname)
Set the source class of this rule (i.e. the onfile class).
Buffer base class used for serializing objects.
Definition: TBuffer.h:40
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=0)=0
Bool_t IsReading() const
Definition: TBuffer.h:83
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
UInt_t GetCheckSum(ECheckSum code=kCurrentCheckSum) const
Call GetCheckSum with validity check.
Definition: TClass.cxx:6217
TDataMember * GetDataMember(const char *datamember) const
Return pointer to datamember object with name "datamember".
Definition: TClass.cxx:3278
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition: TClass.cxx:4452
TClass * GetBaseClass(const char *classname)
Return pointer to the base class "classname".
Definition: TClass.cxx:2572
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition: TClass.cxx:1841
const TObjArray * GetStreamerInfos() const
Definition: TClass.h:462
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2814
Version_t GetClassVersion() const
Definition: TClass.h:391
@ kIsEmulation
Definition: TClass.h:95
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2885
virtual void AddAll(const TCollection *col)
Add all objects from collection col to this collection.
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
Iterator of object array.
Definition: TObjArray.h:125
TObject * Next()
Return next object in array. Returns 0 when no more objects in array.
Definition: TObjArray.cxx:915
An array of TObjects.
Definition: TObjArray.h:37
void Add(TObject *obj)
Definition: TObjArray.h:73
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:522
virtual void Clear(Option_t *option="")
Remove all objects from the array.
Definition: TObjArray.cxx:320
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:89
virtual TObject * Remove(TObject *obj)
Remove object from array.
Definition: TObjArray.cxx:703
TObject * At(Int_t idx) const
Definition: TObjArray.h:165
Collectable string class.
Definition: TObjString.h:28
const TString & GetString() const
Definition: TObjString.h:47
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:357
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
static Int_t IncreaseDirLevel()
Increase the indentation level for ls().
Definition: TROOT.cxx:2843
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition: TROOT.cxx:2851
static Int_t DecreaseDirLevel()
Decrease the indentation level for ls().
Definition: TROOT.cxx:2748
TClass * GetClass() const
virtual Int_t GetProperties() const
virtual TClass * GetValueClass() const =0
virtual Int_t GetCollectionType() const =0
virtual Bool_t HasPointers() const =0
Abstract Interface class describing Streamer information for one class.
virtual TObjArray * GetElements() const =0
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21