1/*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <boot/PathBlocklist.h>
8
9#include <stdlib.h>
10
11#include <algorithm>
12
13
14// #pragma mark - BlockedPath
15
16
17BlockedPath::BlockedPath()
18	:
19	fPath(NULL),
20	fLength(0),
21	fCapacity(0)
22{
23}
24
25
26BlockedPath::~BlockedPath()
27{
28	free(fPath);
29}
30
31
32bool
33BlockedPath::SetTo(const char* path)
34{
35	size_t length = strlen(path);
36	if (length > 0 && path[length - 1] == '/')
37		length--;
38
39	if (!_Resize(length, false))
40		return false;
41
42	if (length > 0) {
43		memcpy(fPath, path, length);
44		fPath[length] = '\0';
45	}
46
47	return true;
48}
49
50
51bool
52BlockedPath::Append(const char* component)
53{
54	size_t componentLength = strlen(component);
55	if (componentLength > 0 && component[componentLength - 1] == '/')
56		componentLength--;
57	if (componentLength == 0)
58		return true;
59
60	size_t oldLength = fLength;
61	size_t length = (fLength > 0 ? fLength + 1 : 0) + componentLength;
62	if (!_Resize(length, true))
63		return false;
64
65	if (oldLength > 0)
66		fPath[oldLength++] = '/';
67	memcpy(fPath + oldLength, component, componentLength);
68	return true;
69}
70
71
72bool
73BlockedPath::_Resize(size_t length, bool keepData)
74{
75	if (length == 0) {
76		free(fPath);
77		fPath = NULL;
78		fLength = 0;
79		fCapacity = 0;
80		return true;
81	}
82
83	if (length < fCapacity) {
84		fPath[length] = '\0';
85		fLength = length;
86		return true;
87	}
88
89	size_t capacity = std::max(length + 1, 2 * fCapacity);
90	capacity = std::max(capacity, size_t(32));
91
92	char* path;
93	if (fLength > 0 && keepData) {
94		path = (char*)realloc(fPath, capacity);
95		if (path == NULL)
96			return false;
97	} else {
98		path = (char*)malloc(capacity);
99		if (path == NULL)
100			return false;
101		free(fPath);
102	}
103
104	fPath = path;
105	fPath[length] = '\0';
106	fLength = length;
107	fCapacity = capacity;
108	return true;
109}
110
111
112// #pragma mark - PathBlocklist
113
114
115PathBlocklist::PathBlocklist()
116{
117}
118
119
120PathBlocklist::~PathBlocklist()
121{
122	MakeEmpty();
123}
124
125
126bool
127PathBlocklist::Add(const char* path)
128{
129	BlockedPath* blockedPath = _FindPath(path);
130	if (blockedPath != NULL)
131		return true;
132
133	blockedPath = new(std::nothrow) BlockedPath;
134	if (blockedPath == NULL || !blockedPath->SetTo(path)) {
135		delete blockedPath;
136		return false;
137	}
138
139	fPaths.Add(blockedPath);
140	return true;
141}
142
143
144void
145PathBlocklist::Remove(const char* path)
146{
147	BlockedPath* blockedPath = _FindPath(path);
148	if (blockedPath != NULL) {
149		fPaths.Remove(blockedPath);
150		delete blockedPath;
151	}
152}
153
154
155bool
156PathBlocklist::Contains(const char* path) const
157{
158	return _FindPath(path) != NULL;
159}
160
161
162void
163PathBlocklist::MakeEmpty()
164{
165	while (BlockedPath* blockedPath = fPaths.RemoveHead())
166		delete blockedPath;
167}
168
169
170BlockedPath*
171PathBlocklist::_FindPath(const char* path) const
172{
173	for (PathList::Iterator it = fPaths.GetIterator(); it.HasNext();) {
174		BlockedPath* blockedPath = it.Next();
175		if (*blockedPath == path)
176			return blockedPath;
177	}
178
179	return NULL;
180}
181