├── Data
├── .gitkeep
├── diagram
│ ├── Cone.png
│ ├── Kitti.png
│ └── Building.png
├── option.xml
├── option_Cone.xml
├── option_KITTI.xml
├── option_Building.xml
└── option2.xml
├── 3rdparty
└── .gitkeep
├── library
└── FasterStereoCuda
│ ├── dll
│ ├── .gitkeep
│ ├── StereoCuda.dll
│ ├── cudart64_110.dll
│ └── FasterStereoCuda.dll
│ ├── lib
│ ├── .gitkeep
│ └── FasterStereoCuda.lib
│ └── include
│ ├── .gitkeep
│ └── FasterStereoCuda.h
├── x64
├── Debug
│ └── fasterstereocuda.a
└── Release
│ └── fasterstereocuda.a
├── FasterStereoConsole
├── resource.h
├── option_manager.h
├── fasterstereocuda.a
├── option_manager.cpp
├── FasterStereoConsole.aps
├── FasterStereoConsole.cpp
├── FasterStereoConsole.rc
├── FasterStereoConsole.vcxproj.administrator.nvuser
├── FasterStereoConsole.vcxproj.lys.nvuser
├── FasterStereoConsole.vcxproj.user
├── FasterStereoConsole.vcxproj.filters
├── FasterStereoConsole.vcxproj
├── tinyxml2.h
└── tinyxml2.cpp
├── FasterStereoCuda-v19.sln
└── README.md
/Data/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/3rdparty/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/library/FasterStereoCuda/dll/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/library/FasterStereoCuda/lib/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/library/FasterStereoCuda/include/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Data/diagram/Cone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/Data/diagram/Cone.png
--------------------------------------------------------------------------------
/Data/diagram/Kitti.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/Data/diagram/Kitti.png
--------------------------------------------------------------------------------
/Data/diagram/Building.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/Data/diagram/Building.png
--------------------------------------------------------------------------------
/x64/Debug/fasterstereocuda.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/x64/Debug/fasterstereocuda.a
--------------------------------------------------------------------------------
/FasterStereoConsole/resource.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/FasterStereoConsole/resource.h
--------------------------------------------------------------------------------
/x64/Release/fasterstereocuda.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/x64/Release/fasterstereocuda.a
--------------------------------------------------------------------------------
/FasterStereoConsole/option_manager.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/FasterStereoConsole/option_manager.h
--------------------------------------------------------------------------------
/FasterStereoConsole/fasterstereocuda.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/FasterStereoConsole/fasterstereocuda.a
--------------------------------------------------------------------------------
/FasterStereoConsole/option_manager.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/FasterStereoConsole/option_manager.cpp
--------------------------------------------------------------------------------
/FasterStereoConsole/FasterStereoConsole.aps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/FasterStereoConsole/FasterStereoConsole.aps
--------------------------------------------------------------------------------
/FasterStereoConsole/FasterStereoConsole.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/FasterStereoConsole/FasterStereoConsole.cpp
--------------------------------------------------------------------------------
/FasterStereoConsole/FasterStereoConsole.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/FasterStereoConsole/FasterStereoConsole.rc
--------------------------------------------------------------------------------
/library/FasterStereoCuda/dll/StereoCuda.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/library/FasterStereoCuda/dll/StereoCuda.dll
--------------------------------------------------------------------------------
/library/FasterStereoCuda/dll/cudart64_110.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/library/FasterStereoCuda/dll/cudart64_110.dll
--------------------------------------------------------------------------------
/library/FasterStereoCuda/dll/FasterStereoCuda.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/library/FasterStereoCuda/dll/FasterStereoCuda.dll
--------------------------------------------------------------------------------
/library/FasterStereoCuda/include/FasterStereoCuda.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/library/FasterStereoCuda/include/FasterStereoCuda.h
--------------------------------------------------------------------------------
/library/FasterStereoCuda/lib/FasterStereoCuda.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethan-li-coding/FasterStereoCuda-Library/HEAD/library/FasterStereoCuda/lib/FasterStereoCuda.lib
--------------------------------------------------------------------------------
/FasterStereoConsole/FasterStereoConsole.vcxproj.administrator.nvuser:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Data/option.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4800
5 | 3409
6 |
7 |
8 | -776
9 | -520
10 | 2
11 | 1
12 | 1
13 | 0
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Data/option_Cone.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 450
5 | 375
6 |
7 |
8 | 0
9 | 64
10 | 1
11 | 1
12 | 0
13 | 0
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Data/option_KITTI.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1242
5 | 375
6 |
7 |
8 | 0
9 | 64
10 | 2
11 | 1
12 | 0
13 | 0
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Data/option_Building.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4800
5 | 3409
6 |
7 |
8 | -776
9 | -520
10 | 3
11 | 1
12 | 1
13 | 0
14 |
15 |
16 |
--------------------------------------------------------------------------------
/FasterStereoConsole/FasterStereoConsole.vcxproj.lys.nvuser:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Data/option2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4800
5 | 3409
6 |
7 |
8 | 34000.0
9 | 96500.0
10 | 2
11 | 1
12 | 1
13 | 0
14 |
15 |
16 | 2627.2746582031250
17 | 1630.0000000000000
18 | 3542.9848632812500
19 | 1630.0000000000000
20 | 4324.5149416122963
21 | 3117.0942850000001
22 |
23 |
24 |
--------------------------------------------------------------------------------
/FasterStereoConsole/FasterStereoConsole.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(SolutionDir)Data\Building\left.bmp $(SolutionDir)Data\Building\right.bmp $(SolutionDir)Data\Building\option.xml
5 | WindowsLocalDebugger
6 | E:\ZG-Prog\GScan\Data\Ep-Data2
7 | $(TargetPath)
8 |
9 |
10 |
11 |
12 | WindowsLocalDebugger
13 |
14 |
--------------------------------------------------------------------------------
/FasterStereoCuda-v19.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28803.202
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FasterStereoConsole", "FasterStereoConsole\FasterStereoConsole.vcxproj", "{82B60534-8E5C-4398-8880-6ABDC8FBE24E}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}.Debug|x64.ActiveCfg = Debug|x64
17 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}.Debug|x64.Build.0 = Debug|x64
18 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}.Debug|x86.ActiveCfg = Debug|Win32
19 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}.Debug|x86.Build.0 = Debug|Win32
20 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}.Release|x64.ActiveCfg = Release|x64
21 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}.Release|x64.Build.0 = Release|x64
22 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}.Release|x86.ActiveCfg = Release|Win32
23 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {AD074331-6078-4D5B-8C81-68A4EDA16ACF}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/FasterStereoConsole/FasterStereoConsole.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 |
29 |
30 | Header Files
31 |
32 |
33 | Header Files
34 |
35 |
36 | Header Files
37 |
38 |
39 |
40 |
41 | Resource Files
42 |
43 |
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FasterStereoCuda-Library
2 |
3 | # 必要更新提醒
4 | 1. 试用期更新为12个月,过期了直接contact me!
5 | 2. 修复了你可能不知道的很多bugs!
6 | # 简介
7 |
8 | 这是一个基于CUDA加速的快速立体匹配库,它的核心是SemiglobalMatching(SGM)算法,它不仅在时间效率上要远远优于基于CPU的常规SGM,而且明显占用更少的内存,这意味着它不仅可以在较低分辨率(百万级)图像上达到实时的帧率,且完全具备处理千万级甚至更高量级图像的能力。
9 |
10 | 你可以拉取本测试工程并在自己的数据上体验它的改进效果,也可以在右侧下载已经打包好的压缩包,直接在本地运行控制台程序,或者在你的工程里通过动态库的方式调用它。
11 |
12 | # 环境
13 |
14 | Windows 10
15 | Visual Studio 2019
16 | CUDA v11.0
17 | Opencv3.2(下载地址:[https://download.csdn.net/download/rs_lys/13193887](https://download.csdn.net/download/rs_lys/13193887))
18 |
19 | # 控制台调用方式
20 | >**单像对:**
21 | >../FasterStereoConsole.exe ../Data/Cone/left.png ../Data/Cone/right.png ../Data/Cone/option.xml
22 | >**多像对:**(KITTI)
23 | >../FasterStereoConsole.exe ../Data/KITTI/image_2 ../Data/KITTI/image_3 png ../Data/KITTI/option.xml
24 | >把../换成你的路径。option.xml是算法参数文件,在Data/文件夹中,附有两类参数文件option.xml和option2.xml,分别对应视差空间和深度空间的参数,二者用其一即可。不同的数据,需要对应修改option.xml文件的参数值。
25 |
26 | >关于视差范围有特殊要求:必须满足64x2n,如64、128、256、512。
27 |
28 | >使用过程中有任何问题,特别是算法BUG,请及时和我交流,感谢!
29 |
30 | # 重要说明
31 |
32 | 算法库为试用版,试用期12个月,联系!
33 |
34 | 微信:EthanYs6
35 | 邮箱:rs_lys@163.com
36 |
37 | # 一些案例图片
38 | ## 概览
39 | | 数据 | Cone(450x375x64) | Kitti(1242x375x64) | Building(4800x3409x256) |
40 | | ------ | ------ | ------ | ------ |
41 | | 帧率 | 341.2 | 154.7 | 6.0 |
42 | | 显存(Mb) | 258.9 | 325.3 | 4185.9 |
43 |
44 | 案例数据下载地址:[https://download.csdn.net/download/rs_lys/13074343](https://download.csdn.net/download/rs_lys/13074343)
45 | 测试平台:NVIDIA GTX1080
46 |
47 | ## 数据1:Cone(450*375)
48 |
49 |

50 |
51 |
52 | ## 数据2:Kitti(1242*375)
53 |
54 |

55 |
56 |
57 | ## 数据3:Building(4800*3409)
58 |
59 |

60 |
61 |
62 | ## Github图片不显示的解决办法
63 | 修改hosts
64 |
65 | C:\Windows\System32\drivers\etc\hosts
66 |
67 | 在文件末尾添加:
68 | ```cpp
69 | # GitHub Start
70 | 192.30.253.119 gist.github.com
71 | 151.101.184.133 assets-cdn.github.com
72 | 151.101.184.133 raw.githubusercontent.com
73 | 151.101.184.133 gist.githubusercontent.com
74 | 151.101.184.133 cloud.githubusercontent.com
75 | 151.101.184.133 camo.githubusercontent.com
76 | 151.101.184.133 avatars0.githubusercontent.com
77 | 151.101.184.133 avatars1.githubusercontent.com
78 | 151.101.184.133 avatars2.githubusercontent.com
79 | 151.101.184.133 avatars3.githubusercontent.com
80 | 151.101.184.133 avatars4.githubusercontent.com
81 | 151.101.184.133 avatars5.githubusercontent.com
82 | 151.101.184.133 avatars6.githubusercontent.com
83 | 151.101.184.133 avatars7.githubusercontent.com
84 | 151.101.184.133 avatars8.githubusercontent.com
85 | # GitHub End
86 |
87 | ```
88 |
--------------------------------------------------------------------------------
/FasterStereoConsole/FasterStereoConsole.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {82B60534-8E5C-4398-8880-6ABDC8FBE24E}
23 | Win32Proj
24 | SpeckleConsoleTest
25 | 10.0.19041.0
26 | FasterStereoConsole
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | MultiByte
47 |
48 |
49 | Application
50 | false
51 | v140
52 | true
53 | MultiByte
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | true
78 |
79 |
80 | false
81 |
82 |
83 | false
84 |
85 |
86 |
87 | Use
88 | Level3
89 | Disabled
90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
91 | true
92 |
93 |
94 | Console
95 | true
96 |
97 |
98 |
99 |
100 | Use
101 | Level3
102 | Disabled
103 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
104 | true
105 | $(SolutionDir)3rdparty\opencv\include;$(SolutionDir)3rdparty\opencv\include\opencv;$(SolutionDir)3rdparty\opencv\include\opencv2;$(SolutionDir)library\FasterStereoCuda\include\
106 | /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)
107 |
108 |
109 | Console
110 | true
111 | $(SolutionDir)3rdparty\opencv\lib\;$(SolutionDir)library\FasterStereoCuda\lib\;%(AdditionalLibraryDirectories)
112 |
113 |
114 |
115 |
116 | Level3
117 | Use
118 | MaxSpeed
119 | true
120 | true
121 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
122 | true
123 |
124 |
125 | Console
126 | true
127 | true
128 | true
129 |
130 |
131 |
132 |
133 | Level3
134 | Use
135 | MaxSpeed
136 | true
137 | true
138 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
139 | true
140 | $(SolutionDir)3rdparty\opencv\include;$(SolutionDir)3rdparty\opencv\include\opencv;$(SolutionDir)3rdparty\opencv\include\opencv2;$(SolutionDir)library\FasterStereoCuda\include\
141 | /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)
142 | true
143 |
144 |
145 | Console
146 | true
147 | true
148 | true
149 | $(SolutionDir)3rdparty\opencv\lib\;$(SolutionDir)library\FasterStereoCuda\lib\;%(AdditionalLibraryDirectories)
150 |
151 |
152 |
153 |
154 | NotUsing
155 | NotUsing
156 |
157 |
158 | NotUsing
159 | NotUsing
160 |
161 |
162 | NotUsing
163 | NotUsing
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
--------------------------------------------------------------------------------
/FasterStereoConsole/tinyxml2.h:
--------------------------------------------------------------------------------
1 | /*
2 | Original code by Lee Thomason (www.grinninglizard.com)
3 | This software is provided 'as-is', without any express or implied
4 | warranty. In no event will the authors be held liable for any
5 | damages arising from the use of this software.
6 | Permission is granted to anyone to use this software for any
7 | purpose, including commercial applications, and to alter it and
8 | redistribute it freely, subject to the following restrictions:
9 | 1. The origin of this software must not be misrepresented; you must
10 | not claim that you wrote the original software. If you use this
11 | software in a product, an acknowledgment in the product documentation
12 | would be appreciated but is not required.
13 | 2. Altered source versions must be plainly marked as such, and
14 | must not be misrepresented as being the original software.
15 | 3. This notice may not be removed or altered from any source
16 | distribution.
17 | */
18 |
19 | #ifndef TINYXML2_INCLUDED
20 | #define TINYXML2_INCLUDED
21 |
22 | #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
23 | # include
24 | # include
25 | # include
26 | # include
27 | # include
28 | # if defined(__PS3__)
29 | # include
30 | # endif
31 | #else
32 | # include
33 | # include
34 | # include
35 | # include
36 | # include
37 | #endif
38 | #include
39 |
40 | /*
41 | TODO: intern strings instead of allocation.
42 | */
43 | /*
44 | gcc:
45 | g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
46 | Formatting, Artistic Style:
47 | AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
48 | */
49 |
50 | #if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
51 | # ifndef DEBUG
52 | # define DEBUG
53 | # endif
54 | #endif
55 |
56 | #ifdef _MSC_VER
57 | # pragma warning(push)
58 | # pragma warning(disable: 4251)
59 | #endif
60 |
61 | #ifdef _WIN32
62 | # ifdef TINYXML2_EXPORT
63 | # define TINYXML2_LIB __declspec(dllexport)
64 | # elif defined(TINYXML2_IMPORT)
65 | # define TINYXML2_LIB __declspec(dllimport)
66 | # else
67 | # define TINYXML2_LIB
68 | # endif
69 | #elif __GNUC__ >= 4
70 | # define TINYXML2_LIB __attribute__((visibility("default")))
71 | #else
72 | # define TINYXML2_LIB
73 | #endif
74 |
75 |
76 | #if defined(DEBUG)
77 | # if defined(_MSC_VER)
78 | # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
79 | # define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); }
80 | # elif defined (ANDROID_NDK)
81 | # include
82 | # define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
83 | # else
84 | # include
85 | # define TIXMLASSERT assert
86 | # endif
87 | #else
88 | # define TIXMLASSERT( x ) {}
89 | #endif
90 |
91 |
92 | /* Versioning, past 1.0.14:
93 | http://semver.org/
94 | */
95 | static const int TIXML2_MAJOR_VERSION = 4;
96 | static const int TIXML2_MINOR_VERSION = 0;
97 | static const int TIXML2_PATCH_VERSION = 1;
98 |
99 | namespace tinyxml2
100 | {
101 | class XMLDocument;
102 | class XMLElement;
103 | class XMLAttribute;
104 | class XMLComment;
105 | class XMLText;
106 | class XMLDeclaration;
107 | class XMLUnknown;
108 | class XMLPrinter;
109 |
110 | /*
111 | A class that wraps strings. Normally stores the start and end
112 | pointers into the XML file itself, and will apply normalization
113 | and entity translation if actually read. Can also store (and memory
114 | manage) a traditional char[]
115 | */
116 | class StrPair
117 | {
118 | public:
119 | enum {
120 | NEEDS_ENTITY_PROCESSING = 0x01,
121 | NEEDS_NEWLINE_NORMALIZATION = 0x02,
122 | NEEDS_WHITESPACE_COLLAPSING = 0x04,
123 |
124 | TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
125 | TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
126 | ATTRIBUTE_NAME = 0,
127 | ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
128 | ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
129 | COMMENT = NEEDS_NEWLINE_NORMALIZATION
130 | };
131 |
132 | StrPair() : _flags(0), _start(0), _end(0) {}
133 | ~StrPair();
134 |
135 | void Set(char* start, char* end, int flags) {
136 | TIXMLASSERT(start);
137 | TIXMLASSERT(end);
138 | Reset();
139 | _start = start;
140 | _end = end;
141 | _flags = flags | NEEDS_FLUSH;
142 | }
143 |
144 | const char* GetStr();
145 |
146 | bool Empty() const {
147 | return _start == _end;
148 | }
149 |
150 | void SetInternedStr(const char* str) {
151 | Reset();
152 | _start = const_cast(str);
153 | }
154 |
155 | void SetStr(const char* str, int flags = 0);
156 |
157 | char* ParseText(char* in, const char* endTag, int strFlags);
158 | char* ParseName(char* in);
159 |
160 | void TransferTo(StrPair* other);
161 | void Reset();
162 |
163 | private:
164 | void CollapseWhitespace();
165 |
166 | enum {
167 | NEEDS_FLUSH = 0x100,
168 | NEEDS_DELETE = 0x200
169 | };
170 |
171 | int _flags;
172 | char* _start;
173 | char* _end;
174 |
175 | StrPair(const StrPair& other); // not supported
176 | void operator=(StrPair& other); // not supported, use TransferTo()
177 | };
178 |
179 |
180 | /*
181 | A dynamic array of Plain Old Data. Doesn't support constructors, etc.
182 | Has a small initial memory pool, so that low or no usage will not
183 | cause a call to new/delete
184 | */
185 | template
186 | class DynArray
187 | {
188 | public:
189 | DynArray() {
190 | _mem = _pool;
191 | _allocated = INITIAL_SIZE;
192 | _size = 0;
193 | }
194 |
195 | ~DynArray() {
196 | if (_mem != _pool) {
197 | delete[] _mem;
198 | }
199 | }
200 |
201 | void Clear() {
202 | _size = 0;
203 | }
204 |
205 | void Push(T t) {
206 | TIXMLASSERT(_size < INT_MAX);
207 | EnsureCapacity(_size + 1);
208 | _mem[_size] = t;
209 | ++_size;
210 | }
211 |
212 | T* PushArr(int count) {
213 | TIXMLASSERT(count >= 0);
214 | TIXMLASSERT(_size <= INT_MAX - count);
215 | EnsureCapacity(_size + count);
216 | T* ret = &_mem[_size];
217 | _size += count;
218 | return ret;
219 | }
220 |
221 | T Pop() {
222 | TIXMLASSERT(_size > 0);
223 | --_size;
224 | return _mem[_size];
225 | }
226 |
227 | void PopArr(int count) {
228 | TIXMLASSERT(_size >= count);
229 | _size -= count;
230 | }
231 |
232 | bool Empty() const {
233 | return _size == 0;
234 | }
235 |
236 | T& operator[](int i) {
237 | TIXMLASSERT(i >= 0 && i < _size);
238 | return _mem[i];
239 | }
240 |
241 | const T& operator[](int i) const {
242 | TIXMLASSERT(i >= 0 && i < _size);
243 | return _mem[i];
244 | }
245 |
246 | const T& PeekTop() const {
247 | TIXMLASSERT(_size > 0);
248 | return _mem[_size - 1];
249 | }
250 |
251 | int Size() const {
252 | TIXMLASSERT(_size >= 0);
253 | return _size;
254 | }
255 |
256 | int Capacity() const {
257 | TIXMLASSERT(_allocated >= INITIAL_SIZE);
258 | return _allocated;
259 | }
260 |
261 | const T* Mem() const {
262 | TIXMLASSERT(_mem);
263 | return _mem;
264 | }
265 |
266 | T* Mem() {
267 | TIXMLASSERT(_mem);
268 | return _mem;
269 | }
270 |
271 | private:
272 | DynArray(const DynArray&); // not supported
273 | void operator=(const DynArray&); // not supported
274 |
275 | void EnsureCapacity(int cap) {
276 | TIXMLASSERT(cap > 0);
277 | if (cap > _allocated) {
278 | TIXMLASSERT(cap <= INT_MAX / 2);
279 | int newAllocated = cap * 2;
280 | T* newMem = new T[newAllocated];
281 | memcpy(newMem, _mem, sizeof(T)*_size); // warning: not using constructors, only works for PODs
282 | if (_mem != _pool) {
283 | delete[] _mem;
284 | }
285 | _mem = newMem;
286 | _allocated = newAllocated;
287 | }
288 | }
289 |
290 | T* _mem;
291 | T _pool[INITIAL_SIZE];
292 | int _allocated; // objects allocated
293 | int _size; // number objects in use
294 | };
295 |
296 |
297 | /*
298 | Parent virtual class of a pool for fast allocation
299 | and deallocation of objects.
300 | */
301 | class MemPool
302 | {
303 | public:
304 | MemPool() {}
305 | virtual ~MemPool() {}
306 |
307 | virtual int ItemSize() const = 0;
308 | virtual void* Alloc() = 0;
309 | virtual void Free(void*) = 0;
310 | virtual void SetTracked() = 0;
311 | virtual void Clear() = 0;
312 | };
313 |
314 |
315 | /*
316 | Template child class to create pools of the correct type.
317 | */
318 | template< int ITEM_SIZE >
319 | class MemPoolT : public MemPool
320 | {
321 | public:
322 | MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
323 | ~MemPoolT() {
324 | Clear();
325 | }
326 |
327 | void Clear() {
328 | // Delete the blocks.
329 | while (!_blockPtrs.Empty()) {
330 | Block* b = _blockPtrs.Pop();
331 | delete b;
332 | }
333 | _root = 0;
334 | _currentAllocs = 0;
335 | _nAllocs = 0;
336 | _maxAllocs = 0;
337 | _nUntracked = 0;
338 | }
339 |
340 | virtual int ItemSize() const {
341 | return ITEM_SIZE;
342 | }
343 | int CurrentAllocs() const {
344 | return _currentAllocs;
345 | }
346 |
347 | virtual void* Alloc() {
348 | if (!_root) {
349 | // Need a new block.
350 | Block* block = new Block();
351 | _blockPtrs.Push(block);
352 |
353 | Item* blockItems = block->items;
354 | for (int i = 0; i < ITEMS_PER_BLOCK - 1; ++i) {
355 | blockItems[i].next = &(blockItems[i + 1]);
356 | }
357 | blockItems[ITEMS_PER_BLOCK - 1].next = 0;
358 | _root = blockItems;
359 | }
360 | Item* const result = _root;
361 | TIXMLASSERT(result != 0);
362 | _root = _root->next;
363 |
364 | ++_currentAllocs;
365 | if (_currentAllocs > _maxAllocs) {
366 | _maxAllocs = _currentAllocs;
367 | }
368 | ++_nAllocs;
369 | ++_nUntracked;
370 | return result;
371 | }
372 |
373 | virtual void Free(void* mem) {
374 | if (!mem) {
375 | return;
376 | }
377 | --_currentAllocs;
378 | Item* item = static_cast- (mem);
379 | #ifdef DEBUG
380 | memset(item, 0xfe, sizeof(*item));
381 | #endif
382 | item->next = _root;
383 | _root = item;
384 | }
385 | void Trace(const char* name) {
386 | printf("Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
387 | name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,
388 | ITEM_SIZE, _nAllocs, _blockPtrs.Size());
389 | }
390 |
391 | void SetTracked() {
392 | --_nUntracked;
393 | }
394 |
395 | int Untracked() const {
396 | return _nUntracked;
397 | }
398 |
399 | // This number is perf sensitive. 4k seems like a good tradeoff on my machine.
400 | // The test file is large, 170k.
401 | // Release: VS2010 gcc(no opt)
402 | // 1k: 4000
403 | // 2k: 4000
404 | // 4k: 3900 21000
405 | // 16k: 5200
406 | // 32k: 4300
407 | // 64k: 4000 21000
408 | // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK
409 | // in private part if ITEMS_PER_BLOCK is private
410 | enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };
411 |
412 | private:
413 | MemPoolT(const MemPoolT&); // not supported
414 | void operator=(const MemPoolT&); // not supported
415 |
416 | union Item {
417 | Item* next;
418 | char itemData[ITEM_SIZE];
419 | };
420 | struct Block {
421 | Item items[ITEMS_PER_BLOCK];
422 | };
423 | DynArray< Block*, 10 > _blockPtrs;
424 | Item* _root;
425 |
426 | int _currentAllocs;
427 | int _nAllocs;
428 | int _maxAllocs;
429 | int _nUntracked;
430 | };
431 |
432 |
433 |
434 | /**
435 | Implements the interface to the "Visitor pattern" (see the Accept() method.)
436 | If you call the Accept() method, it requires being passed a XMLVisitor
437 | class to handle callbacks. For nodes that contain other nodes (Document, Element)
438 | you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
439 | are simply called with Visit().
440 | If you return 'true' from a Visit method, recursive parsing will continue. If you return
441 | false, no children of this node or its siblings will be visited.
442 | All flavors of Visit methods have a default implementation that returns 'true' (continue
443 | visiting). You need to only override methods that are interesting to you.
444 | Generally Accept() is called on the XMLDocument, although all nodes support visiting.
445 | You should never change the document from a callback.
446 | @sa XMLNode::Accept()
447 | */
448 | class TINYXML2_LIB XMLVisitor
449 | {
450 | public:
451 | virtual ~XMLVisitor() {}
452 |
453 | /// Visit a document.
454 | virtual bool VisitEnter(const XMLDocument& /*doc*/) {
455 | return true;
456 | }
457 | /// Visit a document.
458 | virtual bool VisitExit(const XMLDocument& /*doc*/) {
459 | return true;
460 | }
461 |
462 | /// Visit an element.
463 | virtual bool VisitEnter(const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/) {
464 | return true;
465 | }
466 | /// Visit an element.
467 | virtual bool VisitExit(const XMLElement& /*element*/) {
468 | return true;
469 | }
470 |
471 | /// Visit a declaration.
472 | virtual bool Visit(const XMLDeclaration& /*declaration*/) {
473 | return true;
474 | }
475 | /// Visit a text node.
476 | virtual bool Visit(const XMLText& /*text*/) {
477 | return true;
478 | }
479 | /// Visit a comment node.
480 | virtual bool Visit(const XMLComment& /*comment*/) {
481 | return true;
482 | }
483 | /// Visit an unknown node.
484 | virtual bool Visit(const XMLUnknown& /*unknown*/) {
485 | return true;
486 | }
487 | };
488 |
489 | // WARNING: must match XMLDocument::_errorNames[]
490 | enum XMLError {
491 | XML_SUCCESS = 0,
492 | XML_NO_ATTRIBUTE,
493 | XML_WRONG_ATTRIBUTE_TYPE,
494 | XML_ERROR_FILE_NOT_FOUND,
495 | XML_ERROR_FILE_COULD_NOT_BE_OPENED,
496 | XML_ERROR_FILE_READ_ERROR,
497 | XML_ERROR_ELEMENT_MISMATCH,
498 | XML_ERROR_PARSING_ELEMENT,
499 | XML_ERROR_PARSING_ATTRIBUTE,
500 | XML_ERROR_IDENTIFYING_TAG,
501 | XML_ERROR_PARSING_TEXT,
502 | XML_ERROR_PARSING_CDATA,
503 | XML_ERROR_PARSING_COMMENT,
504 | XML_ERROR_PARSING_DECLARATION,
505 | XML_ERROR_PARSING_UNKNOWN,
506 | XML_ERROR_EMPTY_DOCUMENT,
507 | XML_ERROR_MISMATCHED_ELEMENT,
508 | XML_ERROR_PARSING,
509 | XML_CAN_NOT_CONVERT_TEXT,
510 | XML_NO_TEXT_NODE,
511 |
512 | XML_ERROR_COUNT
513 | };
514 |
515 |
516 | /*
517 | Utility functionality.
518 | */
519 | class XMLUtil
520 | {
521 | public:
522 | static const char* SkipWhiteSpace(const char* p) {
523 | TIXMLASSERT(p);
524 | while (IsWhiteSpace(*p)) {
525 | ++p;
526 | }
527 | TIXMLASSERT(p);
528 | return p;
529 | }
530 | static char* SkipWhiteSpace(char* p) {
531 | return const_cast(SkipWhiteSpace(const_cast(p)));
532 | }
533 |
534 | // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
535 | // correct, but simple, and usually works.
536 | static bool IsWhiteSpace(char p) {
537 | return !IsUTF8Continuation(p) && isspace(static_cast(p));
538 | }
539 |
540 | inline static bool IsNameStartChar(unsigned char ch) {
541 | if (ch >= 128) {
542 | // This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
543 | return true;
544 | }
545 | if (isalpha(ch)) {
546 | return true;
547 | }
548 | return ch == ':' || ch == '_';
549 | }
550 |
551 | inline static bool IsNameChar(unsigned char ch) {
552 | return IsNameStartChar(ch)
553 | || isdigit(ch)
554 | || ch == '.'
555 | || ch == '-';
556 | }
557 |
558 | inline static bool StringEqual(const char* p, const char* q, int nChar = INT_MAX) {
559 | if (p == q) {
560 | return true;
561 | }
562 | TIXMLASSERT(p);
563 | TIXMLASSERT(q);
564 | TIXMLASSERT(nChar >= 0);
565 | return strncmp(p, q, nChar) == 0;
566 | }
567 |
568 | inline static bool IsUTF8Continuation(char p) {
569 | return (p & 0x80) != 0;
570 | }
571 |
572 | static const char* ReadBOM(const char* p, bool* hasBOM);
573 | // p is the starting location,
574 | // the UTF-8 value of the entity will be placed in value, and length filled in.
575 | static const char* GetCharacterRef(const char* p, char* value, int* length);
576 | static void ConvertUTF32ToUTF8(unsigned long input, char* output, int* length);
577 |
578 | // converts primitive types to strings
579 | static void ToStr(int v, char* buffer, int bufferSize);
580 | static void ToStr(unsigned v, char* buffer, int bufferSize);
581 | static void ToStr(bool v, char* buffer, int bufferSize);
582 | static void ToStr(float v, char* buffer, int bufferSize);
583 | static void ToStr(double v, char* buffer, int bufferSize);
584 | static void ToStr(int64_t v, char* buffer, int bufferSize);
585 |
586 | // converts strings to primitive types
587 | static bool ToInt(const char* str, int* value);
588 | static bool ToUnsigned(const char* str, unsigned* value);
589 | static bool ToBool(const char* str, bool* value);
590 | static bool ToFloat(const char* str, float* value);
591 | static bool ToDouble(const char* str, double* value);
592 | static bool ToInt64(const char* str, int64_t* value);
593 | };
594 |
595 |
596 | /** XMLNode is a base class for every object that is in the
597 | XML Document Object Model (DOM), except XMLAttributes.
598 | Nodes have siblings, a parent, and children which can
599 | be navigated. A node is always in a XMLDocument.
600 | The type of a XMLNode can be queried, and it can
601 | be cast to its more defined type.
602 | A XMLDocument allocates memory for all its Nodes.
603 | When the XMLDocument gets deleted, all its Nodes
604 | will also be deleted.
605 | @verbatim
606 | A Document can contain: Element (container or leaf)
607 | Comment (leaf)
608 | Unknown (leaf)
609 | Declaration( leaf )
610 | An Element can contain: Element (container or leaf)
611 | Text (leaf)
612 | Attributes (not on tree)
613 | Comment (leaf)
614 | Unknown (leaf)
615 | @endverbatim
616 | */
617 | class TINYXML2_LIB XMLNode
618 | {
619 | friend class XMLDocument;
620 | friend class XMLElement;
621 | public:
622 |
623 | /// Get the XMLDocument that owns this XMLNode.
624 | const XMLDocument* GetDocument() const {
625 | TIXMLASSERT(_document);
626 | return _document;
627 | }
628 | /// Get the XMLDocument that owns this XMLNode.
629 | XMLDocument* GetDocument() {
630 | TIXMLASSERT(_document);
631 | return _document;
632 | }
633 |
634 | /// Safely cast to an Element, or null.
635 | virtual XMLElement* ToElement() {
636 | return 0;
637 | }
638 | /// Safely cast to Text, or null.
639 | virtual XMLText* ToText() {
640 | return 0;
641 | }
642 | /// Safely cast to a Comment, or null.
643 | virtual XMLComment* ToComment() {
644 | return 0;
645 | }
646 | /// Safely cast to a Document, or null.
647 | virtual XMLDocument* ToDocument() {
648 | return 0;
649 | }
650 | /// Safely cast to a Declaration, or null.
651 | virtual XMLDeclaration* ToDeclaration() {
652 | return 0;
653 | }
654 | /// Safely cast to an Unknown, or null.
655 | virtual XMLUnknown* ToUnknown() {
656 | return 0;
657 | }
658 |
659 | virtual const XMLElement* ToElement() const {
660 | return 0;
661 | }
662 | virtual const XMLText* ToText() const {
663 | return 0;
664 | }
665 | virtual const XMLComment* ToComment() const {
666 | return 0;
667 | }
668 | virtual const XMLDocument* ToDocument() const {
669 | return 0;
670 | }
671 | virtual const XMLDeclaration* ToDeclaration() const {
672 | return 0;
673 | }
674 | virtual const XMLUnknown* ToUnknown() const {
675 | return 0;
676 | }
677 |
678 | /** The meaning of 'value' changes for the specific type.
679 | @verbatim
680 | Document: empty (NULL is returned, not an empty string)
681 | Element: name of the element
682 | Comment: the comment text
683 | Unknown: the tag contents
684 | Text: the text string
685 | @endverbatim
686 | */
687 | const char* Value() const;
688 |
689 | /** Set the Value of an XML node.
690 | @sa Value()
691 | */
692 | void SetValue(const char* val, bool staticMem = false);
693 |
694 | /// Get the parent of this node on the DOM.
695 | const XMLNode* Parent() const {
696 | return _parent;
697 | }
698 |
699 | XMLNode* Parent() {
700 | return _parent;
701 | }
702 |
703 | /// Returns true if this node has no children.
704 | bool NoChildren() const {
705 | return !_firstChild;
706 | }
707 |
708 | /// Get the first child node, or null if none exists.
709 | const XMLNode* FirstChild() const {
710 | return _firstChild;
711 | }
712 |
713 | XMLNode* FirstChild() {
714 | return _firstChild;
715 | }
716 |
717 | /** Get the first child element, or optionally the first child
718 | element with the specified name.
719 | */
720 | const XMLElement* FirstChildElement(const char* name = 0) const;
721 |
722 | XMLElement* FirstChildElement(const char* name = 0) {
723 | return const_cast(const_cast(this)->FirstChildElement(name));
724 | }
725 |
726 | /// Get the last child node, or null if none exists.
727 | const XMLNode* LastChild() const {
728 | return _lastChild;
729 | }
730 |
731 | XMLNode* LastChild() {
732 | return _lastChild;
733 | }
734 |
735 | /** Get the last child element or optionally the last child
736 | element with the specified name.
737 | */
738 | const XMLElement* LastChildElement(const char* name = 0) const;
739 |
740 | XMLElement* LastChildElement(const char* name = 0) {
741 | return const_cast(const_cast(this)->LastChildElement(name));
742 | }
743 |
744 | /// Get the previous (left) sibling node of this node.
745 | const XMLNode* PreviousSibling() const {
746 | return _prev;
747 | }
748 |
749 | XMLNode* PreviousSibling() {
750 | return _prev;
751 | }
752 |
753 | /// Get the previous (left) sibling element of this node, with an optionally supplied name.
754 | const XMLElement* PreviousSiblingElement(const char* name = 0) const;
755 |
756 | XMLElement* PreviousSiblingElement(const char* name = 0) {
757 | return const_cast(const_cast(this)->PreviousSiblingElement(name));
758 | }
759 |
760 | /// Get the next (right) sibling node of this node.
761 | const XMLNode* NextSibling() const {
762 | return _next;
763 | }
764 |
765 | XMLNode* NextSibling() {
766 | return _next;
767 | }
768 |
769 | /// Get the next (right) sibling element of this node, with an optionally supplied name.
770 | const XMLElement* NextSiblingElement(const char* name = 0) const;
771 |
772 | XMLElement* NextSiblingElement(const char* name = 0) {
773 | return const_cast(const_cast(this)->NextSiblingElement(name));
774 | }
775 |
776 | /**
777 | Add a child node as the last (right) child.
778 | If the child node is already part of the document,
779 | it is moved from its old location to the new location.
780 | Returns the addThis argument or 0 if the node does not
781 | belong to the same document.
782 | */
783 | XMLNode* InsertEndChild(XMLNode* addThis);
784 |
785 | XMLNode* LinkEndChild(XMLNode* addThis) {
786 | return InsertEndChild(addThis);
787 | }
788 | /**
789 | Add a child node as the first (left) child.
790 | If the child node is already part of the document,
791 | it is moved from its old location to the new location.
792 | Returns the addThis argument or 0 if the node does not
793 | belong to the same document.
794 | */
795 | XMLNode* InsertFirstChild(XMLNode* addThis);
796 | /**
797 | Add a node after the specified child node.
798 | If the child node is already part of the document,
799 | it is moved from its old location to the new location.
800 | Returns the addThis argument or 0 if the afterThis node
801 | is not a child of this node, or if the node does not
802 | belong to the same document.
803 | */
804 | XMLNode* InsertAfterChild(XMLNode* afterThis, XMLNode* addThis);
805 |
806 | /**
807 | Delete all the children of this node.
808 | */
809 | void DeleteChildren();
810 |
811 | /**
812 | Delete a child of this node.
813 | */
814 | void DeleteChild(XMLNode* node);
815 |
816 | /**
817 | Make a copy of this node, but not its children.
818 | You may pass in a Document pointer that will be
819 | the owner of the new Node. If the 'document' is
820 | null, then the node returned will be allocated
821 | from the current Document. (this->GetDocument())
822 | Note: if called on a XMLDocument, this will return null.
823 | */
824 | virtual XMLNode* ShallowClone(XMLDocument* document) const = 0;
825 |
826 | /**
827 | Test if 2 nodes are the same, but don't test children.
828 | The 2 nodes do not need to be in the same Document.
829 | Note: if called on a XMLDocument, this will return false.
830 | */
831 | virtual bool ShallowEqual(const XMLNode* compare) const = 0;
832 |
833 | /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the
834 | XML tree will be conditionally visited and the host will be called back
835 | via the XMLVisitor interface.
836 | This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse
837 | the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this
838 | interface versus any other.)
839 | The interface has been based on ideas from:
840 | - http://www.saxproject.org/
841 | - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
842 | Which are both good references for "visiting".
843 | An example of using Accept():
844 | @verbatim
845 | XMLPrinter printer;
846 | tinyxmlDoc.Accept( &printer );
847 | const char* xmlcstr = printer.CStr();
848 | @endverbatim
849 | */
850 | virtual bool Accept(XMLVisitor* visitor) const = 0;
851 |
852 | /**
853 | Set user data into the XMLNode. TinyXML-2 in
854 | no way processes or interprets user data.
855 | It is initially 0.
856 | */
857 | void SetUserData(void* userData) { _userData = userData; }
858 |
859 | /**
860 | Get user data set into the XMLNode. TinyXML-2 in
861 | no way processes or interprets user data.
862 | It is initially 0.
863 | */
864 | void* GetUserData() const { return _userData; }
865 |
866 | protected:
867 | XMLNode(XMLDocument*);
868 | virtual ~XMLNode();
869 |
870 | virtual char* ParseDeep(char*, StrPair*);
871 |
872 | XMLDocument* _document;
873 | XMLNode* _parent;
874 | mutable StrPair _value;
875 |
876 | XMLNode* _firstChild;
877 | XMLNode* _lastChild;
878 |
879 | XMLNode* _prev;
880 | XMLNode* _next;
881 |
882 | void* _userData;
883 |
884 | private:
885 | MemPool* _memPool;
886 | void Unlink(XMLNode* child);
887 | static void DeleteNode(XMLNode* node);
888 | void InsertChildPreamble(XMLNode* insertThis) const;
889 | const XMLElement* ToElementWithName(const char* name) const;
890 |
891 | XMLNode(const XMLNode&); // not supported
892 | XMLNode& operator=(const XMLNode&); // not supported
893 | };
894 |
895 |
896 | /** XML text.
897 | Note that a text node can have child element nodes, for example:
898 | @verbatim
899 | This is bold
900 | @endverbatim
901 | A text node can have 2 ways to output the next. "normal" output
902 | and CDATA. It will default to the mode it was parsed from the XML file and
903 | you generally want to leave it alone, but you can change the output mode with
904 | SetCData() and query it with CData().
905 | */
906 | class TINYXML2_LIB XMLText : public XMLNode
907 | {
908 | friend class XMLDocument;
909 | public:
910 | virtual bool Accept(XMLVisitor* visitor) const;
911 |
912 | virtual XMLText* ToText() {
913 | return this;
914 | }
915 | virtual const XMLText* ToText() const {
916 | return this;
917 | }
918 |
919 | /// Declare whether this should be CDATA or standard text.
920 | void SetCData(bool isCData) {
921 | _isCData = isCData;
922 | }
923 | /// Returns true if this is a CDATA text element.
924 | bool CData() const {
925 | return _isCData;
926 | }
927 |
928 | virtual XMLNode* ShallowClone(XMLDocument* document) const;
929 | virtual bool ShallowEqual(const XMLNode* compare) const;
930 |
931 | protected:
932 | XMLText(XMLDocument* doc) : XMLNode(doc), _isCData(false) {}
933 | virtual ~XMLText() {}
934 |
935 | char* ParseDeep(char*, StrPair* endTag);
936 |
937 | private:
938 | bool _isCData;
939 |
940 | XMLText(const XMLText&); // not supported
941 | XMLText& operator=(const XMLText&); // not supported
942 | };
943 |
944 |
945 | /** An XML Comment. */
946 | class TINYXML2_LIB XMLComment : public XMLNode
947 | {
948 | friend class XMLDocument;
949 | public:
950 | virtual XMLComment* ToComment() {
951 | return this;
952 | }
953 | virtual const XMLComment* ToComment() const {
954 | return this;
955 | }
956 |
957 | virtual bool Accept(XMLVisitor* visitor) const;
958 |
959 | virtual XMLNode* ShallowClone(XMLDocument* document) const;
960 | virtual bool ShallowEqual(const XMLNode* compare) const;
961 |
962 | protected:
963 | XMLComment(XMLDocument* doc);
964 | virtual ~XMLComment();
965 |
966 | char* ParseDeep(char*, StrPair* endTag);
967 |
968 | private:
969 | XMLComment(const XMLComment&); // not supported
970 | XMLComment& operator=(const XMLComment&); // not supported
971 | };
972 |
973 |
974 | /** In correct XML the declaration is the first entry in the file.
975 | @verbatim
976 |
977 | @endverbatim
978 | TinyXML-2 will happily read or write files without a declaration,
979 | however.
980 | The text of the declaration isn't interpreted. It is parsed
981 | and written as a string.
982 | */
983 | class TINYXML2_LIB XMLDeclaration : public XMLNode
984 | {
985 | friend class XMLDocument;
986 | public:
987 | virtual XMLDeclaration* ToDeclaration() {
988 | return this;
989 | }
990 | virtual const XMLDeclaration* ToDeclaration() const {
991 | return this;
992 | }
993 |
994 | virtual bool Accept(XMLVisitor* visitor) const;
995 |
996 | virtual XMLNode* ShallowClone(XMLDocument* document) const;
997 | virtual bool ShallowEqual(const XMLNode* compare) const;
998 |
999 | protected:
1000 | XMLDeclaration(XMLDocument* doc);
1001 | virtual ~XMLDeclaration();
1002 |
1003 | char* ParseDeep(char*, StrPair* endTag);
1004 |
1005 | private:
1006 | XMLDeclaration(const XMLDeclaration&); // not supported
1007 | XMLDeclaration& operator=(const XMLDeclaration&); // not supported
1008 | };
1009 |
1010 |
1011 | /** Any tag that TinyXML-2 doesn't recognize is saved as an
1012 | unknown. It is a tag of text, but should not be modified.
1013 | It will be written back to the XML, unchanged, when the file
1014 | is saved.
1015 | DTD tags get thrown into XMLUnknowns.
1016 | */
1017 | class TINYXML2_LIB XMLUnknown : public XMLNode
1018 | {
1019 | friend class XMLDocument;
1020 | public:
1021 | virtual XMLUnknown* ToUnknown() {
1022 | return this;
1023 | }
1024 | virtual const XMLUnknown* ToUnknown() const {
1025 | return this;
1026 | }
1027 |
1028 | virtual bool Accept(XMLVisitor* visitor) const;
1029 |
1030 | virtual XMLNode* ShallowClone(XMLDocument* document) const;
1031 | virtual bool ShallowEqual(const XMLNode* compare) const;
1032 |
1033 | protected:
1034 | XMLUnknown(XMLDocument* doc);
1035 | virtual ~XMLUnknown();
1036 |
1037 | char* ParseDeep(char*, StrPair* endTag);
1038 |
1039 | private:
1040 | XMLUnknown(const XMLUnknown&); // not supported
1041 | XMLUnknown& operator=(const XMLUnknown&); // not supported
1042 | };
1043 |
1044 |
1045 |
1046 | /** An attribute is a name-value pair. Elements have an arbitrary
1047 | number of attributes, each with a unique name.
1048 | @note The attributes are not XMLNodes. You may only query the
1049 | Next() attribute in a list.
1050 | */
1051 | class TINYXML2_LIB XMLAttribute
1052 | {
1053 | friend class XMLElement;
1054 | public:
1055 | /// The name of the attribute.
1056 | const char* Name() const;
1057 |
1058 | /// The value of the attribute.
1059 | const char* Value() const;
1060 |
1061 | /// The next attribute in the list.
1062 | const XMLAttribute* Next() const {
1063 | return _next;
1064 | }
1065 |
1066 | /** IntValue interprets the attribute as an integer, and returns the value.
1067 | If the value isn't an integer, 0 will be returned. There is no error checking;
1068 | use QueryIntValue() if you need error checking.
1069 | */
1070 | int IntValue() const {
1071 | int i = 0;
1072 | QueryIntValue(&i);
1073 | return i;
1074 | }
1075 |
1076 | int64_t Int64Value() const {
1077 | int64_t i = 0;
1078 | QueryInt64Value(&i);
1079 | return i;
1080 | }
1081 |
1082 | /// Query as an unsigned integer. See IntValue()
1083 | unsigned UnsignedValue() const {
1084 | unsigned i = 0;
1085 | QueryUnsignedValue(&i);
1086 | return i;
1087 | }
1088 | /// Query as a boolean. See IntValue()
1089 | bool BoolValue() const {
1090 | bool b = false;
1091 | QueryBoolValue(&b);
1092 | return b;
1093 | }
1094 | /// Query as a double. See IntValue()
1095 | double DoubleValue() const {
1096 | double d = 0;
1097 | QueryDoubleValue(&d);
1098 | return d;
1099 | }
1100 | /// Query as a float. See IntValue()
1101 | float FloatValue() const {
1102 | float f = 0;
1103 | QueryFloatValue(&f);
1104 | return f;
1105 | }
1106 |
1107 | /** QueryIntValue interprets the attribute as an integer, and returns the value
1108 | in the provided parameter. The function will return XML_SUCCESS on success,
1109 | and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
1110 | */
1111 | XMLError QueryIntValue(int* value) const;
1112 | /// See QueryIntValue
1113 | XMLError QueryUnsignedValue(unsigned int* value) const;
1114 | /// See QueryIntValue
1115 | XMLError QueryInt64Value(int64_t* value) const;
1116 | /// See QueryIntValue
1117 | XMLError QueryBoolValue(bool* value) const;
1118 | /// See QueryIntValue
1119 | XMLError QueryDoubleValue(double* value) const;
1120 | /// See QueryIntValue
1121 | XMLError QueryFloatValue(float* value) const;
1122 |
1123 | /// Set the attribute to a string value.
1124 | void SetAttribute(const char* value);
1125 | /// Set the attribute to value.
1126 | void SetAttribute(int value);
1127 | /// Set the attribute to value.
1128 | void SetAttribute(unsigned value);
1129 | /// Set the attribute to value.
1130 | void SetAttribute(int64_t value);
1131 | /// Set the attribute to value.
1132 | void SetAttribute(bool value);
1133 | /// Set the attribute to value.
1134 | void SetAttribute(double value);
1135 | /// Set the attribute to value.
1136 | void SetAttribute(float value);
1137 |
1138 | private:
1139 | enum { BUF_SIZE = 200 };
1140 |
1141 | XMLAttribute() : _next(0), _memPool(0) {}
1142 | virtual ~XMLAttribute() {}
1143 |
1144 | XMLAttribute(const XMLAttribute&); // not supported
1145 | void operator=(const XMLAttribute&); // not supported
1146 | void SetName(const char* name);
1147 |
1148 | char* ParseDeep(char* p, bool processEntities);
1149 |
1150 | mutable StrPair _name;
1151 | mutable StrPair _value;
1152 | XMLAttribute* _next;
1153 | MemPool* _memPool;
1154 | };
1155 |
1156 |
1157 | /** The element is a container class. It has a value, the element name,
1158 | and can contain other elements, text, comments, and unknowns.
1159 | Elements also contain an arbitrary number of attributes.
1160 | */
1161 | class TINYXML2_LIB XMLElement : public XMLNode
1162 | {
1163 | friend class XMLDocument;
1164 | public:
1165 | /// Get the name of an element (which is the Value() of the node.)
1166 | const char* Name() const {
1167 | return Value();
1168 | }
1169 | /// Set the name of the element.
1170 | void SetName(const char* str, bool staticMem = false) {
1171 | SetValue(str, staticMem);
1172 | }
1173 |
1174 | virtual XMLElement* ToElement() {
1175 | return this;
1176 | }
1177 | virtual const XMLElement* ToElement() const {
1178 | return this;
1179 | }
1180 | virtual bool Accept(XMLVisitor* visitor) const;
1181 |
1182 | /** Given an attribute name, Attribute() returns the value
1183 | for the attribute of that name, or null if none
1184 | exists. For example:
1185 | @verbatim
1186 | const char* value = ele->Attribute( "foo" );
1187 | @endverbatim
1188 | The 'value' parameter is normally null. However, if specified,
1189 | the attribute will only be returned if the 'name' and 'value'
1190 | match. This allow you to write code:
1191 | @verbatim
1192 | if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
1193 | @endverbatim
1194 | rather than:
1195 | @verbatim
1196 | if ( ele->Attribute( "foo" ) ) {
1197 | if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
1198 | }
1199 | @endverbatim
1200 | */
1201 | const char* Attribute(const char* name, const char* value = 0) const;
1202 |
1203 | /** Given an attribute name, IntAttribute() returns the value
1204 | of the attribute interpreted as an integer. The default
1205 | value will be returned if the attribute isn't present,
1206 | or if there is an error. (For a method with error
1207 | checking, see QueryIntAttribute()).
1208 | */
1209 | int IntAttribute(const char* name, int defaultValue = 0) const;
1210 | /// See IntAttribute()
1211 | unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
1212 | /// See IntAttribute()
1213 | int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;
1214 | /// See IntAttribute()
1215 | bool BoolAttribute(const char* name, bool defaultValue = false) const;
1216 | /// See IntAttribute()
1217 | double DoubleAttribute(const char* name, double defaultValue = 0) const;
1218 | /// See IntAttribute()
1219 | float FloatAttribute(const char* name, float defaultValue = 0) const;
1220 |
1221 | /** Given an attribute name, QueryIntAttribute() returns
1222 | XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1223 | can't be performed, or XML_NO_ATTRIBUTE if the attribute
1224 | doesn't exist. If successful, the result of the conversion
1225 | will be written to 'value'. If not successful, nothing will
1226 | be written to 'value'. This allows you to provide default
1227 | value:
1228 | @verbatim
1229 | int value = 10;
1230 | QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1231 | @endverbatim
1232 | */
1233 | XMLError QueryIntAttribute(const char* name, int* value) const {
1234 | const XMLAttribute* a = FindAttribute(name);
1235 | if (!a) {
1236 | return XML_NO_ATTRIBUTE;
1237 | }
1238 | return a->QueryIntValue(value);
1239 | }
1240 |
1241 | /// See QueryIntAttribute()
1242 | XMLError QueryUnsignedAttribute(const char* name, unsigned int* value) const {
1243 | const XMLAttribute* a = FindAttribute(name);
1244 | if (!a) {
1245 | return XML_NO_ATTRIBUTE;
1246 | }
1247 | return a->QueryUnsignedValue(value);
1248 | }
1249 |
1250 | /// See QueryIntAttribute()
1251 | XMLError QueryInt64Attribute(const char* name, int64_t* value) const {
1252 | const XMLAttribute* a = FindAttribute(name);
1253 | if (!a) {
1254 | return XML_NO_ATTRIBUTE;
1255 | }
1256 | return a->QueryInt64Value(value);
1257 | }
1258 |
1259 | /// See QueryIntAttribute()
1260 | XMLError QueryBoolAttribute(const char* name, bool* value) const {
1261 | const XMLAttribute* a = FindAttribute(name);
1262 | if (!a) {
1263 | return XML_NO_ATTRIBUTE;
1264 | }
1265 | return a->QueryBoolValue(value);
1266 | }
1267 | /// See QueryIntAttribute()
1268 | XMLError QueryDoubleAttribute(const char* name, double* value) const {
1269 | const XMLAttribute* a = FindAttribute(name);
1270 | if (!a) {
1271 | return XML_NO_ATTRIBUTE;
1272 | }
1273 | return a->QueryDoubleValue(value);
1274 | }
1275 | /// See QueryIntAttribute()
1276 | XMLError QueryFloatAttribute(const char* name, float* value) const {
1277 | const XMLAttribute* a = FindAttribute(name);
1278 | if (!a) {
1279 | return XML_NO_ATTRIBUTE;
1280 | }
1281 | return a->QueryFloatValue(value);
1282 | }
1283 |
1284 |
1285 | /** Given an attribute name, QueryAttribute() returns
1286 | XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1287 | can't be performed, or XML_NO_ATTRIBUTE if the attribute
1288 | doesn't exist. It is overloaded for the primitive types,
1289 | and is a generally more convenient replacement of
1290 | QueryIntAttribute() and related functions.
1291 |
1292 | If successful, the result of the conversion
1293 | will be written to 'value'. If not successful, nothing will
1294 | be written to 'value'. This allows you to provide default
1295 | value:
1296 | @verbatim
1297 | int value = 10;
1298 | QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1299 | @endverbatim
1300 | */
1301 | int QueryAttribute(const char* name, int* value) const {
1302 | return QueryIntAttribute(name, value);
1303 | }
1304 |
1305 | int QueryAttribute(const char* name, unsigned int* value) const {
1306 | return QueryUnsignedAttribute(name, value);
1307 | }
1308 |
1309 | int QueryAttribute(const char* name, int64_t* value) const {
1310 | return QueryInt64Attribute(name, value);
1311 | }
1312 |
1313 | int QueryAttribute(const char* name, bool* value) const {
1314 | return QueryBoolAttribute(name, value);
1315 | }
1316 |
1317 | int QueryAttribute(const char* name, double* value) const {
1318 | return QueryDoubleAttribute(name, value);
1319 | }
1320 |
1321 | int QueryAttribute(const char* name, float* value) const {
1322 | return QueryFloatAttribute(name, value);
1323 | }
1324 |
1325 | /// Sets the named attribute to value.
1326 | void SetAttribute(const char* name, const char* value) {
1327 | XMLAttribute* a = FindOrCreateAttribute(name);
1328 | a->SetAttribute(value);
1329 | }
1330 | /// Sets the named attribute to value.
1331 | void SetAttribute(const char* name, int value) {
1332 | XMLAttribute* a = FindOrCreateAttribute(name);
1333 | a->SetAttribute(value);
1334 | }
1335 | /// Sets the named attribute to value.
1336 | void SetAttribute(const char* name, unsigned value) {
1337 | XMLAttribute* a = FindOrCreateAttribute(name);
1338 | a->SetAttribute(value);
1339 | }
1340 |
1341 | /// Sets the named attribute to value.
1342 | void SetAttribute(const char* name, int64_t value) {
1343 | XMLAttribute* a = FindOrCreateAttribute(name);
1344 | a->SetAttribute(value);
1345 | }
1346 |
1347 | /// Sets the named attribute to value.
1348 | void SetAttribute(const char* name, bool value) {
1349 | XMLAttribute* a = FindOrCreateAttribute(name);
1350 | a->SetAttribute(value);
1351 | }
1352 | /// Sets the named attribute to value.
1353 | void SetAttribute(const char* name, double value) {
1354 | XMLAttribute* a = FindOrCreateAttribute(name);
1355 | a->SetAttribute(value);
1356 | }
1357 | /// Sets the named attribute to value.
1358 | void SetAttribute(const char* name, float value) {
1359 | XMLAttribute* a = FindOrCreateAttribute(name);
1360 | a->SetAttribute(value);
1361 | }
1362 |
1363 | /**
1364 | Delete an attribute.
1365 | */
1366 | void DeleteAttribute(const char* name);
1367 |
1368 | /// Return the first attribute in the list.
1369 | const XMLAttribute* FirstAttribute() const {
1370 | return _rootAttribute;
1371 | }
1372 | /// Query a specific attribute in the list.
1373 | const XMLAttribute* FindAttribute(const char* name) const;
1374 |
1375 | /** Convenience function for easy access to the text inside an element. Although easy
1376 | and concise, GetText() is limited compared to getting the XMLText child
1377 | and accessing it directly.
1378 | If the first child of 'this' is a XMLText, the GetText()
1379 | returns the character string of the Text node, else null is returned.
1380 | This is a convenient method for getting the text of simple contained text:
1381 | @verbatim
1382 | This is text
1383 | const char* str = fooElement->GetText();
1384 | @endverbatim
1385 | 'str' will be a pointer to "This is text".
1386 | Note that this function can be misleading. If the element foo was created from
1387 | this XML:
1388 | @verbatim
1389 | This is text
1390 | @endverbatim
1391 | then the value of str would be null. The first child node isn't a text node, it is
1392 | another element. From this XML:
1393 | @verbatim
1394 | This is text
1395 | @endverbatim
1396 | GetText() will return "This is ".
1397 | */
1398 | const char* GetText() const;
1399 |
1400 | /** Convenience function for easy access to the text inside an element. Although easy
1401 | and concise, SetText() is limited compared to creating an XMLText child
1402 | and mutating it directly.
1403 | If the first child of 'this' is a XMLText, SetText() sets its value to
1404 | the given string, otherwise it will create a first child that is an XMLText.
1405 | This is a convenient method for setting the text of simple contained text:
1406 | @verbatim
1407 | This is text
1408 | fooElement->SetText( "Hullaballoo!" );
1409 | Hullaballoo!
1410 | @endverbatim
1411 | Note that this function can be misleading. If the element foo was created from
1412 | this XML:
1413 | @verbatim
1414 | This is text
1415 | @endverbatim
1416 | then it will not change "This is text", but rather prefix it with a text element:
1417 | @verbatim
1418 | Hullaballoo!This is text
1419 | @endverbatim
1420 |
1421 | For this XML:
1422 | @verbatim
1423 |
1424 | @endverbatim
1425 | SetText() will generate
1426 | @verbatim
1427 | Hullaballoo!
1428 | @endverbatim
1429 | */
1430 | void SetText(const char* inText);
1431 | /// Convenience method for setting text inside an element. See SetText() for important limitations.
1432 | void SetText(int value);
1433 | /// Convenience method for setting text inside an element. See SetText() for important limitations.
1434 | void SetText(unsigned value);
1435 | /// Convenience method for setting text inside an element. See SetText() for important limitations.
1436 | void SetText(int64_t value);
1437 | /// Convenience method for setting text inside an element. See SetText() for important limitations.
1438 | void SetText(bool value);
1439 | /// Convenience method for setting text inside an element. See SetText() for important limitations.
1440 | void SetText(double value);
1441 | /// Convenience method for setting text inside an element. See SetText() for important limitations.
1442 | void SetText(float value);
1443 |
1444 | /**
1445 | Convenience method to query the value of a child text node. This is probably best
1446 | shown by example. Given you have a document is this form:
1447 | @verbatim
1448 |
1449 | 1
1450 | 1.4
1451 |
1452 | @endverbatim
1453 | The QueryIntText() and similar functions provide a safe and easier way to get to the
1454 | "value" of x and y.
1455 | @verbatim
1456 | int x = 0;
1457 | float y = 0; // types of x and y are contrived for example
1458 | const XMLElement* xElement = pointElement->FirstChildElement( "x" );
1459 | const XMLElement* yElement = pointElement->FirstChildElement( "y" );
1460 | xElement->QueryIntText( &x );
1461 | yElement->QueryFloatText( &y );
1462 | @endverbatim
1463 | @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
1464 | to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
1465 | */
1466 | XMLError QueryIntText(int* ival) const;
1467 | /// See QueryIntText()
1468 | XMLError QueryUnsignedText(unsigned* uval) const;
1469 | /// See QueryIntText()
1470 | XMLError QueryInt64Text(int64_t* uval) const;
1471 | /// See QueryIntText()
1472 | XMLError QueryBoolText(bool* bval) const;
1473 | /// See QueryIntText()
1474 | XMLError QueryDoubleText(double* dval) const;
1475 | /// See QueryIntText()
1476 | XMLError QueryFloatText(float* fval) const;
1477 |
1478 | int IntText(int defaultValue = 0) const;
1479 |
1480 | /// See QueryIntText()
1481 | unsigned UnsignedText(unsigned defaultValue = 0) const;
1482 | /// See QueryIntText()
1483 | int64_t Int64Text(int64_t defaultValue = 0) const;
1484 | /// See QueryIntText()
1485 | bool BoolText(bool defaultValue = false) const;
1486 | /// See QueryIntText()
1487 | double DoubleText(double defaultValue = 0) const;
1488 | /// See QueryIntText()
1489 | float FloatText(float defaultValue = 0) const;
1490 |
1491 | // internal:
1492 | enum {
1493 | OPEN, //
1494 | CLOSED, //
1495 | CLOSING //
1496 | };
1497 | int ClosingType() const {
1498 | return _closingType;
1499 | }
1500 | virtual XMLNode* ShallowClone(XMLDocument* document) const;
1501 | virtual bool ShallowEqual(const XMLNode* compare) const;
1502 |
1503 | protected:
1504 | char* ParseDeep(char* p, StrPair* endTag);
1505 |
1506 | private:
1507 | XMLElement(XMLDocument* doc);
1508 | virtual ~XMLElement();
1509 | XMLElement(const XMLElement&); // not supported
1510 | void operator=(const XMLElement&); // not supported
1511 |
1512 | XMLAttribute* FindAttribute(const char* name) {
1513 | return const_cast(const_cast(this)->FindAttribute(name));
1514 | }
1515 | XMLAttribute* FindOrCreateAttribute(const char* name);
1516 | //void LinkAttribute( XMLAttribute* attrib );
1517 | char* ParseAttributes(char* p);
1518 | static void DeleteAttribute(XMLAttribute* attribute);
1519 | XMLAttribute* CreateAttribute();
1520 |
1521 | enum { BUF_SIZE = 200 };
1522 | int _closingType;
1523 | // The attribute list is ordered; there is no 'lastAttribute'
1524 | // because the list needs to be scanned for dupes before adding
1525 | // a new attribute.
1526 | XMLAttribute* _rootAttribute;
1527 | };
1528 |
1529 |
1530 | enum Whitespace {
1531 | PRESERVE_WHITESPACE,
1532 | COLLAPSE_WHITESPACE
1533 | };
1534 |
1535 |
1536 | /** A Document binds together all the functionality.
1537 | It can be saved, loaded, and printed to the screen.
1538 | All Nodes are connected and allocated to a Document.
1539 | If the Document is deleted, all its Nodes are also deleted.
1540 | */
1541 | class TINYXML2_LIB XMLDocument : public XMLNode
1542 | {
1543 | friend class XMLElement;
1544 | public:
1545 | /// constructor
1546 | XMLDocument(bool processEntities = true, Whitespace = PRESERVE_WHITESPACE);
1547 | ~XMLDocument();
1548 |
1549 | virtual XMLDocument* ToDocument() {
1550 | TIXMLASSERT(this == _document);
1551 | return this;
1552 | }
1553 | virtual const XMLDocument* ToDocument() const {
1554 | TIXMLASSERT(this == _document);
1555 | return this;
1556 | }
1557 |
1558 | /**
1559 | Parse an XML file from a character string.
1560 | Returns XML_SUCCESS (0) on success, or
1561 | an errorID.
1562 | You may optionally pass in the 'nBytes', which is
1563 | the number of bytes which will be parsed. If not
1564 | specified, TinyXML-2 will assume 'xml' points to a
1565 | null terminated string.
1566 | */
1567 | XMLError Parse(const char* xml, size_t nBytes = (size_t)(-1));
1568 |
1569 | /**
1570 | Load an XML file from disk.
1571 | Returns XML_SUCCESS (0) on success, or
1572 | an errorID.
1573 | */
1574 | XMLError LoadFile(const char* filename);
1575 |
1576 | /**
1577 | Load an XML file from disk. You are responsible
1578 | for providing and closing the FILE*.
1579 |
1580 | NOTE: The file should be opened as binary ("rb")
1581 | not text in order for TinyXML-2 to correctly
1582 | do newline normalization.
1583 | Returns XML_SUCCESS (0) on success, or
1584 | an errorID.
1585 | */
1586 | XMLError LoadFile(FILE*);
1587 |
1588 | /**
1589 | Save the XML file to disk.
1590 | Returns XML_SUCCESS (0) on success, or
1591 | an errorID.
1592 | */
1593 | XMLError SaveFile(const char* filename, bool compact = false);
1594 |
1595 | /**
1596 | Save the XML file to disk. You are responsible
1597 | for providing and closing the FILE*.
1598 | Returns XML_SUCCESS (0) on success, or
1599 | an errorID.
1600 | */
1601 | XMLError SaveFile(FILE* fp, bool compact = false);
1602 |
1603 | bool ProcessEntities() const {
1604 | return _processEntities;
1605 | }
1606 | Whitespace WhitespaceMode() const {
1607 | return _whitespace;
1608 | }
1609 |
1610 | /**
1611 | Returns true if this document has a leading Byte Order Mark of UTF8.
1612 | */
1613 | bool HasBOM() const {
1614 | return _writeBOM;
1615 | }
1616 | /** Sets whether to write the BOM when writing the file.
1617 | */
1618 | void SetBOM(bool useBOM) {
1619 | _writeBOM = useBOM;
1620 | }
1621 |
1622 | /** Return the root element of DOM. Equivalent to FirstChildElement().
1623 | To get the first node, use FirstChild().
1624 | */
1625 | XMLElement* RootElement() {
1626 | return FirstChildElement();
1627 | }
1628 | const XMLElement* RootElement() const {
1629 | return FirstChildElement();
1630 | }
1631 |
1632 | /** Print the Document. If the Printer is not provided, it will
1633 | print to stdout. If you provide Printer, this can print to a file:
1634 | @verbatim
1635 | XMLPrinter printer( fp );
1636 | doc.Print( &printer );
1637 | @endverbatim
1638 | Or you can use a printer to print to memory:
1639 | @verbatim
1640 | XMLPrinter printer;
1641 | doc.Print( &printer );
1642 | // printer.CStr() has a const char* to the XML
1643 | @endverbatim
1644 | */
1645 | void Print(XMLPrinter* streamer = 0) const;
1646 | virtual bool Accept(XMLVisitor* visitor) const;
1647 |
1648 | /**
1649 | Create a new Element associated with
1650 | this Document. The memory for the Element
1651 | is managed by the Document.
1652 | */
1653 | XMLElement* NewElement(const char* name);
1654 | /**
1655 | Create a new Comment associated with
1656 | this Document. The memory for the Comment
1657 | is managed by the Document.
1658 | */
1659 | XMLComment* NewComment(const char* comment);
1660 | /**
1661 | Create a new Text associated with
1662 | this Document. The memory for the Text
1663 | is managed by the Document.
1664 | */
1665 | XMLText* NewText(const char* text);
1666 | /**
1667 | Create a new Declaration associated with
1668 | this Document. The memory for the object
1669 | is managed by the Document.
1670 | If the 'text' param is null, the standard
1671 | declaration is used.:
1672 | @verbatim
1673 |
1674 | @endverbatim
1675 | */
1676 | XMLDeclaration* NewDeclaration(const char* text = 0);
1677 | /**
1678 | Create a new Unknown associated with
1679 | this Document. The memory for the object
1680 | is managed by the Document.
1681 | */
1682 | XMLUnknown* NewUnknown(const char* text);
1683 |
1684 | /**
1685 | Delete a node associated with this document.
1686 | It will be unlinked from the DOM.
1687 | */
1688 | void DeleteNode(XMLNode* node);
1689 |
1690 | void SetError(XMLError error, const char* str1, const char* str2);
1691 |
1692 | void ClearError() {
1693 | SetError(XML_SUCCESS, 0, 0);
1694 | }
1695 |
1696 | /// Return true if there was an error parsing the document.
1697 | bool Error() const {
1698 | return _errorID != XML_SUCCESS;
1699 | }
1700 | /// Return the errorID.
1701 | XMLError ErrorID() const {
1702 | return _errorID;
1703 | }
1704 | const char* ErrorName() const;
1705 |
1706 | /// Return a possibly helpful diagnostic location or string.
1707 | const char* GetErrorStr1() const {
1708 | return _errorStr1.GetStr();
1709 | }
1710 | /// Return a possibly helpful secondary diagnostic location or string.
1711 | const char* GetErrorStr2() const {
1712 | return _errorStr2.GetStr();
1713 | }
1714 | /// If there is an error, print it to stdout.
1715 | void PrintError() const;
1716 |
1717 | /// Clear the document, resetting it to the initial state.
1718 | void Clear();
1719 |
1720 | // internal
1721 | char* Identify(char* p, XMLNode** node);
1722 |
1723 | virtual XMLNode* ShallowClone(XMLDocument* /*document*/) const {
1724 | return 0;
1725 | }
1726 | virtual bool ShallowEqual(const XMLNode* /*compare*/) const {
1727 | return false;
1728 | }
1729 |
1730 | private:
1731 | XMLDocument(const XMLDocument&); // not supported
1732 | void operator=(const XMLDocument&); // not supported
1733 |
1734 | bool _writeBOM;
1735 | bool _processEntities;
1736 | XMLError _errorID;
1737 | Whitespace _whitespace;
1738 | mutable StrPair _errorStr1;
1739 | mutable StrPair _errorStr2;
1740 | char* _charBuffer;
1741 |
1742 | MemPoolT< sizeof(XMLElement) > _elementPool;
1743 | MemPoolT< sizeof(XMLAttribute) > _attributePool;
1744 | MemPoolT< sizeof(XMLText) > _textPool;
1745 | MemPoolT< sizeof(XMLComment) > _commentPool;
1746 |
1747 | static const char* _errorNames[XML_ERROR_COUNT];
1748 |
1749 | void Parse();
1750 | };
1751 |
1752 |
1753 | /**
1754 | A XMLHandle is a class that wraps a node pointer with null checks; this is
1755 | an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2
1756 | DOM structure. It is a separate utility class.
1757 | Take an example:
1758 | @verbatim
1759 |
1760 |
1761 |
1762 |
1763 |
1764 |
1765 | @endverbatim
1766 | Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
1767 | easy to write a *lot* of code that looks like:
1768 | @verbatim
1769 | XMLElement* root = document.FirstChildElement( "Document" );
1770 | if ( root )
1771 | {
1772 | XMLElement* element = root->FirstChildElement( "Element" );
1773 | if ( element )
1774 | {
1775 | XMLElement* child = element->FirstChildElement( "Child" );
1776 | if ( child )
1777 | {
1778 | XMLElement* child2 = child->NextSiblingElement( "Child" );
1779 | if ( child2 )
1780 | {
1781 | // Finally do something useful.
1782 | @endverbatim
1783 | And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
1784 | of such code. A XMLHandle checks for null pointers so it is perfectly safe
1785 | and correct to use:
1786 | @verbatim
1787 | XMLHandle docHandle( &document );
1788 | XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement();
1789 | if ( child2 )
1790 | {
1791 | // do something useful
1792 | @endverbatim
1793 | Which is MUCH more concise and useful.
1794 | It is also safe to copy handles - internally they are nothing more than node pointers.
1795 | @verbatim
1796 | XMLHandle handleCopy = handle;
1797 | @endverbatim
1798 | See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
1799 | */
1800 | class TINYXML2_LIB XMLHandle
1801 | {
1802 | public:
1803 | /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
1804 | XMLHandle(XMLNode* node) {
1805 | _node = node;
1806 | }
1807 | /// Create a handle from a node.
1808 | XMLHandle(XMLNode& node) {
1809 | _node = &node;
1810 | }
1811 | /// Copy constructor
1812 | XMLHandle(const XMLHandle& ref) {
1813 | _node = ref._node;
1814 | }
1815 | /// Assignment
1816 | XMLHandle& operator=(const XMLHandle& ref) {
1817 | _node = ref._node;
1818 | return *this;
1819 | }
1820 |
1821 | /// Get the first child of this handle.
1822 | XMLHandle FirstChild() {
1823 | return XMLHandle(_node ? _node->FirstChild() : 0);
1824 | }
1825 | /// Get the first child element of this handle.
1826 | XMLHandle FirstChildElement(const char* name = 0) {
1827 | return XMLHandle(_node ? _node->FirstChildElement(name) : 0);
1828 | }
1829 | /// Get the last child of this handle.
1830 | XMLHandle LastChild() {
1831 | return XMLHandle(_node ? _node->LastChild() : 0);
1832 | }
1833 | /// Get the last child element of this handle.
1834 | XMLHandle LastChildElement(const char* name = 0) {
1835 | return XMLHandle(_node ? _node->LastChildElement(name) : 0);
1836 | }
1837 | /// Get the previous sibling of this handle.
1838 | XMLHandle PreviousSibling() {
1839 | return XMLHandle(_node ? _node->PreviousSibling() : 0);
1840 | }
1841 | /// Get the previous sibling element of this handle.
1842 | XMLHandle PreviousSiblingElement(const char* name = 0) {
1843 | return XMLHandle(_node ? _node->PreviousSiblingElement(name) : 0);
1844 | }
1845 | /// Get the next sibling of this handle.
1846 | XMLHandle NextSibling() {
1847 | return XMLHandle(_node ? _node->NextSibling() : 0);
1848 | }
1849 | /// Get the next sibling element of this handle.
1850 | XMLHandle NextSiblingElement(const char* name = 0) {
1851 | return XMLHandle(_node ? _node->NextSiblingElement(name) : 0);
1852 | }
1853 |
1854 | /// Safe cast to XMLNode. This can return null.
1855 | XMLNode* ToNode() {
1856 | return _node;
1857 | }
1858 | /// Safe cast to XMLElement. This can return null.
1859 | XMLElement* ToElement() {
1860 | return (_node ? _node->ToElement() : 0);
1861 | }
1862 | /// Safe cast to XMLText. This can return null.
1863 | XMLText* ToText() {
1864 | return (_node ? _node->ToText() : 0);
1865 | }
1866 | /// Safe cast to XMLUnknown. This can return null.
1867 | XMLUnknown* ToUnknown() {
1868 | return (_node ? _node->ToUnknown() : 0);
1869 | }
1870 | /// Safe cast to XMLDeclaration. This can return null.
1871 | XMLDeclaration* ToDeclaration() {
1872 | return (_node ? _node->ToDeclaration() : 0);
1873 | }
1874 |
1875 | private:
1876 | XMLNode* _node;
1877 | };
1878 |
1879 |
1880 | /**
1881 | A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
1882 | same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
1883 | */
1884 | class TINYXML2_LIB XMLConstHandle
1885 | {
1886 | public:
1887 | XMLConstHandle(const XMLNode* node) {
1888 | _node = node;
1889 | }
1890 | XMLConstHandle(const XMLNode& node) {
1891 | _node = &node;
1892 | }
1893 | XMLConstHandle(const XMLConstHandle& ref) {
1894 | _node = ref._node;
1895 | }
1896 |
1897 | XMLConstHandle& operator=(const XMLConstHandle& ref) {
1898 | _node = ref._node;
1899 | return *this;
1900 | }
1901 |
1902 | const XMLConstHandle FirstChild() const {
1903 | return XMLConstHandle(_node ? _node->FirstChild() : 0);
1904 | }
1905 | const XMLConstHandle FirstChildElement(const char* name = 0) const {
1906 | return XMLConstHandle(_node ? _node->FirstChildElement(name) : 0);
1907 | }
1908 | const XMLConstHandle LastChild() const {
1909 | return XMLConstHandle(_node ? _node->LastChild() : 0);
1910 | }
1911 | const XMLConstHandle LastChildElement(const char* name = 0) const {
1912 | return XMLConstHandle(_node ? _node->LastChildElement(name) : 0);
1913 | }
1914 | const XMLConstHandle PreviousSibling() const {
1915 | return XMLConstHandle(_node ? _node->PreviousSibling() : 0);
1916 | }
1917 | const XMLConstHandle PreviousSiblingElement(const char* name = 0) const {
1918 | return XMLConstHandle(_node ? _node->PreviousSiblingElement(name) : 0);
1919 | }
1920 | const XMLConstHandle NextSibling() const {
1921 | return XMLConstHandle(_node ? _node->NextSibling() : 0);
1922 | }
1923 | const XMLConstHandle NextSiblingElement(const char* name = 0) const {
1924 | return XMLConstHandle(_node ? _node->NextSiblingElement(name) : 0);
1925 | }
1926 |
1927 |
1928 | const XMLNode* ToNode() const {
1929 | return _node;
1930 | }
1931 | const XMLElement* ToElement() const {
1932 | return (_node ? _node->ToElement() : 0);
1933 | }
1934 | const XMLText* ToText() const {
1935 | return (_node ? _node->ToText() : 0);
1936 | }
1937 | const XMLUnknown* ToUnknown() const {
1938 | return (_node ? _node->ToUnknown() : 0);
1939 | }
1940 | const XMLDeclaration* ToDeclaration() const {
1941 | return (_node ? _node->ToDeclaration() : 0);
1942 | }
1943 |
1944 | private:
1945 | const XMLNode* _node;
1946 | };
1947 |
1948 |
1949 | /**
1950 | Printing functionality. The XMLPrinter gives you more
1951 | options than the XMLDocument::Print() method.
1952 | It can:
1953 | -# Print to memory.
1954 | -# Print to a file you provide.
1955 | -# Print XML without a XMLDocument.
1956 | Print to Memory
1957 | @verbatim
1958 | XMLPrinter printer;
1959 | doc.Print( &printer );
1960 | SomeFunction( printer.CStr() );
1961 | @endverbatim
1962 | Print to a File
1963 | You provide the file pointer.
1964 | @verbatim
1965 | XMLPrinter printer( fp );
1966 | doc.Print( &printer );
1967 | @endverbatim
1968 | Print without a XMLDocument
1969 | When loading, an XML parser is very useful. However, sometimes
1970 | when saving, it just gets in the way. The code is often set up
1971 | for streaming, and constructing the DOM is just overhead.
1972 | The Printer supports the streaming case. The following code
1973 | prints out a trivially simple XML file without ever creating
1974 | an XML document.
1975 | @verbatim
1976 | XMLPrinter printer( fp );
1977 | printer.OpenElement( "foo" );
1978 | printer.PushAttribute( "foo", "bar" );
1979 | printer.CloseElement();
1980 | @endverbatim
1981 | */
1982 | class TINYXML2_LIB XMLPrinter : public XMLVisitor
1983 | {
1984 | public:
1985 | /** Construct the printer. If the FILE* is specified,
1986 | this will print to the FILE. Else it will print
1987 | to memory, and the result is available in CStr().
1988 | If 'compact' is set to true, then output is created
1989 | with only required whitespace and newlines.
1990 | */
1991 | XMLPrinter(FILE* file = 0, bool compact = false, int depth = 0);
1992 | virtual ~XMLPrinter() {}
1993 |
1994 | /** If streaming, write the BOM and declaration. */
1995 | void PushHeader(bool writeBOM, bool writeDeclaration);
1996 | /** If streaming, start writing an element.
1997 | The element must be closed with CloseElement()
1998 | */
1999 | void OpenElement(const char* name, bool compactMode = false);
2000 | /// If streaming, add an attribute to an open element.
2001 | void PushAttribute(const char* name, const char* value);
2002 | void PushAttribute(const char* name, int value);
2003 | void PushAttribute(const char* name, unsigned value);
2004 | void PushAttribute(const char* name, int64_t value);
2005 | void PushAttribute(const char* name, bool value);
2006 | void PushAttribute(const char* name, double value);
2007 | /// If streaming, close the Element.
2008 | virtual void CloseElement(bool compactMode = false);
2009 |
2010 | /// Add a text node.
2011 | void PushText(const char* text, bool cdata = false);
2012 | /// Add a text node from an integer.
2013 | void PushText(int value);
2014 | /// Add a text node from an unsigned.
2015 | void PushText(unsigned value);
2016 | /// Add a text node from an unsigned.
2017 | void PushText(int64_t value);
2018 | /// Add a text node from a bool.
2019 | void PushText(bool value);
2020 | /// Add a text node from a float.
2021 | void PushText(float value);
2022 | /// Add a text node from a double.
2023 | void PushText(double value);
2024 |
2025 | /// Add a comment
2026 | void PushComment(const char* comment);
2027 |
2028 | void PushDeclaration(const char* value);
2029 | void PushUnknown(const char* value);
2030 |
2031 | virtual bool VisitEnter(const XMLDocument& /*doc*/);
2032 | virtual bool VisitExit(const XMLDocument& /*doc*/) {
2033 | return true;
2034 | }
2035 |
2036 | virtual bool VisitEnter(const XMLElement& element, const XMLAttribute* attribute);
2037 | virtual bool VisitExit(const XMLElement& element);
2038 |
2039 | virtual bool Visit(const XMLText& text);
2040 | virtual bool Visit(const XMLComment& comment);
2041 | virtual bool Visit(const XMLDeclaration& declaration);
2042 | virtual bool Visit(const XMLUnknown& unknown);
2043 |
2044 | /**
2045 | If in print to memory mode, return a pointer to
2046 | the XML file in memory.
2047 | */
2048 | const char* CStr() const {
2049 | return _buffer.Mem();
2050 | }
2051 | /**
2052 | If in print to memory mode, return the size
2053 | of the XML file in memory. (Note the size returned
2054 | includes the terminating null.)
2055 | */
2056 | int CStrSize() const {
2057 | return _buffer.Size();
2058 | }
2059 | /**
2060 | If in print to memory mode, reset the buffer to the
2061 | beginning.
2062 | */
2063 | void ClearBuffer() {
2064 | _buffer.Clear();
2065 | _buffer.Push(0);
2066 | }
2067 |
2068 | protected:
2069 | virtual bool CompactMode(const XMLElement&) { return _compactMode; }
2070 |
2071 | /** Prints out the space before an element. You may override to change
2072 | the space and tabs used. A PrintSpace() override should call Print().
2073 | */
2074 | virtual void PrintSpace(int depth);
2075 | void Print(const char* format, ...);
2076 |
2077 | void SealElementIfJustOpened();
2078 | bool _elementJustOpened;
2079 | DynArray< const char*, 10 > _stack;
2080 |
2081 | private:
2082 | void PrintString(const char*, bool restrictedEntitySet); // prints out, after detecting entities.
2083 |
2084 | bool _firstElement;
2085 | FILE* _fp;
2086 | int _depth;
2087 | int _textDepth;
2088 | bool _processEntities;
2089 | bool _compactMode;
2090 |
2091 | enum {
2092 | ENTITY_RANGE = 64,
2093 | BUF_SIZE = 200
2094 | };
2095 | bool _entityFlag[ENTITY_RANGE];
2096 | bool _restrictedEntityFlag[ENTITY_RANGE];
2097 |
2098 | DynArray< char, 20 > _buffer;
2099 | };
2100 |
2101 |
2102 | } // tinyxml2
2103 |
2104 | #if defined(_MSC_VER)
2105 | # pragma warning(pop)
2106 | #endif
2107 |
2108 | #endif // TINYXML2_INCLUDED
--------------------------------------------------------------------------------
/FasterStereoConsole/tinyxml2.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Original code by Lee Thomason (www.grinninglizard.com)
3 | This software is provided 'as-is', without any express or implied
4 | warranty. In no event will the authors be held liable for any
5 | damages arising from the use of this software.
6 | Permission is granted to anyone to use this software for any
7 | purpose, including commercial applications, and to alter it and
8 | redistribute it freely, subject to the following restrictions:
9 | 1. The origin of this software must not be misrepresented; you must
10 | not claim that you wrote the original software. If you use this
11 | software in a product, an acknowledgment in the product documentation
12 | would be appreciated but is not required.
13 | 2. Altered source versions must be plainly marked as such, and
14 | must not be misrepresented as being the original software.
15 | 3. This notice may not be removed or altered from any source
16 | distribution.
17 | */
18 | #include "tinyxml2.h"
19 |
20 | #include // yes, this one new style header, is in the Android SDK.
21 | #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
22 | # include
23 | # include
24 | #else
25 | # include
26 | # include
27 | #endif
28 |
29 | #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
30 | // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
31 | /*int _snprintf_s(
32 | char *buffer,
33 | size_t sizeOfBuffer,
34 | size_t count,
35 | const char *format [,
36 | argument] ...
37 | );*/
38 | static inline int TIXML_SNPRINTF(char* buffer, size_t size, const char* format, ...)
39 | {
40 | va_list va;
41 | va_start(va, format);
42 | int result = vsnprintf_s(buffer, size, _TRUNCATE, format, va);
43 | va_end(va);
44 | return result;
45 | }
46 |
47 | static inline int TIXML_VSNPRINTF(char* buffer, size_t size, const char* format, va_list va)
48 | {
49 | int result = vsnprintf_s(buffer, size, _TRUNCATE, format, va);
50 | return result;
51 | }
52 |
53 | #define TIXML_VSCPRINTF _vscprintf
54 | #define TIXML_SSCANF sscanf_s
55 | #elif defined _MSC_VER
56 | // Microsoft Visual Studio 2003 and earlier or WinCE
57 | #define TIXML_SNPRINTF _snprintf
58 | #define TIXML_VSNPRINTF _vsnprintf
59 | #define TIXML_SSCANF sscanf
60 | #if (_MSC_VER < 1400 ) && (!defined WINCE)
61 | // Microsoft Visual Studio 2003 and not WinCE.
62 | #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
63 | #else
64 | // Microsoft Visual Studio 2003 and earlier or WinCE.
65 | static inline int TIXML_VSCPRINTF(const char* format, va_list va)
66 | {
67 | int len = 512;
68 | for (;;) {
69 | len = len * 2;
70 | char* str = new char[len]();
71 | const int required = _vsnprintf(str, len, format, va);
72 | delete[] str;
73 | if (required != -1) {
74 | TIXMLASSERT(required >= 0);
75 | len = required;
76 | break;
77 | }
78 | }
79 | TIXMLASSERT(len >= 0);
80 | return len;
81 | }
82 | #endif
83 | #else
84 | // GCC version 3 and higher
85 | //#warning( "Using sn* functions." )
86 | #define TIXML_SNPRINTF snprintf
87 | #define TIXML_VSNPRINTF vsnprintf
88 | static inline int TIXML_VSCPRINTF(const char* format, va_list va)
89 | {
90 | int len = vsnprintf(0, 0, format, va);
91 | TIXMLASSERT(len >= 0);
92 | return len;
93 | }
94 | #define TIXML_SSCANF sscanf
95 | #endif
96 |
97 |
98 | static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
99 | static const char LF = LINE_FEED;
100 | static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
101 | static const char CR = CARRIAGE_RETURN;
102 | static const char SINGLE_QUOTE = '\'';
103 | static const char DOUBLE_QUOTE = '\"';
104 |
105 | // Bunch of unicode info at:
106 | // http://www.unicode.org/faq/utf_bom.html
107 | // ef bb bf (Microsoft "lead bytes") - designates UTF-8
108 |
109 | static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
110 | static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
111 | static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
112 |
113 | namespace tinyxml2
114 | {
115 |
116 | struct Entity {
117 | const char* pattern;
118 | int length;
119 | char value;
120 | };
121 |
122 | static const int NUM_ENTITIES = 5;
123 | static const Entity entities[NUM_ENTITIES] = {
124 | { "quot", 4, DOUBLE_QUOTE },
125 | { "amp", 3, '&' },
126 | { "apos", 4, SINGLE_QUOTE },
127 | { "lt", 2, '<' },
128 | { "gt", 2, '>' }
129 | };
130 |
131 |
132 | StrPair::~StrPair()
133 | {
134 | Reset();
135 | }
136 |
137 |
138 | void StrPair::TransferTo(StrPair* other)
139 | {
140 | if (this == other) {
141 | return;
142 | }
143 | // This in effect implements the assignment operator by "moving"
144 | // ownership (as in auto_ptr).
145 |
146 | TIXMLASSERT(other != 0);
147 | TIXMLASSERT(other->_flags == 0);
148 | TIXMLASSERT(other->_start == 0);
149 | TIXMLASSERT(other->_end == 0);
150 |
151 | other->Reset();
152 |
153 | other->_flags = _flags;
154 | other->_start = _start;
155 | other->_end = _end;
156 |
157 | _flags = 0;
158 | _start = 0;
159 | _end = 0;
160 | }
161 |
162 | void StrPair::Reset()
163 | {
164 | if (_flags & NEEDS_DELETE) {
165 | delete[] _start;
166 | }
167 | _flags = 0;
168 | _start = 0;
169 | _end = 0;
170 | }
171 |
172 |
173 | void StrPair::SetStr(const char* str, int flags)
174 | {
175 | TIXMLASSERT(str);
176 | Reset();
177 | size_t len = strlen(str);
178 | TIXMLASSERT(_start == 0);
179 | _start = new char[len + 1];
180 | memcpy(_start, str, len + 1);
181 | _end = _start + len;
182 | _flags = flags | NEEDS_DELETE;
183 | }
184 |
185 |
186 | char* StrPair::ParseText(char* p, const char* endTag, int strFlags)
187 | {
188 | TIXMLASSERT(p);
189 | TIXMLASSERT(endTag && *endTag);
190 |
191 | char* start = p;
192 | char endChar = *endTag;
193 | size_t length = strlen(endTag);
194 |
195 | // Inner loop of text parsing.
196 | while (*p) {
197 | if (*p == endChar && strncmp(p, endTag, length) == 0) {
198 | Set(start, p, strFlags);
199 | return p + length;
200 | }
201 | ++p;
202 | TIXMLASSERT(p);
203 | }
204 | return 0;
205 | }
206 |
207 |
208 | char* StrPair::ParseName(char* p)
209 | {
210 | if (!p || !(*p)) {
211 | return 0;
212 | }
213 | if (!XMLUtil::IsNameStartChar(*p)) {
214 | return 0;
215 | }
216 |
217 | char* const start = p;
218 | ++p;
219 | while (*p && XMLUtil::IsNameChar(*p)) {
220 | ++p;
221 | }
222 |
223 | Set(start, p, 0);
224 | return p;
225 | }
226 |
227 |
228 | void StrPair::CollapseWhitespace()
229 | {
230 | // Adjusting _start would cause undefined behavior on delete[]
231 | TIXMLASSERT((_flags & NEEDS_DELETE) == 0);
232 | // Trim leading space.
233 | _start = XMLUtil::SkipWhiteSpace(_start);
234 |
235 | if (*_start) {
236 | const char* p = _start; // the read pointer
237 | char* q = _start; // the write pointer
238 |
239 | while (*p) {
240 | if (XMLUtil::IsWhiteSpace(*p)) {
241 | p = XMLUtil::SkipWhiteSpace(p);
242 | if (*p == 0) {
243 | break; // don't write to q; this trims the trailing space.
244 | }
245 | *q = ' ';
246 | ++q;
247 | }
248 | *q = *p;
249 | ++q;
250 | ++p;
251 | }
252 | *q = 0;
253 | }
254 | }
255 |
256 |
257 | const char* StrPair::GetStr()
258 | {
259 | TIXMLASSERT(_start);
260 | TIXMLASSERT(_end);
261 | if (_flags & NEEDS_FLUSH) {
262 | *_end = 0;
263 | _flags ^= NEEDS_FLUSH;
264 |
265 | if (_flags) {
266 | const char* p = _start; // the read pointer
267 | char* q = _start; // the write pointer
268 |
269 | while (p < _end) {
270 | if ((_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR) {
271 | // CR-LF pair becomes LF
272 | // CR alone becomes LF
273 | // LF-CR becomes LF
274 | if (*(p + 1) == LF) {
275 | p += 2;
276 | }
277 | else {
278 | ++p;
279 | }
280 | *q = LF;
281 | ++q;
282 | }
283 | else if ((_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF) {
284 | if (*(p + 1) == CR) {
285 | p += 2;
286 | }
287 | else {
288 | ++p;
289 | }
290 | *q = LF;
291 | ++q;
292 | }
293 | else if ((_flags & NEEDS_ENTITY_PROCESSING) && *p == '&') {
294 | // Entities handled by tinyXML2:
295 | // - special entities in the entity table [in/out]
296 | // - numeric character reference [in]
297 | // 中 or 中
298 |
299 | if (*(p + 1) == '#') {
300 | const int buflen = 10;
301 | char buf[buflen] = { 0 };
302 | int len = 0;
303 | char* adjusted = const_cast(XMLUtil::GetCharacterRef(p, buf, &len));
304 | if (adjusted == 0) {
305 | *q = *p;
306 | ++p;
307 | ++q;
308 | }
309 | else {
310 | TIXMLASSERT(0 <= len && len <= buflen);
311 | TIXMLASSERT(q + len <= adjusted);
312 | p = adjusted;
313 | memcpy(q, buf, len);
314 | q += len;
315 | }
316 | }
317 | else {
318 | bool entityFound = false;
319 | for (int i = 0; i < NUM_ENTITIES; ++i) {
320 | const Entity& entity = entities[i];
321 | if (strncmp(p + 1, entity.pattern, entity.length) == 0
322 | && *(p + entity.length + 1) == ';') {
323 | // Found an entity - convert.
324 | *q = entity.value;
325 | ++q;
326 | p += entity.length + 2;
327 | entityFound = true;
328 | break;
329 | }
330 | }
331 | if (!entityFound) {
332 | // fixme: treat as error?
333 | ++p;
334 | ++q;
335 | }
336 | }
337 | }
338 | else {
339 | *q = *p;
340 | ++p;
341 | ++q;
342 | }
343 | }
344 | *q = 0;
345 | }
346 | // The loop below has plenty going on, and this
347 | // is a less useful mode. Break it out.
348 | if (_flags & NEEDS_WHITESPACE_COLLAPSING) {
349 | CollapseWhitespace();
350 | }
351 | _flags = (_flags & NEEDS_DELETE);
352 | }
353 | TIXMLASSERT(_start);
354 | return _start;
355 | }
356 |
357 |
358 |
359 |
360 | // --------- XMLUtil ----------- //
361 |
362 | const char* XMLUtil::ReadBOM(const char* p, bool* bom)
363 | {
364 | TIXMLASSERT(p);
365 | TIXMLASSERT(bom);
366 | *bom = false;
367 | const unsigned char* pu = reinterpret_cast(p);
368 | // Check for BOM:
369 | if (*(pu + 0) == TIXML_UTF_LEAD_0
370 | && *(pu + 1) == TIXML_UTF_LEAD_1
371 | && *(pu + 2) == TIXML_UTF_LEAD_2) {
372 | *bom = true;
373 | p += 3;
374 | }
375 | TIXMLASSERT(p);
376 | return p;
377 | }
378 |
379 |
380 | void XMLUtil::ConvertUTF32ToUTF8(unsigned long input, char* output, int* length)
381 | {
382 | const unsigned long BYTE_MASK = 0xBF;
383 | const unsigned long BYTE_MARK = 0x80;
384 | const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
385 |
386 | if (input < 0x80) {
387 | *length = 1;
388 | }
389 | else if (input < 0x800) {
390 | *length = 2;
391 | }
392 | else if (input < 0x10000) {
393 | *length = 3;
394 | }
395 | else if (input < 0x200000) {
396 | *length = 4;
397 | }
398 | else {
399 | *length = 0; // This code won't convert this correctly anyway.
400 | return;
401 | }
402 |
403 | output += *length;
404 |
405 | // Scary scary fall throughs.
406 | switch (*length) {
407 | case 4:
408 | --output;
409 | *output = (char)((input | BYTE_MARK) & BYTE_MASK);
410 | input >>= 6;
411 | case 3:
412 | --output;
413 | *output = (char)((input | BYTE_MARK) & BYTE_MASK);
414 | input >>= 6;
415 | case 2:
416 | --output;
417 | *output = (char)((input | BYTE_MARK) & BYTE_MASK);
418 | input >>= 6;
419 | case 1:
420 | --output;
421 | *output = (char)(input | FIRST_BYTE_MARK[*length]);
422 | break;
423 | default:
424 | TIXMLASSERT(false);
425 | }
426 | }
427 |
428 |
429 | const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length)
430 | {
431 | // Presume an entity, and pull it out.
432 | *length = 0;
433 |
434 | if (*(p + 1) == '#' && *(p + 2)) {
435 | unsigned long ucs = 0;
436 | TIXMLASSERT(sizeof(ucs) >= 4);
437 | ptrdiff_t delta = 0;
438 | unsigned mult = 1;
439 | static const char SEMICOLON = ';';
440 |
441 | if (*(p + 2) == 'x') {
442 | // Hexadecimal.
443 | const char* q = p + 3;
444 | if (!(*q)) {
445 | return 0;
446 | }
447 |
448 | q = strchr(q, SEMICOLON);
449 |
450 | if (!q) {
451 | return 0;
452 | }
453 | TIXMLASSERT(*q == SEMICOLON);
454 |
455 | delta = q - p;
456 | --q;
457 |
458 | while (*q != 'x') {
459 | unsigned int digit = 0;
460 |
461 | if (*q >= '0' && *q <= '9') {
462 | digit = *q - '0';
463 | }
464 | else if (*q >= 'a' && *q <= 'f') {
465 | digit = *q - 'a' + 10;
466 | }
467 | else if (*q >= 'A' && *q <= 'F') {
468 | digit = *q - 'A' + 10;
469 | }
470 | else {
471 | return 0;
472 | }
473 | TIXMLASSERT(digit < 16);
474 | TIXMLASSERT(digit == 0 || mult <= UINT_MAX / digit);
475 | const unsigned int digitScaled = mult * digit;
476 | TIXMLASSERT(ucs <= ULONG_MAX - digitScaled);
477 | ucs += digitScaled;
478 | TIXMLASSERT(mult <= UINT_MAX / 16);
479 | mult *= 16;
480 | --q;
481 | }
482 | }
483 | else {
484 | // Decimal.
485 | const char* q = p + 2;
486 | if (!(*q)) {
487 | return 0;
488 | }
489 |
490 | q = strchr(q, SEMICOLON);
491 |
492 | if (!q) {
493 | return 0;
494 | }
495 | TIXMLASSERT(*q == SEMICOLON);
496 |
497 | delta = q - p;
498 | --q;
499 |
500 | while (*q != '#') {
501 | if (*q >= '0' && *q <= '9') {
502 | const unsigned int digit = *q - '0';
503 | TIXMLASSERT(digit < 10);
504 | TIXMLASSERT(digit == 0 || mult <= UINT_MAX / digit);
505 | const unsigned int digitScaled = mult * digit;
506 | TIXMLASSERT(ucs <= ULONG_MAX - digitScaled);
507 | ucs += digitScaled;
508 | }
509 | else {
510 | return 0;
511 | }
512 | TIXMLASSERT(mult <= UINT_MAX / 10);
513 | mult *= 10;
514 | --q;
515 | }
516 | }
517 | // convert the UCS to UTF-8
518 | ConvertUTF32ToUTF8(ucs, value, length);
519 | return p + delta + 1;
520 | }
521 | return p + 1;
522 | }
523 |
524 |
525 | void XMLUtil::ToStr(int v, char* buffer, int bufferSize)
526 | {
527 | TIXML_SNPRINTF(buffer, bufferSize, "%d", v);
528 | }
529 |
530 |
531 | void XMLUtil::ToStr(unsigned v, char* buffer, int bufferSize)
532 | {
533 | TIXML_SNPRINTF(buffer, bufferSize, "%u", v);
534 | }
535 |
536 |
537 | void XMLUtil::ToStr(bool v, char* buffer, int bufferSize)
538 | {
539 | TIXML_SNPRINTF(buffer, bufferSize, "%s", v ? "true" : "false");
540 | }
541 |
542 | /*
543 | ToStr() of a number is a very tricky topic.
544 | https://github.com/leethomason/tinyxml2/issues/106
545 | */
546 | void XMLUtil::ToStr(float v, char* buffer, int bufferSize)
547 | {
548 | TIXML_SNPRINTF(buffer, bufferSize, "%.8g", v);
549 | }
550 |
551 |
552 | void XMLUtil::ToStr(double v, char* buffer, int bufferSize)
553 | {
554 | TIXML_SNPRINTF(buffer, bufferSize, "%.17g", v);
555 | }
556 |
557 |
558 | void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
559 | {
560 | // horrible syntax trick to make the compiler happy about %lld
561 | TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
562 | }
563 |
564 |
565 | bool XMLUtil::ToInt(const char* str, int* value)
566 | {
567 | if (TIXML_SSCANF(str, "%d", value) == 1) {
568 | return true;
569 | }
570 | return false;
571 | }
572 |
573 | bool XMLUtil::ToUnsigned(const char* str, unsigned *value)
574 | {
575 | if (TIXML_SSCANF(str, "%u", value) == 1) {
576 | return true;
577 | }
578 | return false;
579 | }
580 |
581 | bool XMLUtil::ToBool(const char* str, bool* value)
582 | {
583 | int ival = 0;
584 | if (ToInt(str, &ival)) {
585 | *value = (ival == 0) ? false : true;
586 | return true;
587 | }
588 | if (StringEqual(str, "true")) {
589 | *value = true;
590 | return true;
591 | }
592 | else if (StringEqual(str, "false")) {
593 | *value = false;
594 | return true;
595 | }
596 | return false;
597 | }
598 |
599 |
600 | bool XMLUtil::ToFloat(const char* str, float* value)
601 | {
602 | if (TIXML_SSCANF(str, "%f", value) == 1) {
603 | return true;
604 | }
605 | return false;
606 | }
607 |
608 |
609 | bool XMLUtil::ToDouble(const char* str, double* value)
610 | {
611 | if (TIXML_SSCANF(str, "%lf", value) == 1) {
612 | return true;
613 | }
614 | return false;
615 | }
616 |
617 |
618 | bool XMLUtil::ToInt64(const char* str, int64_t* value)
619 | {
620 | long long v = 0; // horrible syntax trick to make the compiler happy about %lld
621 | if (TIXML_SSCANF(str, "%lld", &v) == 1) {
622 | *value = (int64_t)v;
623 | return true;
624 | }
625 | return false;
626 | }
627 |
628 |
629 | char* XMLDocument::Identify(char* p, XMLNode** node)
630 | {
631 | TIXMLASSERT(node);
632 | TIXMLASSERT(p);
633 | char* const start = p;
634 | p = XMLUtil::SkipWhiteSpace(p);
635 | if (!*p) {
636 | *node = 0;
637 | TIXMLASSERT(p);
638 | return p;
639 | }
640 |
641 | // These strings define the matching patterns:
642 | static const char* xmlHeader = { "" };
643 | static const char* commentHeader = { "
945 | //
946 | // With a special case:
947 | //
948 | //
949 | //
950 | //
951 | // Where the closing element (/foo) *must* be the next thing after the opening
952 | // element, and the names must match. BUT the tricky bit is that the closing
953 | // element will be read by the child.
954 | //
955 | // 'endTag' is the end tag for this node, it is returned by a call to a child.
956 | // 'parentEnd' is the end tag for the parent, which is filled in and returned.
957 |
958 | while (p && *p) {
959 | XMLNode* node = 0;
960 |
961 | p = _document->Identify(p, &node);
962 | TIXMLASSERT(p);
963 | if (node == 0) {
964 | break;
965 | }
966 |
967 | StrPair endTag;
968 | p = node->ParseDeep(p, &endTag);
969 | if (!p) {
970 | DeleteNode(node);
971 | if (!_document->Error()) {
972 | _document->SetError(XML_ERROR_PARSING, 0, 0);
973 | }
974 | break;
975 | }
976 |
977 | XMLDeclaration* decl = node->ToDeclaration();
978 | if (decl) {
979 | // Declarations are only allowed at document level
980 | bool wellLocated = (ToDocument() != 0);
981 | if (wellLocated) {
982 | // Multiple declarations are allowed but all declarations
983 | // must occur before anything else
984 | for (const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling()) {
985 | if (!existingNode->ToDeclaration()) {
986 | wellLocated = false;
987 | break;
988 | }
989 | }
990 | }
991 | if (!wellLocated) {
992 | _document->SetError(XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
993 | DeleteNode(node);
994 | break;
995 | }
996 | }
997 |
998 | XMLElement* ele = node->ToElement();
999 | if (ele) {
1000 | // We read the end tag. Return it to the parent.
1001 | if (ele->ClosingType() == XMLElement::CLOSING) {
1002 | if (parentEnd) {
1003 | ele->_value.TransferTo(parentEnd);
1004 | }
1005 | node->_memPool->SetTracked(); // created and then immediately deleted.
1006 | DeleteNode(node);
1007 | return p;
1008 | }
1009 |
1010 | // Handle an end tag returned to this level.
1011 | // And handle a bunch of annoying errors.
1012 | bool mismatch = false;
1013 | if (endTag.Empty()) {
1014 | if (ele->ClosingType() == XMLElement::OPEN) {
1015 | mismatch = true;
1016 | }
1017 | }
1018 | else {
1019 | if (ele->ClosingType() != XMLElement::OPEN) {
1020 | mismatch = true;
1021 | }
1022 | else if (!XMLUtil::StringEqual(endTag.GetStr(), ele->Name())) {
1023 | mismatch = true;
1024 | }
1025 | }
1026 | if (mismatch) {
1027 | _document->SetError(XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0);
1028 | DeleteNode(node);
1029 | break;
1030 | }
1031 | }
1032 | InsertEndChild(node);
1033 | }
1034 | return 0;
1035 | }
1036 |
1037 | void XMLNode::DeleteNode(XMLNode* node)
1038 | {
1039 | if (node == 0) {
1040 | return;
1041 | }
1042 | MemPool* pool = node->_memPool;
1043 | node->~XMLNode();
1044 | pool->Free(node);
1045 | }
1046 |
1047 | void XMLNode::InsertChildPreamble(XMLNode* insertThis) const
1048 | {
1049 | TIXMLASSERT(insertThis);
1050 | TIXMLASSERT(insertThis->_document == _document);
1051 |
1052 | if (insertThis->_parent)
1053 | insertThis->_parent->Unlink(insertThis);
1054 | else
1055 | insertThis->_memPool->SetTracked();
1056 | }
1057 |
1058 | const XMLElement* XMLNode::ToElementWithName(const char* name) const
1059 | {
1060 | const XMLElement* element = this->ToElement();
1061 | if (element == 0) {
1062 | return 0;
1063 | }
1064 | if (name == 0) {
1065 | return element;
1066 | }
1067 | if (XMLUtil::StringEqual(element->Name(), name)) {
1068 | return element;
1069 | }
1070 | return 0;
1071 | }
1072 |
1073 | // --------- XMLText ---------- //
1074 | char* XMLText::ParseDeep(char* p, StrPair*)
1075 | {
1076 | const char* start = p;
1077 | if (this->CData()) {
1078 | p = _value.ParseText(p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION);
1079 | if (!p) {
1080 | _document->SetError(XML_ERROR_PARSING_CDATA, start, 0);
1081 | }
1082 | return p;
1083 | }
1084 | else {
1085 | int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1086 | if (_document->WhitespaceMode() == COLLAPSE_WHITESPACE) {
1087 | flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1088 | }
1089 |
1090 | p = _value.ParseText(p, "<", flags);
1091 | if (p && *p) {
1092 | return p - 1;
1093 | }
1094 | if (!p) {
1095 | _document->SetError(XML_ERROR_PARSING_TEXT, start, 0);
1096 | }
1097 | }
1098 | return 0;
1099 | }
1100 |
1101 |
1102 | XMLNode* XMLText::ShallowClone(XMLDocument* doc) const
1103 | {
1104 | if (!doc) {
1105 | doc = _document;
1106 | }
1107 | XMLText* text = doc->NewText(Value()); // fixme: this will always allocate memory. Intern?
1108 | text->SetCData(this->CData());
1109 | return text;
1110 | }
1111 |
1112 |
1113 | bool XMLText::ShallowEqual(const XMLNode* compare) const
1114 | {
1115 | const XMLText* text = compare->ToText();
1116 | return (text && XMLUtil::StringEqual(text->Value(), Value()));
1117 | }
1118 |
1119 |
1120 | bool XMLText::Accept(XMLVisitor* visitor) const
1121 | {
1122 | TIXMLASSERT(visitor);
1123 | return visitor->Visit(*this);
1124 | }
1125 |
1126 |
1127 | // --------- XMLComment ---------- //
1128 |
1129 | XMLComment::XMLComment(XMLDocument* doc) : XMLNode(doc)
1130 | {
1131 | }
1132 |
1133 |
1134 | XMLComment::~XMLComment()
1135 | {
1136 | }
1137 |
1138 |
1139 | char* XMLComment::ParseDeep(char* p, StrPair*)
1140 | {
1141 | // Comment parses as text.
1142 | const char* start = p;
1143 | p = _value.ParseText(p, "-->", StrPair::COMMENT);
1144 | if (p == 0) {
1145 | _document->SetError(XML_ERROR_PARSING_COMMENT, start, 0);
1146 | }
1147 | return p;
1148 | }
1149 |
1150 |
1151 | XMLNode* XMLComment::ShallowClone(XMLDocument* doc) const
1152 | {
1153 | if (!doc) {
1154 | doc = _document;
1155 | }
1156 | XMLComment* comment = doc->NewComment(Value()); // fixme: this will always allocate memory. Intern?
1157 | return comment;
1158 | }
1159 |
1160 |
1161 | bool XMLComment::ShallowEqual(const XMLNode* compare) const
1162 | {
1163 | TIXMLASSERT(compare);
1164 | const XMLComment* comment = compare->ToComment();
1165 | return (comment && XMLUtil::StringEqual(comment->Value(), Value()));
1166 | }
1167 |
1168 |
1169 | bool XMLComment::Accept(XMLVisitor* visitor) const
1170 | {
1171 | TIXMLASSERT(visitor);
1172 | return visitor->Visit(*this);
1173 | }
1174 |
1175 |
1176 | // --------- XMLDeclaration ---------- //
1177 |
1178 | XMLDeclaration::XMLDeclaration(XMLDocument* doc) : XMLNode(doc)
1179 | {
1180 | }
1181 |
1182 |
1183 | XMLDeclaration::~XMLDeclaration()
1184 | {
1185 | //printf( "~XMLDeclaration\n" );
1186 | }
1187 |
1188 |
1189 | char* XMLDeclaration::ParseDeep(char* p, StrPair*)
1190 | {
1191 | // Declaration parses as text.
1192 | const char* start = p;
1193 | p = _value.ParseText(p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION);
1194 | if (p == 0) {
1195 | _document->SetError(XML_ERROR_PARSING_DECLARATION, start, 0);
1196 | }
1197 | return p;
1198 | }
1199 |
1200 |
1201 | XMLNode* XMLDeclaration::ShallowClone(XMLDocument* doc) const
1202 | {
1203 | if (!doc) {
1204 | doc = _document;
1205 | }
1206 | XMLDeclaration* dec = doc->NewDeclaration(Value()); // fixme: this will always allocate memory. Intern?
1207 | return dec;
1208 | }
1209 |
1210 |
1211 | bool XMLDeclaration::ShallowEqual(const XMLNode* compare) const
1212 | {
1213 | TIXMLASSERT(compare);
1214 | const XMLDeclaration* declaration = compare->ToDeclaration();
1215 | return (declaration && XMLUtil::StringEqual(declaration->Value(), Value()));
1216 | }
1217 |
1218 |
1219 |
1220 | bool XMLDeclaration::Accept(XMLVisitor* visitor) const
1221 | {
1222 | TIXMLASSERT(visitor);
1223 | return visitor->Visit(*this);
1224 | }
1225 |
1226 | // --------- XMLUnknown ---------- //
1227 |
1228 | XMLUnknown::XMLUnknown(XMLDocument* doc) : XMLNode(doc)
1229 | {
1230 | }
1231 |
1232 |
1233 | XMLUnknown::~XMLUnknown()
1234 | {
1235 | }
1236 |
1237 |
1238 | char* XMLUnknown::ParseDeep(char* p, StrPair*)
1239 | {
1240 | // Unknown parses as text.
1241 | const char* start = p;
1242 |
1243 | p = _value.ParseText(p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION);
1244 | if (!p) {
1245 | _document->SetError(XML_ERROR_PARSING_UNKNOWN, start, 0);
1246 | }
1247 | return p;
1248 | }
1249 |
1250 |
1251 | XMLNode* XMLUnknown::ShallowClone(XMLDocument* doc) const
1252 | {
1253 | if (!doc) {
1254 | doc = _document;
1255 | }
1256 | XMLUnknown* text = doc->NewUnknown(Value()); // fixme: this will always allocate memory. Intern?
1257 | return text;
1258 | }
1259 |
1260 |
1261 | bool XMLUnknown::ShallowEqual(const XMLNode* compare) const
1262 | {
1263 | TIXMLASSERT(compare);
1264 | const XMLUnknown* unknown = compare->ToUnknown();
1265 | return (unknown && XMLUtil::StringEqual(unknown->Value(), Value()));
1266 | }
1267 |
1268 |
1269 | bool XMLUnknown::Accept(XMLVisitor* visitor) const
1270 | {
1271 | TIXMLASSERT(visitor);
1272 | return visitor->Visit(*this);
1273 | }
1274 |
1275 | // --------- XMLAttribute ---------- //
1276 |
1277 | const char* XMLAttribute::Name() const
1278 | {
1279 | return _name.GetStr();
1280 | }
1281 |
1282 | const char* XMLAttribute::Value() const
1283 | {
1284 | return _value.GetStr();
1285 | }
1286 |
1287 | char* XMLAttribute::ParseDeep(char* p, bool processEntities)
1288 | {
1289 | // Parse using the name rules: bug fix, was using ParseText before
1290 | p = _name.ParseName(p);
1291 | if (!p || !*p) {
1292 | return 0;
1293 | }
1294 |
1295 | // Skip white space before =
1296 | p = XMLUtil::SkipWhiteSpace(p);
1297 | if (*p != '=') {
1298 | return 0;
1299 | }
1300 |
1301 | ++p; // move up to opening quote
1302 | p = XMLUtil::SkipWhiteSpace(p);
1303 | if (*p != '\"' && *p != '\'') {
1304 | return 0;
1305 | }
1306 |
1307 | char endTag[2] = { *p, 0 };
1308 | ++p; // move past opening quote
1309 |
1310 | p = _value.ParseText(p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES);
1311 | return p;
1312 | }
1313 |
1314 |
1315 | void XMLAttribute::SetName(const char* n)
1316 | {
1317 | _name.SetStr(n);
1318 | }
1319 |
1320 |
1321 | XMLError XMLAttribute::QueryIntValue(int* value) const
1322 | {
1323 | if (XMLUtil::ToInt(Value(), value)) {
1324 | return XML_SUCCESS;
1325 | }
1326 | return XML_WRONG_ATTRIBUTE_TYPE;
1327 | }
1328 |
1329 |
1330 | XMLError XMLAttribute::QueryUnsignedValue(unsigned int* value) const
1331 | {
1332 | if (XMLUtil::ToUnsigned(Value(), value)) {
1333 | return XML_SUCCESS;
1334 | }
1335 | return XML_WRONG_ATTRIBUTE_TYPE;
1336 | }
1337 |
1338 |
1339 | XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1340 | {
1341 | if (XMLUtil::ToInt64(Value(), value)) {
1342 | return XML_SUCCESS;
1343 | }
1344 | return XML_WRONG_ATTRIBUTE_TYPE;
1345 | }
1346 |
1347 |
1348 | XMLError XMLAttribute::QueryBoolValue(bool* value) const
1349 | {
1350 | if (XMLUtil::ToBool(Value(), value)) {
1351 | return XML_SUCCESS;
1352 | }
1353 | return XML_WRONG_ATTRIBUTE_TYPE;
1354 | }
1355 |
1356 |
1357 | XMLError XMLAttribute::QueryFloatValue(float* value) const
1358 | {
1359 | if (XMLUtil::ToFloat(Value(), value)) {
1360 | return XML_SUCCESS;
1361 | }
1362 | return XML_WRONG_ATTRIBUTE_TYPE;
1363 | }
1364 |
1365 |
1366 | XMLError XMLAttribute::QueryDoubleValue(double* value) const
1367 | {
1368 | if (XMLUtil::ToDouble(Value(), value)) {
1369 | return XML_SUCCESS;
1370 | }
1371 | return XML_WRONG_ATTRIBUTE_TYPE;
1372 | }
1373 |
1374 |
1375 | void XMLAttribute::SetAttribute(const char* v)
1376 | {
1377 | _value.SetStr(v);
1378 | }
1379 |
1380 |
1381 | void XMLAttribute::SetAttribute(int v)
1382 | {
1383 | char buf[BUF_SIZE];
1384 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1385 | _value.SetStr(buf);
1386 | }
1387 |
1388 |
1389 | void XMLAttribute::SetAttribute(unsigned v)
1390 | {
1391 | char buf[BUF_SIZE];
1392 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1393 | _value.SetStr(buf);
1394 | }
1395 |
1396 |
1397 | void XMLAttribute::SetAttribute(int64_t v)
1398 | {
1399 | char buf[BUF_SIZE];
1400 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1401 | _value.SetStr(buf);
1402 | }
1403 |
1404 |
1405 |
1406 | void XMLAttribute::SetAttribute(bool v)
1407 | {
1408 | char buf[BUF_SIZE];
1409 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1410 | _value.SetStr(buf);
1411 | }
1412 |
1413 | void XMLAttribute::SetAttribute(double v)
1414 | {
1415 | char buf[BUF_SIZE];
1416 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1417 | _value.SetStr(buf);
1418 | }
1419 |
1420 | void XMLAttribute::SetAttribute(float v)
1421 | {
1422 | char buf[BUF_SIZE];
1423 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1424 | _value.SetStr(buf);
1425 | }
1426 |
1427 |
1428 | // --------- XMLElement ---------- //
1429 | XMLElement::XMLElement(XMLDocument* doc) : XMLNode(doc),
1430 | _closingType(0),
1431 | _rootAttribute(0)
1432 | {
1433 | }
1434 |
1435 |
1436 | XMLElement::~XMLElement()
1437 | {
1438 | while (_rootAttribute) {
1439 | XMLAttribute* next = _rootAttribute->_next;
1440 | DeleteAttribute(_rootAttribute);
1441 | _rootAttribute = next;
1442 | }
1443 | }
1444 |
1445 |
1446 | const XMLAttribute* XMLElement::FindAttribute(const char* name) const
1447 | {
1448 | for (XMLAttribute* a = _rootAttribute; a; a = a->_next) {
1449 | if (XMLUtil::StringEqual(a->Name(), name)) {
1450 | return a;
1451 | }
1452 | }
1453 | return 0;
1454 | }
1455 |
1456 |
1457 | const char* XMLElement::Attribute(const char* name, const char* value) const
1458 | {
1459 | const XMLAttribute* a = FindAttribute(name);
1460 | if (!a) {
1461 | return 0;
1462 | }
1463 | if (!value || XMLUtil::StringEqual(a->Value(), value)) {
1464 | return a->Value();
1465 | }
1466 | return 0;
1467 | }
1468 |
1469 | int XMLElement::IntAttribute(const char* name, int defaultValue) const
1470 | {
1471 | int i = defaultValue;
1472 | QueryIntAttribute(name, &i);
1473 | return i;
1474 | }
1475 |
1476 | unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1477 | {
1478 | unsigned i = defaultValue;
1479 | QueryUnsignedAttribute(name, &i);
1480 | return i;
1481 | }
1482 |
1483 | int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1484 | {
1485 | int64_t i = defaultValue;
1486 | QueryInt64Attribute(name, &i);
1487 | return i;
1488 | }
1489 |
1490 | bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1491 | {
1492 | bool b = defaultValue;
1493 | QueryBoolAttribute(name, &b);
1494 | return b;
1495 | }
1496 |
1497 | double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1498 | {
1499 | double d = defaultValue;
1500 | QueryDoubleAttribute(name, &d);
1501 | return d;
1502 | }
1503 |
1504 | float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1505 | {
1506 | float f = defaultValue;
1507 | QueryFloatAttribute(name, &f);
1508 | return f;
1509 | }
1510 |
1511 | const char* XMLElement::GetText() const
1512 | {
1513 | if (FirstChild() && FirstChild()->ToText()) {
1514 | return FirstChild()->Value();
1515 | }
1516 | return 0;
1517 | }
1518 |
1519 |
1520 | void XMLElement::SetText(const char* inText)
1521 | {
1522 | if (FirstChild() && FirstChild()->ToText())
1523 | FirstChild()->SetValue(inText);
1524 | else {
1525 | XMLText* theText = GetDocument()->NewText(inText);
1526 | InsertFirstChild(theText);
1527 | }
1528 | }
1529 |
1530 |
1531 | void XMLElement::SetText(int v)
1532 | {
1533 | char buf[BUF_SIZE];
1534 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1535 | SetText(buf);
1536 | }
1537 |
1538 |
1539 | void XMLElement::SetText(unsigned v)
1540 | {
1541 | char buf[BUF_SIZE];
1542 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1543 | SetText(buf);
1544 | }
1545 |
1546 |
1547 | void XMLElement::SetText(int64_t v)
1548 | {
1549 | char buf[BUF_SIZE];
1550 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1551 | SetText(buf);
1552 | }
1553 |
1554 |
1555 | void XMLElement::SetText(bool v)
1556 | {
1557 | char buf[BUF_SIZE];
1558 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1559 | SetText(buf);
1560 | }
1561 |
1562 |
1563 | void XMLElement::SetText(float v)
1564 | {
1565 | char buf[BUF_SIZE];
1566 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1567 | SetText(buf);
1568 | }
1569 |
1570 |
1571 | void XMLElement::SetText(double v)
1572 | {
1573 | char buf[BUF_SIZE];
1574 | XMLUtil::ToStr(v, buf, BUF_SIZE);
1575 | SetText(buf);
1576 | }
1577 |
1578 |
1579 | XMLError XMLElement::QueryIntText(int* ival) const
1580 | {
1581 | if (FirstChild() && FirstChild()->ToText()) {
1582 | const char* t = FirstChild()->Value();
1583 | if (XMLUtil::ToInt(t, ival)) {
1584 | return XML_SUCCESS;
1585 | }
1586 | return XML_CAN_NOT_CONVERT_TEXT;
1587 | }
1588 | return XML_NO_TEXT_NODE;
1589 | }
1590 |
1591 |
1592 | XMLError XMLElement::QueryUnsignedText(unsigned* uval) const
1593 | {
1594 | if (FirstChild() && FirstChild()->ToText()) {
1595 | const char* t = FirstChild()->Value();
1596 | if (XMLUtil::ToUnsigned(t, uval)) {
1597 | return XML_SUCCESS;
1598 | }
1599 | return XML_CAN_NOT_CONVERT_TEXT;
1600 | }
1601 | return XML_NO_TEXT_NODE;
1602 | }
1603 |
1604 |
1605 | XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1606 | {
1607 | if (FirstChild() && FirstChild()->ToText()) {
1608 | const char* t = FirstChild()->Value();
1609 | if (XMLUtil::ToInt64(t, ival)) {
1610 | return XML_SUCCESS;
1611 | }
1612 | return XML_CAN_NOT_CONVERT_TEXT;
1613 | }
1614 | return XML_NO_TEXT_NODE;
1615 | }
1616 |
1617 |
1618 | XMLError XMLElement::QueryBoolText(bool* bval) const
1619 | {
1620 | if (FirstChild() && FirstChild()->ToText()) {
1621 | const char* t = FirstChild()->Value();
1622 | if (XMLUtil::ToBool(t, bval)) {
1623 | return XML_SUCCESS;
1624 | }
1625 | return XML_CAN_NOT_CONVERT_TEXT;
1626 | }
1627 | return XML_NO_TEXT_NODE;
1628 | }
1629 |
1630 |
1631 | XMLError XMLElement::QueryDoubleText(double* dval) const
1632 | {
1633 | if (FirstChild() && FirstChild()->ToText()) {
1634 | const char* t = FirstChild()->Value();
1635 | if (XMLUtil::ToDouble(t, dval)) {
1636 | return XML_SUCCESS;
1637 | }
1638 | return XML_CAN_NOT_CONVERT_TEXT;
1639 | }
1640 | return XML_NO_TEXT_NODE;
1641 | }
1642 |
1643 |
1644 | XMLError XMLElement::QueryFloatText(float* fval) const
1645 | {
1646 | if (FirstChild() && FirstChild()->ToText()) {
1647 | const char* t = FirstChild()->Value();
1648 | if (XMLUtil::ToFloat(t, fval)) {
1649 | return XML_SUCCESS;
1650 | }
1651 | return XML_CAN_NOT_CONVERT_TEXT;
1652 | }
1653 | return XML_NO_TEXT_NODE;
1654 | }
1655 |
1656 | int XMLElement::IntText(int defaultValue) const
1657 | {
1658 | int i = defaultValue;
1659 | QueryIntText(&i);
1660 | return i;
1661 | }
1662 |
1663 | unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1664 | {
1665 | unsigned i = defaultValue;
1666 | QueryUnsignedText(&i);
1667 | return i;
1668 | }
1669 |
1670 | int64_t XMLElement::Int64Text(int64_t defaultValue) const
1671 | {
1672 | int64_t i = defaultValue;
1673 | QueryInt64Text(&i);
1674 | return i;
1675 | }
1676 |
1677 | bool XMLElement::BoolText(bool defaultValue) const
1678 | {
1679 | bool b = defaultValue;
1680 | QueryBoolText(&b);
1681 | return b;
1682 | }
1683 |
1684 | double XMLElement::DoubleText(double defaultValue) const
1685 | {
1686 | double d = defaultValue;
1687 | QueryDoubleText(&d);
1688 | return d;
1689 | }
1690 |
1691 | float XMLElement::FloatText(float defaultValue) const
1692 | {
1693 | float f = defaultValue;
1694 | QueryFloatText(&f);
1695 | return f;
1696 | }
1697 |
1698 |
1699 | XMLAttribute* XMLElement::FindOrCreateAttribute(const char* name)
1700 | {
1701 | XMLAttribute* last = 0;
1702 | XMLAttribute* attrib = 0;
1703 | for (attrib = _rootAttribute;
1704 | attrib;
1705 | last = attrib, attrib = attrib->_next) {
1706 | if (XMLUtil::StringEqual(attrib->Name(), name)) {
1707 | break;
1708 | }
1709 | }
1710 | if (!attrib) {
1711 | attrib = CreateAttribute();
1712 | TIXMLASSERT(attrib);
1713 | if (last) {
1714 | last->_next = attrib;
1715 | }
1716 | else {
1717 | _rootAttribute = attrib;
1718 | }
1719 | attrib->SetName(name);
1720 | }
1721 | return attrib;
1722 | }
1723 |
1724 |
1725 | void XMLElement::DeleteAttribute(const char* name)
1726 | {
1727 | XMLAttribute* prev = 0;
1728 | for (XMLAttribute* a = _rootAttribute; a; a = a->_next) {
1729 | if (XMLUtil::StringEqual(name, a->Name())) {
1730 | if (prev) {
1731 | prev->_next = a->_next;
1732 | }
1733 | else {
1734 | _rootAttribute = a->_next;
1735 | }
1736 | DeleteAttribute(a);
1737 | break;
1738 | }
1739 | prev = a;
1740 | }
1741 | }
1742 |
1743 |
1744 | char* XMLElement::ParseAttributes(char* p)
1745 | {
1746 | const char* start = p;
1747 | XMLAttribute* prevAttribute = 0;
1748 |
1749 | // Read the attributes.
1750 | while (p) {
1751 | p = XMLUtil::SkipWhiteSpace(p);
1752 | if (!(*p)) {
1753 | _document->SetError(XML_ERROR_PARSING_ELEMENT, start, Name());
1754 | return 0;
1755 | }
1756 |
1757 | // attribute.
1758 | if (XMLUtil::IsNameStartChar(*p)) {
1759 | XMLAttribute* attrib = CreateAttribute();
1760 | TIXMLASSERT(attrib);
1761 |
1762 | p = attrib->ParseDeep(p, _document->ProcessEntities());
1763 | if (!p || Attribute(attrib->Name())) {
1764 | DeleteAttribute(attrib);
1765 | _document->SetError(XML_ERROR_PARSING_ATTRIBUTE, start, p);
1766 | return 0;
1767 | }
1768 | // There is a minor bug here: if the attribute in the source xml
1769 | // document is duplicated, it will not be detected and the
1770 | // attribute will be doubly added. However, tracking the 'prevAttribute'
1771 | // avoids re-scanning the attribute list. Preferring performance for
1772 | // now, may reconsider in the future.
1773 | if (prevAttribute) {
1774 | prevAttribute->_next = attrib;
1775 | }
1776 | else {
1777 | _rootAttribute = attrib;
1778 | }
1779 | prevAttribute = attrib;
1780 | }
1781 | // end of the tag
1782 | else if (*p == '>') {
1783 | ++p;
1784 | break;
1785 | }
1786 | // end of the tag
1787 | else if (*p == '/' && *(p + 1) == '>') {
1788 | _closingType = CLOSED;
1789 | return p + 2; // done; sealed element.
1790 | }
1791 | else {
1792 | _document->SetError(XML_ERROR_PARSING_ELEMENT, start, p);
1793 | return 0;
1794 | }
1795 | }
1796 | return p;
1797 | }
1798 |
1799 | void XMLElement::DeleteAttribute(XMLAttribute* attribute)
1800 | {
1801 | if (attribute == 0) {
1802 | return;
1803 | }
1804 | MemPool* pool = attribute->_memPool;
1805 | attribute->~XMLAttribute();
1806 | pool->Free(attribute);
1807 | }
1808 |
1809 | XMLAttribute* XMLElement::CreateAttribute()
1810 | {
1811 | TIXMLASSERT(sizeof(XMLAttribute) == _document->_attributePool.ItemSize());
1812 | XMLAttribute* attrib = new (_document->_attributePool.Alloc()) XMLAttribute();
1813 | attrib->_memPool = &_document->_attributePool;
1814 | attrib->_memPool->SetTracked();
1815 | return attrib;
1816 | }
1817 |
1818 | //
1819 | //
1820 | // foobar
1821 | //
1822 | char* XMLElement::ParseDeep(char* p, StrPair* strPair)
1823 | {
1824 | // Read the element name.
1825 | p = XMLUtil::SkipWhiteSpace(p);
1826 |
1827 | // The closing element is the form. It is
1828 | // parsed just like a regular element then deleted from
1829 | // the DOM.
1830 | if (*p == '/') {
1831 | _closingType = CLOSING;
1832 | ++p;
1833 | }
1834 |
1835 | p = _value.ParseName(p);
1836 | if (_value.Empty()) {
1837 | return 0;
1838 | }
1839 |
1840 | p = ParseAttributes(p);
1841 | if (!p || !*p || _closingType) {
1842 | return p;
1843 | }
1844 |
1845 | p = XMLNode::ParseDeep(p, strPair);
1846 | return p;
1847 | }
1848 |
1849 |
1850 |
1851 | XMLNode* XMLElement::ShallowClone(XMLDocument* doc) const
1852 | {
1853 | if (!doc) {
1854 | doc = _document;
1855 | }
1856 | XMLElement* element = doc->NewElement(Value()); // fixme: this will always allocate memory. Intern?
1857 | for (const XMLAttribute* a = FirstAttribute(); a; a = a->Next()) {
1858 | element->SetAttribute(a->Name(), a->Value()); // fixme: this will always allocate memory. Intern?
1859 | }
1860 | return element;
1861 | }
1862 |
1863 |
1864 | bool XMLElement::ShallowEqual(const XMLNode* compare) const
1865 | {
1866 | TIXMLASSERT(compare);
1867 | const XMLElement* other = compare->ToElement();
1868 | if (other && XMLUtil::StringEqual(other->Name(), Name())) {
1869 |
1870 | const XMLAttribute* a = FirstAttribute();
1871 | const XMLAttribute* b = other->FirstAttribute();
1872 |
1873 | while (a && b) {
1874 | if (!XMLUtil::StringEqual(a->Value(), b->Value())) {
1875 | return false;
1876 | }
1877 | a = a->Next();
1878 | b = b->Next();
1879 | }
1880 | if (a || b) {
1881 | // different count
1882 | return false;
1883 | }
1884 | return true;
1885 | }
1886 | return false;
1887 | }
1888 |
1889 |
1890 | bool XMLElement::Accept(XMLVisitor* visitor) const
1891 | {
1892 | TIXMLASSERT(visitor);
1893 | if (visitor->VisitEnter(*this, _rootAttribute)) {
1894 | for (const XMLNode* node = FirstChild(); node; node = node->NextSibling()) {
1895 | if (!node->Accept(visitor)) {
1896 | break;
1897 | }
1898 | }
1899 | }
1900 | return visitor->VisitExit(*this);
1901 | }
1902 |
1903 |
1904 | // --------- XMLDocument ----------- //
1905 |
1906 | // Warning: List must match 'enum XMLError'
1907 | const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1908 | "XML_SUCCESS",
1909 | "XML_NO_ATTRIBUTE",
1910 | "XML_WRONG_ATTRIBUTE_TYPE",
1911 | "XML_ERROR_FILE_NOT_FOUND",
1912 | "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1913 | "XML_ERROR_FILE_READ_ERROR",
1914 | "XML_ERROR_ELEMENT_MISMATCH",
1915 | "XML_ERROR_PARSING_ELEMENT",
1916 | "XML_ERROR_PARSING_ATTRIBUTE",
1917 | "XML_ERROR_IDENTIFYING_TAG",
1918 | "XML_ERROR_PARSING_TEXT",
1919 | "XML_ERROR_PARSING_CDATA",
1920 | "XML_ERROR_PARSING_COMMENT",
1921 | "XML_ERROR_PARSING_DECLARATION",
1922 | "XML_ERROR_PARSING_UNKNOWN",
1923 | "XML_ERROR_EMPTY_DOCUMENT",
1924 | "XML_ERROR_MISMATCHED_ELEMENT",
1925 | "XML_ERROR_PARSING",
1926 | "XML_CAN_NOT_CONVERT_TEXT",
1927 | "XML_NO_TEXT_NODE"
1928 | };
1929 |
1930 |
1931 | XMLDocument::XMLDocument(bool processEntities, Whitespace whitespace) :
1932 | XMLNode(0),
1933 | _writeBOM(false),
1934 | _processEntities(processEntities),
1935 | _errorID(XML_SUCCESS),
1936 | _whitespace(whitespace),
1937 | _charBuffer(0)
1938 | {
1939 | // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1940 | _document = this;
1941 | }
1942 |
1943 |
1944 | XMLDocument::~XMLDocument()
1945 | {
1946 | Clear();
1947 | }
1948 |
1949 |
1950 | void XMLDocument::Clear()
1951 | {
1952 | DeleteChildren();
1953 |
1954 | #ifdef DEBUG
1955 | const bool hadError = Error();
1956 | #endif
1957 | ClearError();
1958 |
1959 | delete[] _charBuffer;
1960 | _charBuffer = 0;
1961 |
1962 | #if 0
1963 | _textPool.Trace("text");
1964 | _elementPool.Trace("element");
1965 | _commentPool.Trace("comment");
1966 | _attributePool.Trace("attribute");
1967 | #endif
1968 |
1969 | #ifdef DEBUG
1970 | if (!hadError) {
1971 | TIXMLASSERT(_elementPool.CurrentAllocs() == _elementPool.Untracked());
1972 | TIXMLASSERT(_attributePool.CurrentAllocs() == _attributePool.Untracked());
1973 | TIXMLASSERT(_textPool.CurrentAllocs() == _textPool.Untracked());
1974 | TIXMLASSERT(_commentPool.CurrentAllocs() == _commentPool.Untracked());
1975 | }
1976 | #endif
1977 | }
1978 |
1979 |
1980 | XMLElement* XMLDocument::NewElement(const char* name)
1981 | {
1982 | TIXMLASSERT(sizeof(XMLElement) == _elementPool.ItemSize());
1983 | XMLElement* ele = new (_elementPool.Alloc()) XMLElement(this);
1984 | ele->_memPool = &_elementPool;
1985 | ele->SetName(name);
1986 | return ele;
1987 | }
1988 |
1989 |
1990 | XMLComment* XMLDocument::NewComment(const char* str)
1991 | {
1992 | TIXMLASSERT(sizeof(XMLComment) == _commentPool.ItemSize());
1993 | XMLComment* comment = new (_commentPool.Alloc()) XMLComment(this);
1994 | comment->_memPool = &_commentPool;
1995 | comment->SetValue(str);
1996 | return comment;
1997 | }
1998 |
1999 |
2000 | XMLText* XMLDocument::NewText(const char* str)
2001 | {
2002 | TIXMLASSERT(sizeof(XMLText) == _textPool.ItemSize());
2003 | XMLText* text = new (_textPool.Alloc()) XMLText(this);
2004 | text->_memPool = &_textPool;
2005 | text->SetValue(str);
2006 | return text;
2007 | }
2008 |
2009 |
2010 | XMLDeclaration* XMLDocument::NewDeclaration(const char* str)
2011 | {
2012 | TIXMLASSERT(sizeof(XMLDeclaration) == _commentPool.ItemSize());
2013 | XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration(this);
2014 | dec->_memPool = &_commentPool;
2015 | dec->SetValue(str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"");
2016 | return dec;
2017 | }
2018 |
2019 |
2020 | XMLUnknown* XMLDocument::NewUnknown(const char* str)
2021 | {
2022 | TIXMLASSERT(sizeof(XMLUnknown) == _commentPool.ItemSize());
2023 | XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown(this);
2024 | unk->_memPool = &_commentPool;
2025 | unk->SetValue(str);
2026 | return unk;
2027 | }
2028 |
2029 | static FILE* callfopen(const char* filepath, const char* mode)
2030 | {
2031 | TIXMLASSERT(filepath);
2032 | TIXMLASSERT(mode);
2033 | #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2034 | FILE* fp = 0;
2035 | errno_t err = fopen_s(&fp, filepath, mode);
2036 | if (err) {
2037 | return 0;
2038 | }
2039 | #else
2040 | FILE* fp = fopen(filepath, mode);
2041 | #endif
2042 | return fp;
2043 | }
2044 |
2045 | void XMLDocument::DeleteNode(XMLNode* node) {
2046 | TIXMLASSERT(node);
2047 | TIXMLASSERT(node->_document == this);
2048 | if (node->_parent) {
2049 | node->_parent->DeleteChild(node);
2050 | }
2051 | else {
2052 | // Isn't in the tree.
2053 | // Use the parent delete.
2054 | // Also, we need to mark it tracked: we 'know'
2055 | // it was never used.
2056 | node->_memPool->SetTracked();
2057 | // Call the static XMLNode version:
2058 | XMLNode::DeleteNode(node);
2059 | }
2060 | }
2061 |
2062 |
2063 | XMLError XMLDocument::LoadFile(const char* filename)
2064 | {
2065 | Clear();
2066 | FILE* fp = callfopen(filename, "rb");
2067 | if (!fp) {
2068 | SetError(XML_ERROR_FILE_NOT_FOUND, filename, 0);
2069 | return _errorID;
2070 | }
2071 | LoadFile(fp);
2072 | fclose(fp);
2073 | return _errorID;
2074 | }
2075 |
2076 | // This is likely overengineered template art to have a check that unsigned long value incremented
2077 | // by one still fits into size_t. If size_t type is larger than unsigned long type
2078 | // (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
2079 | // -Wtype-limits warning. This piece makes the compiler select code with a check when a check
2080 | // is useful and code with no check when a check is redundant depending on how size_t and unsigned long
2081 | // types sizes relate to each other.
2082 | template
2083 | = sizeof(size_t))>
2084 | struct LongFitsIntoSizeTMinusOne {
2085 | static bool Fits(unsigned long value)
2086 | {
2087 | return value < (size_t)-1;
2088 | }
2089 | };
2090 |
2091 | template <>
2092 | struct LongFitsIntoSizeTMinusOne {
2093 | static bool Fits(unsigned long)
2094 | {
2095 | return true;
2096 | }
2097 | };
2098 |
2099 | XMLError XMLDocument::LoadFile(FILE* fp)
2100 | {
2101 | Clear();
2102 |
2103 | fseek(fp, 0, SEEK_SET);
2104 | if (fgetc(fp) == EOF && ferror(fp) != 0) {
2105 | SetError(XML_ERROR_FILE_READ_ERROR, 0, 0);
2106 | return _errorID;
2107 | }
2108 |
2109 | fseek(fp, 0, SEEK_END);
2110 | const long filelength = ftell(fp);
2111 | fseek(fp, 0, SEEK_SET);
2112 | if (filelength == -1L) {
2113 | SetError(XML_ERROR_FILE_READ_ERROR, 0, 0);
2114 | return _errorID;
2115 | }
2116 | TIXMLASSERT(filelength >= 0);
2117 |
2118 | if (!LongFitsIntoSizeTMinusOne<>::Fits(filelength)) {
2119 | // Cannot handle files which won't fit in buffer together with null terminator
2120 | SetError(XML_ERROR_FILE_READ_ERROR, 0, 0);
2121 | return _errorID;
2122 | }
2123 |
2124 | if (filelength == 0) {
2125 | SetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0);
2126 | return _errorID;
2127 | }
2128 |
2129 | const size_t size = filelength;
2130 | TIXMLASSERT(_charBuffer == 0);
2131 | _charBuffer = new char[size + 1];
2132 | size_t read = fread(_charBuffer, 1, size, fp);
2133 | if (read != size) {
2134 | SetError(XML_ERROR_FILE_READ_ERROR, 0, 0);
2135 | return _errorID;
2136 | }
2137 |
2138 | _charBuffer[size] = 0;
2139 |
2140 | Parse();
2141 | return _errorID;
2142 | }
2143 |
2144 |
2145 | XMLError XMLDocument::SaveFile(const char* filename, bool compact)
2146 | {
2147 | FILE* fp = callfopen(filename, "w");
2148 | if (!fp) {
2149 | SetError(XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0);
2150 | return _errorID;
2151 | }
2152 | SaveFile(fp, compact);
2153 | fclose(fp);
2154 | return _errorID;
2155 | }
2156 |
2157 |
2158 | XMLError XMLDocument::SaveFile(FILE* fp, bool compact)
2159 | {
2160 | // Clear any error from the last save, otherwise it will get reported
2161 | // for *this* call.
2162 | ClearError();
2163 | XMLPrinter stream(fp, compact);
2164 | Print(&stream);
2165 | return _errorID;
2166 | }
2167 |
2168 |
2169 | XMLError XMLDocument::Parse(const char* p, size_t len)
2170 | {
2171 | Clear();
2172 |
2173 | if (len == 0 || !p || !*p) {
2174 | SetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0);
2175 | return _errorID;
2176 | }
2177 | if (len == (size_t)(-1)) {
2178 | len = strlen(p);
2179 | }
2180 | TIXMLASSERT(_charBuffer == 0);
2181 | _charBuffer = new char[len + 1];
2182 | memcpy(_charBuffer, p, len);
2183 | _charBuffer[len] = 0;
2184 |
2185 | Parse();
2186 | if (Error()) {
2187 | // clean up now essentially dangling memory.
2188 | // and the parse fail can put objects in the
2189 | // pools that are dead and inaccessible.
2190 | DeleteChildren();
2191 | _elementPool.Clear();
2192 | _attributePool.Clear();
2193 | _textPool.Clear();
2194 | _commentPool.Clear();
2195 | }
2196 | return _errorID;
2197 | }
2198 |
2199 |
2200 | void XMLDocument::Print(XMLPrinter* streamer) const
2201 | {
2202 | if (streamer) {
2203 | Accept(streamer);
2204 | }
2205 | else {
2206 | XMLPrinter stdoutStreamer(stdout);
2207 | Accept(&stdoutStreamer);
2208 | }
2209 | }
2210 |
2211 |
2212 | void XMLDocument::SetError(XMLError error, const char* str1, const char* str2)
2213 | {
2214 | TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT);
2215 | _errorID = error;
2216 |
2217 | _errorStr1.Reset();
2218 | _errorStr2.Reset();
2219 |
2220 | if (str1)
2221 | _errorStr1.SetStr(str1);
2222 | if (str2)
2223 | _errorStr2.SetStr(str2);
2224 | }
2225 |
2226 | const char* XMLDocument::ErrorName() const
2227 | {
2228 | TIXMLASSERT(_errorID >= 0 && _errorID < XML_ERROR_COUNT);
2229 | const char* errorName = _errorNames[_errorID];
2230 | TIXMLASSERT(errorName && errorName[0]);
2231 | return errorName;
2232 | }
2233 |
2234 | void XMLDocument::PrintError() const
2235 | {
2236 | if (Error()) {
2237 | static const int LEN = 20;
2238 | char buf1[LEN] = { 0 };
2239 | char buf2[LEN] = { 0 };
2240 |
2241 | if (!_errorStr1.Empty()) {
2242 | TIXML_SNPRINTF(buf1, LEN, "%s", _errorStr1.GetStr());
2243 | }
2244 | if (!_errorStr2.Empty()) {
2245 | TIXML_SNPRINTF(buf2, LEN, "%s", _errorStr2.GetStr());
2246 | }
2247 |
2248 | // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2249 | // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2250 | TIXMLASSERT(0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX);
2251 | printf("XMLDocument error id=%d '%s' str1=%s str2=%s\n",
2252 | static_cast(_errorID), ErrorName(), buf1, buf2);
2253 | }
2254 | }
2255 |
2256 | void XMLDocument::Parse()
2257 | {
2258 | TIXMLASSERT(NoChildren()); // Clear() must have been called previously
2259 | TIXMLASSERT(_charBuffer);
2260 | char* p = _charBuffer;
2261 | p = XMLUtil::SkipWhiteSpace(p);
2262 | p = const_cast(XMLUtil::ReadBOM(p, &_writeBOM));
2263 | if (!*p) {
2264 | SetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0);
2265 | return;
2266 | }
2267 | ParseDeep(p, 0);
2268 | }
2269 |
2270 | XMLPrinter::XMLPrinter(FILE* file, bool compact, int depth) :
2271 | _elementJustOpened(false),
2272 | _firstElement(true),
2273 | _fp(file),
2274 | _depth(depth),
2275 | _textDepth(-1),
2276 | _processEntities(true),
2277 | _compactMode(compact)
2278 | {
2279 | for (int i = 0; i'] = true; // not required, but consistency is nice
2291 | _buffer.Push(0);
2292 | }
2293 |
2294 |
2295 | void XMLPrinter::Print(const char* format, ...)
2296 | {
2297 | va_list va;
2298 | va_start(va, format);
2299 |
2300 | if (_fp) {
2301 | vfprintf(_fp, format, va);
2302 | }
2303 | else {
2304 | const int len = TIXML_VSCPRINTF(format, va);
2305 | // Close out and re-start the va-args
2306 | va_end(va);
2307 | TIXMLASSERT(len >= 0);
2308 | va_start(va, format);
2309 | TIXMLASSERT(_buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0);
2310 | char* p = _buffer.PushArr(len) - 1; // back up over the null terminator.
2311 | TIXML_VSNPRINTF(p, len + 1, format, va);
2312 | }
2313 | va_end(va);
2314 | }
2315 |
2316 |
2317 | void XMLPrinter::PrintSpace(int depth)
2318 | {
2319 | for (int i = 0; i 0 && *q < ENTITY_RANGE) {
2336 | // Check for entities. If one is found, flush
2337 | // the stream up until the entity, write the
2338 | // entity, and keep looking.
2339 | if (flag[(unsigned char)(*q)]) {
2340 | while (p < q) {
2341 | const size_t delta = q - p;
2342 | // %.*s accepts type int as "precision"
2343 | const int toPrint = (INT_MAX < delta) ? INT_MAX : (int)delta;
2344 | Print("%.*s", toPrint, p);
2345 | p += toPrint;
2346 | }
2347 | bool entityPatternPrinted = false;
2348 | for (int i = 0; i");
2462 | }
2463 | else {
2464 | if (_textDepth < 0 && !compactMode) {
2465 | Print("\n");
2466 | PrintSpace(_depth);
2467 | }
2468 | Print("%s>", name);
2469 | }
2470 |
2471 | if (_textDepth == _depth) {
2472 | _textDepth = -1;
2473 | }
2474 | if (_depth == 0 && !compactMode) {
2475 | Print("\n");
2476 | }
2477 | _elementJustOpened = false;
2478 | }
2479 |
2480 |
2481 | void XMLPrinter::SealElementIfJustOpened()
2482 | {
2483 | if (!_elementJustOpened) {
2484 | return;
2485 | }
2486 | _elementJustOpened = false;
2487 | Print(">");
2488 | }
2489 |
2490 |
2491 | void XMLPrinter::PushText(const char* text, bool cdata)
2492 | {
2493 | _textDepth = _depth - 1;
2494 |
2495 | SealElementIfJustOpened();
2496 | if (cdata) {
2497 | Print("", text);
2498 | }
2499 | else {
2500 | PrintString(text, true);
2501 | }
2502 | }
2503 |
2504 | void XMLPrinter::PushText(int64_t value)
2505 | {
2506 | char buf[BUF_SIZE];
2507 | XMLUtil::ToStr(value, buf, BUF_SIZE);
2508 | PushText(buf, false);
2509 | }
2510 |
2511 | void XMLPrinter::PushText(int value)
2512 | {
2513 | char buf[BUF_SIZE];
2514 | XMLUtil::ToStr(value, buf, BUF_SIZE);
2515 | PushText(buf, false);
2516 | }
2517 |
2518 |
2519 | void XMLPrinter::PushText(unsigned value)
2520 | {
2521 | char buf[BUF_SIZE];
2522 | XMLUtil::ToStr(value, buf, BUF_SIZE);
2523 | PushText(buf, false);
2524 | }
2525 |
2526 |
2527 | void XMLPrinter::PushText(bool value)
2528 | {
2529 | char buf[BUF_SIZE];
2530 | XMLUtil::ToStr(value, buf, BUF_SIZE);
2531 | PushText(buf, false);
2532 | }
2533 |
2534 |
2535 | void XMLPrinter::PushText(float value)
2536 | {
2537 | char buf[BUF_SIZE];
2538 | XMLUtil::ToStr(value, buf, BUF_SIZE);
2539 | PushText(buf, false);
2540 | }
2541 |
2542 |
2543 | void XMLPrinter::PushText(double value)
2544 | {
2545 | char buf[BUF_SIZE];
2546 | XMLUtil::ToStr(value, buf, BUF_SIZE);
2547 | PushText(buf, false);
2548 | }
2549 |
2550 |
2551 | void XMLPrinter::PushComment(const char* comment)
2552 | {
2553 | SealElementIfJustOpened();
2554 | if (_textDepth < 0 && !_firstElement && !_compactMode) {
2555 | Print("\n");
2556 | PrintSpace(_depth);
2557 | }
2558 | _firstElement = false;
2559 | Print("", comment);
2560 | }
2561 |
2562 |
2563 | void XMLPrinter::PushDeclaration(const char* value)
2564 | {
2565 | SealElementIfJustOpened();
2566 | if (_textDepth < 0 && !_firstElement && !_compactMode) {
2567 | Print("\n");
2568 | PrintSpace(_depth);
2569 | }
2570 | _firstElement = false;
2571 | Print("%s?>", value);
2572 | }
2573 |
2574 |
2575 | void XMLPrinter::PushUnknown(const char* value)
2576 | {
2577 | SealElementIfJustOpened();
2578 | if (_textDepth < 0 && !_firstElement && !_compactMode) {
2579 | Print("\n");
2580 | PrintSpace(_depth);
2581 | }
2582 | _firstElement = false;
2583 | Print("", value);
2584 | }
2585 |
2586 |
2587 | bool XMLPrinter::VisitEnter(const XMLDocument& doc)
2588 | {
2589 | _processEntities = doc.ProcessEntities();
2590 | if (doc.HasBOM()) {
2591 | PushHeader(true, false);
2592 | }
2593 | return true;
2594 | }
2595 |
2596 |
2597 | bool XMLPrinter::VisitEnter(const XMLElement& element, const XMLAttribute* attribute)
2598 | {
2599 | const XMLElement* parentElem = 0;
2600 | if (element.Parent()) {
2601 | parentElem = element.Parent()->ToElement();
2602 | }
2603 | const bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2604 | OpenElement(element.Name(), compactMode);
2605 | while (attribute) {
2606 | PushAttribute(attribute->Name(), attribute->Value());
2607 | attribute = attribute->Next();
2608 | }
2609 | return true;
2610 | }
2611 |
2612 |
2613 | bool XMLPrinter::VisitExit(const XMLElement& element)
2614 | {
2615 | CloseElement(CompactMode(element));
2616 | return true;
2617 | }
2618 |
2619 |
2620 | bool XMLPrinter::Visit(const XMLText& text)
2621 | {
2622 | PushText(text.Value(), text.CData());
2623 | return true;
2624 | }
2625 |
2626 |
2627 | bool XMLPrinter::Visit(const XMLComment& comment)
2628 | {
2629 | PushComment(comment.Value());
2630 | return true;
2631 | }
2632 |
2633 | bool XMLPrinter::Visit(const XMLDeclaration& declaration)
2634 | {
2635 | PushDeclaration(declaration.Value());
2636 | return true;
2637 | }
2638 |
2639 |
2640 | bool XMLPrinter::Visit(const XMLUnknown& unknown)
2641 | {
2642 | PushUnknown(unknown.Value());
2643 | return true;
2644 | }
2645 |
2646 | } // namespace tinyxml2
--------------------------------------------------------------------------------