Summary Files Commits Branches @commit @diff @stats
path: root / Year 1 / Object-oriented Programming / xml.cpp
blob: 720e8380bdef245ea15063435dfb6107596e8a7c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * This is a very simple, hard-coded and limited XML parser, which parses XML from file into local variable.
 * Made for illustrative purposes.
 */

#include <fstream>
#include <iostream>
#include <cstring>

class Tag {
public: // щото да не се занимавам с гетъри и сетъри
	char name[64];
	// char id[64];
	char value[64];

	Tag* children;
	unsigned length;
	unsigned count;

private:
	void copyFrom(const Tag& other) {
		strncpy(name, other.name, 64);
		strncpy(value, other.value, 64);
		children = new Tag[other.length];
		for (unsigned i = 0; i < other.count; i++)
			children[i] = other.children[i];
		length = other.length;
		count = other.count;
	}

	void free() {
		delete[] children;
	}

	void resize() {
		if (length == 0) length = 4;

		Tag* tmp = new Tag[length <<= 1];
		for (unsigned i = 0; i < count; i++)
			tmp[i] = children[i];
		delete[] children;
		children = tmp;
	}
public:
	void addChild(const Tag& child) {
		if (length == count)
			resize();
		children[count++] = child;
	}

	Tag() {
		children = nullptr;
		length = count = 0;
	}

	Tag(const Tag& other) {
		copyFrom(other);
	}

	Tag& operator=(const Tag& other) {
		if (this != &other) {
			free();
			copyFrom(other);
		}
		return *this;
	}

	~Tag() {
		free();
	}
};

void parseTag(Tag& root, std::ifstream& file) {
	Tag newTag;

	// Вземаме името на тага (все едно всичко между < и >)
	// важно: предполагаме, че вече сме минали < и от сега до > е само името на тага
	char buffer = '<';
	for (unsigned i = 0; i < 63 && file.peek() != '>'; i++) {
		buffer = file.get();
		newTag.name[i] = buffer;
		newTag.name[i + 1] = '\0';
	}
	file.get(); // ние сме на знак >, затова отиваме на следващия

	// ако следващия не е <, то имаме някаква стойност, която ще запазим
	for (unsigned i = 0; i < 63 && file.peek() != '<'; i++) {
		buffer = file.get();
		newTag.value[i] = buffer;
		newTag.value[i + 1] = '\0';
	}
	file.get(); // ние сме на знак <, затова отиваме на следващия

	// предишния знак е <, тоест, ако сегашния е /, то имаме </ и значи край на обекта
	// иначе, означава, че четем името на някое дете
	while (file.peek() != '/') {
		parseTag(newTag, file);
	}
	// значи, намираме се в затварящ таг (</ ... >), сега просто ще скипнем името му
	for (unsigned i = 0; file.peek() != '>'; i++)
		file.get();

	file.get(); // знаем, че сме на >, затова отиваме на следващия
	file.get(); // ако има съседни тагове, то в момента ще сме на <, затова и него го скипваме

	root.addChild(newTag);
}

void printTag(Tag& tag, unsigned level = 0) {
	for (unsigned i = 0; i < level; i++)
		std::cout << "  ";

	std::cout << "<" << tag.name << ">"  << " " << tag.value << std::endl;
	level++;
	for (unsigned i = 0; i < tag.count; i++)
		printTag(tag.children[i], level);
}

int main() {
	std::ifstream inFile("test.xml");
	inFile.get();

	Tag root;
	parseTag(root, inFile);
	printTag(root);

	inFile.close();
}