-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCppReflect.cpp
145 lines (119 loc) · 4.01 KB
/
CppReflect.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include "CppReflect.h"
#include "pugixml\pugixml.hpp" //pugi::xml_node
using namespace pugi;
//
// Serializes class instance to xml node.
//
void DataToNode( xml_node& _node, void* pclass, CppTypeInfo& type )
{
USES_CONVERSION;
xml_node& node = _node.append_child( CA2W( type.name ) );
for each (FieldInfo fi in type.fields)
{
void* p = ((char*)pclass) + fi.offset;
CppTypeInfo* arrayType = nullptr;
if( !fi.fieldType->GetArrayElementType( arrayType ) )
{
// Simple type, append as attribute.
CStringW s = fi.fieldType->ToString( p );
if( s.GetLength() ) // Don't serialize empty values.
node.append_attribute( CA2W( fi.name ) ) = s;
continue;
}
if( !arrayType )
continue;
xml_node& fieldNode = node.append_child( CA2W( fi.name ) );
size_t size = fi.fieldType->ArraySize( p );
for( size_t i = 0; i < size; i++ )
{
void* pstr2 = fi.fieldType->ArrayElement( p, i );
DataToNode( fieldNode, pstr2, *arrayType );
}
} //for each
} //DataToNode
// Helper class.
struct xml_string_writer : xml_writer
{
CStringA result;
virtual void write( const void* data, size_t size )
{
result += CStringA( (const char*)data, (int)size );
}
};
CStringA ToXML_UTF8( void* pclass, CppTypeInfo& type )
{
xml_document doc;
xml_node decl = doc.prepend_child( pugi::node_declaration );
decl.append_attribute( _T( "version" ) ) = _T( "1.0" );
decl.append_attribute( _T( "encoding" ) ) = _T( "utf-8" );
DataToNode( doc, pclass, type );
xml_string_writer writer;
doc.save( writer );
return writer.result;
}
CStringW ToXML( void* pclass, CppTypeInfo& type )
{
xml_document doc;
xml_node decl = doc.prepend_child( pugi::node_declaration );
decl.append_attribute( _T( "version" ) ) = _T( "1.0" );
decl.append_attribute( _T( "encoding" ) ) = _T( "utf-8" );
DataToNode( doc, pclass, type );
xml_string_writer writer;
doc.save( writer );
return CStringW(CA2T(writer.result, CP_UTF8));
}
//
// Deserializes xml to class structure, returns true if succeeded, false if fails.
// error holds error information if any.
//
bool NodeToData( xml_node& node, void* pclass, CppTypeInfo& type, CStringW& error )
{
CStringA name = node.name();
if( type.name != name )
{
error.AppendFormat( _T( "Expected xml tag '%S', but found '%S' instead" ), type.name.GetBuffer(), name.GetBuffer() );
return false;
}
for each (FieldInfo fi in type.fields)
{
void* p = ((char*)pclass) + fi.offset;
CppTypeInfo* arrayType = nullptr;
if( !fi.fieldType->GetArrayElementType( arrayType ) )
{
// Simple type, query from attribute value.
xml_attribute& attr = node.attribute( CA2W( fi.name ) );
fi.fieldType->FromString( p, attr.value() );
continue;
}
if( !arrayType )
continue;
xml_node& fieldNode = node.child( CA2W( fi.name ) );
if( fieldNode.empty() )
continue;
int size = 0;
for( auto it = fieldNode.children().begin(); it != fieldNode.children().end(); it++ )
size++;
fi.fieldType->SetArraySize( p, size );
int i = 0;
for( auto it = fieldNode.children().begin(); it != fieldNode.children().end(); it++ )
{
void* pstr2 = fi.fieldType->ArrayElement( p, i );
if( !NodeToData( *it, pstr2, *arrayType, error ) )
return false;
i++;
}
} //for each
return true;
} //NodeToData
bool FromXml( void* pclass, CppTypeInfo& type, const wchar_t* xml, CStringW& error )
{
xml_document doc2;
xml_parse_result res = doc2.load_string( xml );
if( !res )
{
error = L"Failed to load xml: ";
error += res.description();
return false;
}
return NodeToData( doc2.first_child(), pclass, type, error );
}