Skip to content

Commit e556829

Browse files
committed
Merge pull request #8 from tweakdeveloper/master
Added C++ compatibility
2 parents 052f19e + b98fb3f commit e556829

File tree

7 files changed

+250
-10
lines changed

7 files changed

+250
-10
lines changed

.travis.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
language: c
22
compiler:
33
- gcc
4+
- g++
45
before_install:
6+
- sudo apt-get update
57
- sudo apt-get install cmake valgrind
68
script:
7-
- mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DXML_PARSER_VERBOSE=On .. && make && ./test-xml && valgrind --tool=memcheck --leak-check=full --track-origins=yes -v ./test-xml
9+
- mkdir build && cd build
10+
- cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=gcc -DXML_PARSER_VERBOSE=On ..
11+
- make
12+
after_script: ../run-tests.sh
813

CMakeLists.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,15 @@ ADD_LIBRARY(xml STATIC
3232
# Build unit cases
3333
INCLUDE_DIRECTORIES(${SOURCE_DIRECTORY})
3434

35-
ADD_EXECUTABLE(test-xml
36-
${TEST_SOURCE_DIRECTORY}/test-xml
35+
ADD_EXECUTABLE(test-xml-c
36+
${TEST_SOURCE_DIRECTORY}/test-xml-c
3737
)
38-
TARGET_LINK_LIBRARIES(test-xml xml)
38+
TARGET_LINK_LIBRARIES(test-xml-c xml)
39+
40+
ADD_EXECUTABLE(test-xml-cpp
41+
${TEST_SOURCE_DIRECTORY}/test-xml-cpp
42+
)
43+
TARGET_LINK_LIBRARIES(test-xml-cpp xml)
3944

4045
FILE( COPY ${TEST_SOURCE_DIRECTORY}/test.xml
4146
DESTINATION ${PROJECT_BINARY_DIR}

run-tests.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
./test-xml-c
3+
./test-xml-cpp
4+
valgrind --tool=memcheck --leak-check=full --track-origins=yes -v ./test-xml-c
5+
valgrind --tool=memcheck --leak-check=full --track-origins=yes -v ./test-xml-cpp

src/xml.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,7 @@ struct xml_document* xml_open_document(FILE* source) {
729729
/**
730730
* [PUBLIC API]
731731
*/
732-
void xml_document_free(struct xml_document* document, _Bool free_buffer) {
732+
void xml_document_free(struct xml_document* document, bool free_buffer) {
733733
xml_node_free(document->root);
734734

735735
if (free_buffer) {

src/xml.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@
2929
*/
3030
#include <stdint.h>
3131
#include <string.h>
32+
#include <stdbool.h>
3233

33-
34+
#ifdef __cplusplus
35+
extern "C" {
36+
#endif
3437

3538
/**
3639
* Opaque structure holding the parsed xml document
@@ -84,7 +87,7 @@ struct xml_document* xml_open_document(FILE* source);
8487
* @param free_buffer iff true the internal buffer supplied via xml_parse_buffer
8588
* will be freed with the `free` system call
8689
*/
87-
void xml_document_free(struct xml_document* document, _Bool free_buffer);
90+
void xml_document_free(struct xml_document* document, bool free_buffer);
8891

8992

9093
/**
@@ -162,9 +165,9 @@ size_t xml_string_length(struct xml_string* string);
162165
*/
163166
void xml_string_copy(struct xml_string* string, uint8_t* buffer, size_t length);
164167

165-
166-
167-
168+
#ifdef __cplusplus
169+
}
170+
#endif
168171

169172
#endif
170173

File renamed without changes.

test/test-xml-cpp.cpp

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/**
2+
* Copyright (c) 2012 ooxi/xml.c
3+
* https://github.com/ooxi/xml.c
4+
*
5+
* This software is provided 'as-is', without any express or implied warranty.
6+
* In no event will the authors be held liable for any damages arising from the
7+
* use of this software.
8+
*
9+
* Permission is granted to anyone to use this software for any purpose,
10+
* including commercial applications, and to alter it and redistribute it
11+
* freely, subject to the following restrictions:
12+
*
13+
* 1. The origin of this software must not be misrepresented; you must not
14+
* claim that you wrote the original software. If you use this software in a
15+
* product, an acknowledgment in the product documentation would be
16+
* appreciated but is not required.
17+
*
18+
* 2. Altered source versions must be plainly marked as such, and must not be
19+
* misrepresented as being the original software.
20+
*
21+
* 3. This notice may not be removed or altered from any source distribution.
22+
*/
23+
24+
#include <iostream>
25+
#include <cstdlib>
26+
#include <cstdio>
27+
#include <xml.h>
28+
29+
/**
30+
* Will halt the program iff assertion fails
31+
*/
32+
static void _assert_that(bool condition, const char* message,
33+
const char* func, const char* file, int line) {
34+
if (!condition) {
35+
std::cerr << "Assertion failed: " << message << ", in " << func << " ("
36+
<< file << ":" << line << ")\n";
37+
exit(EXIT_FAILURE);
38+
}
39+
}
40+
41+
#define assert_that(condition, message) \
42+
_assert_that(condition, message, __func__, __FILE__, __LINE__)
43+
44+
/**
45+
* @return true iff xml string equals the c string
46+
*/
47+
static bool string_equals(struct xml_string* a, const char* b) {
48+
size_t a_length = xml_string_length(a);
49+
size_t b_length = strlen(b);
50+
uint8_t* a_buffer = new uint8_t[((a_length + 1) * sizeof(uint8_t))];
51+
xml_string_copy(a, a_buffer, a_length);
52+
a_buffer[a_length] = 0;
53+
if (a_length != b_length) {
54+
std::cerr << "string_equals: " << a_buffer << "#" << a_length << " <> "
55+
<< b << "#" << b_length << "\n";
56+
delete[] a_buffer;
57+
return false;
58+
}
59+
size_t i = 0; for (; i < a_length; ++i) {
60+
if (a_buffer[i] != b[i]) {
61+
std::cerr << "string_equals: " << a_buffer << " <> " << b << "\n";
62+
delete[] a_buffer;
63+
return false;
64+
}
65+
}
66+
delete[] a_buffer;
67+
return true;
68+
}
69+
70+
/**
71+
* Converts a static character array to an uint8_t data source
72+
*/
73+
#define SOURCE(source, content) \
74+
uint8_t* source = new uint8_t[strlen(content)]; \
75+
{ \
76+
const char* content_string = content; \
77+
memcpy(source, content_string, strlen(content) + 1); \
78+
}
79+
80+
/**
81+
* Tries to parse a simple document containing only one tag
82+
*/
83+
static void test_xml_parse_document_0() {
84+
SOURCE(source, "<Hello>World</Hello>");
85+
// uint8_t* source = malloc((1 + strlen("<Hello>World</Hello>")) *
86+
// sizeof(uint8_t));
87+
// {
88+
// const char* content_string = "<Hello>World</Hello>";
89+
// memcpy(source, content_string, strlen("<Hello>World</Hello>") + 1);
90+
// }
91+
struct xml_document* document = xml_parse_document(source,
92+
strlen((const char *)source));
93+
assert_that(document, "Could not parse document");
94+
struct xml_node* root = xml_document_root(document);
95+
assert_that(string_equals(xml_node_name(root), "Hello"),
96+
"root node name must be `Hello'");
97+
assert_that(string_equals(xml_node_content(root), "World"),
98+
"root node content must be `World'");
99+
xml_document_free(document, true);
100+
}
101+
102+
/**
103+
* Tries to parse a document containing multiple tags
104+
*/
105+
static void test_xml_parse_document_1() {
106+
SOURCE(source, ""
107+
"<Parent>\n"
108+
"\t<Child>\n"
109+
"\t\tFirst content\n"
110+
"\t</Child>\n"
111+
"\t<Child>\n"
112+
"\t\tSecond content\n"
113+
"\t</Child>\n"
114+
"</Parent>\n"
115+
);
116+
struct xml_document* document = xml_parse_document(source,
117+
strlen((const char *)source));
118+
assert_that(document, "Could not parse document");
119+
struct xml_node* root = xml_document_root(document);
120+
assert_that(string_equals(xml_node_name(root), "Parent"),
121+
"root node name must be `Parent'");
122+
assert_that(2 == xml_node_children(root), "root must have two children");
123+
struct xml_node* first_child = xml_node_child(root, 0);
124+
struct xml_node* second_child = xml_node_child(root, 1);
125+
assert_that(first_child && second_child,
126+
"Failed retrieving the children of root");
127+
struct xml_node* third_child = xml_node_child(root, 2);
128+
assert_that(!third_child, "root has a third child where non should be");
129+
assert_that(string_equals(xml_node_name(first_child), "Child"),
130+
"first_child node name must be `Child'");
131+
assert_that(string_equals(xml_node_content(first_child), "First content"),
132+
"first_child node content must be `First content'");
133+
assert_that(string_equals(xml_node_name(second_child), "Child"),
134+
"second_child node name must be `Child'");
135+
assert_that(string_equals(xml_node_content(second_child), "Second content"),
136+
"second_child node content must be `tSecond content'");
137+
xml_document_free(document, true);
138+
}
139+
140+
/**
141+
* Tests the eas functionality
142+
*/
143+
static void test_xml_parse_document_2() {
144+
SOURCE(source, ""
145+
"<Parent>\n"
146+
"\t<Child>\n"
147+
"\t\tFirst content\n"
148+
"\t</Child>\n"
149+
"\t<This><Is>\n"
150+
"<A><Test>Content A</Test></A>\n"
151+
"<B><Test>Content B</Test></B>\n"
152+
"\t</Is></This>\n"
153+
"\t<Child>\n"
154+
"\t\tSecond content\n"
155+
"\t</Child>\n"
156+
"</Parent>\n"
157+
);
158+
struct xml_document* document = xml_parse_document(source,
159+
strlen((const char *)source));
160+
assert_that(document, "Could not parse document");
161+
struct xml_node* root = xml_document_root(document);
162+
assert_that(string_equals(xml_node_name(root), "Parent"),
163+
"root node name must be `Parent'");
164+
assert_that(3 == xml_node_children(root),
165+
"root must have two children");
166+
struct xml_node* test_a = xml_easy_child(root, (uint8_t *)"This",
167+
(uint8_t *)"Is", (uint8_t *)"A", (uint8_t *)"Test", 0);
168+
assert_that(test_a, "Cannot find Parent/This/Is/A/Test");
169+
assert_that(string_equals(xml_node_content(test_a), "Content A"),
170+
"Content of Parent/This/Is/A/Test must be `Content A'");
171+
struct xml_node* test_b = xml_easy_child(root, (uint8_t *)"This",
172+
(uint8_t *)"Is", (uint8_t *)"B", (uint8_t *)"Test", 0);
173+
assert_that(test_b, "Cannot find Parent/This/Is/B/Test");
174+
assert_that(string_equals(xml_node_content(test_b), "Content B"),
175+
"Content of Parent/This/Is/B/Test must be `Content B'");
176+
struct xml_node* test_c = xml_easy_child(root, (uint8_t *)"This",
177+
(uint8_t *)"Is", (uint8_t *)"C", (uint8_t *)"Test", 0);
178+
assert_that(!test_c,
179+
"Must not find Parent/This/Is/C/Test because no such path exists");
180+
struct xml_node* must_be_null = xml_easy_child(root, (uint8_t *)"Child");
181+
assert_that(!must_be_null,
182+
"Parent/Child cannot be a valid expression, because there are two children "
183+
"named `Child' in `Parent'");
184+
uint8_t* name_is = xml_easy_name(xml_easy_child(root, (uint8_t *)"This",
185+
(uint8_t *)"Is", 0));
186+
assert_that(!strcmp((const char*)name_is, "Is"),
187+
"Name of Parent/This/Is must be `Is'");
188+
delete[] name_is;
189+
uint8_t* content_a = xml_easy_content(test_a);
190+
assert_that(!strcmp((const char*)content_a, "Content A"),
191+
"Content of Parent/This/Is/A/Test must be `Content A'");
192+
delete[] content_a;
193+
xml_document_free(document, true);
194+
}
195+
196+
/**
197+
* Tests the xml_open_document functionality
198+
*/
199+
static void test_xml_parse_document_3() {
200+
#define FILE_NAME "test.xml"
201+
FILE* handle = fopen(FILE_NAME, "rb");
202+
assert_that(handle, "Cannot open " FILE_NAME);
203+
struct xml_document* document = xml_open_document(handle);
204+
assert_that(document, "Cannot parse " FILE_NAME);
205+
struct xml_node* element = xml_easy_child(xml_document_root(document),
206+
(uint8_t *)"Element", (uint8_t *)"With", 0);
207+
assert_that(element, "Cannot find Document/Element/With");
208+
assert_that(string_equals(xml_node_content(element), "Child"),
209+
"Content of Document/Element/With must be `Child'");
210+
xml_document_free(document, true);
211+
#undef FILE_NAME
212+
}
213+
214+
int main(int argc, char **argv) {
215+
test_xml_parse_document_0();
216+
test_xml_parse_document_1();
217+
test_xml_parse_document_2();
218+
test_xml_parse_document_3();
219+
std::cout << "All tests passed :-)\n";
220+
exit(EXIT_SUCCESS);
221+
}
222+

0 commit comments

Comments
 (0)