vfs: check userland buffers before reading them.
[haiku.git] / src / kits / package / PackageInfoStringBuilder.h
blob4e4c33d323da7c82623c58b9c2fb582807874012
1 /*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5 #ifndef PACKAGE_INFO_STRING_BUILDER_H
6 #define PACKAGE_INFO_STRING_BUILDER_H
9 #include <ctype.h>
11 #include <DataIO.h>
12 #include <package/PackageInfo.h>
15 namespace BPackageKit {
18 struct BPackageInfo::StringBuilder {
19 StringBuilder()
21 fData(),
22 fError(B_OK),
23 fBasePackage()
27 status_t Error() const
29 return fError;
32 status_t GetString(BString& _string) const
34 if (fError != B_OK) {
35 _string = BString();
36 return fError;
39 _string.SetTo((const char*)fData.Buffer(), fData.BufferLength());
40 return (size_t)_string.Length() == fData.BufferLength()
41 ? B_OK : B_NO_MEMORY;
44 template<typename Value>
45 StringBuilder& Write(const char* attribute, Value value)
47 if (_IsValueEmpty(value))
48 return *this;
50 _Write(attribute);
51 _Write('\t');
52 _WriteValue(value);
53 _Write('\n');
54 return *this;
57 StringBuilder& WriteFlags(const char* attribute, uint32 flags)
59 if ((flags & B_PACKAGE_FLAG_APPROVE_LICENSE) == 0
60 && (flags & B_PACKAGE_FLAG_SYSTEM_PACKAGE) == 0) {
61 return *this;
64 _Write(attribute);
65 _Write('\t');
67 if ((flags & B_PACKAGE_FLAG_APPROVE_LICENSE) == 0)
68 _Write(" approve_license");
69 if ((flags & B_PACKAGE_FLAG_SYSTEM_PACKAGE) == 0)
70 _Write(" system_package");
72 _Write('\n');
73 return *this;
76 StringBuilder& BeginRequires(const BString& basePackage)
78 fBasePackage = basePackage;
79 return *this;
82 StringBuilder& EndRequires()
84 fBasePackage.Truncate(0);
85 return *this;
88 private:
89 void _WriteValue(const char* value)
91 _WriteMaybeQuoted(value);
94 void _WriteValue(const BPackageVersion& value)
96 if (fError != B_OK)
97 return;
99 if (value.InitCheck() != B_OK) {
100 fError = B_BAD_VALUE;
101 return;
104 _Write(value.ToString());
107 void _WriteValue(const BStringList& value)
109 int32 count = value.CountStrings();
110 if (count == 1) {
111 _WriteMaybeQuoted(value.StringAt(0));
112 } else {
113 _Write("{\n", 2);
115 int32 count = value.CountStrings();
116 for (int32 i = 0; i < count; i++) {
117 _Write('\t');
118 _WriteMaybeQuoted(value.StringAt(i));
119 _Write('\n');
122 _Write('}');
126 template<typename Value>
127 void _WriteValue(const BObjectList<Value>& value)
129 // Note: The fBasePackage solution is disgusting, but any attempt of
130 // encapsulating the stringification via templates seems to result in
131 // an Internal Compiler Error with gcc 2.
133 _Write("{\n", 2);
135 int32 count = value.CountItems();
136 for (int32 i = 0; i < count; i++) {
137 _Write('\t');
138 _WriteListElement(value.ItemAt(i));
139 _Write('\n');
142 _Write('}');
145 template<typename Value>
146 void _WriteListElement(const Value* value)
148 _Write(value->ToString());
149 if (!fBasePackage.IsEmpty()
150 && value->Name() == fBasePackage) {
151 _Write(" base");
155 void _WriteListElement(const BGlobalWritableFileInfo* value)
157 _WriteMaybeQuoted(value->Path());
158 if (value->IsDirectory()) {
159 _Write(' ');
160 _Write("directory");
162 if (value->IsIncluded()) {
163 _Write(' ');
164 _Write(kWritableFileUpdateTypes[value->UpdateType()]);
168 void _WriteListElement(const BUserSettingsFileInfo* value)
170 _WriteMaybeQuoted(value->Path());
171 if (value->IsDirectory()) {
172 _Write(" directory");
173 } else if (!value->TemplatePath().IsEmpty()) {
174 _Write(" template ");
175 _WriteMaybeQuoted(value->TemplatePath());
179 void _WriteListElement(const BUser* value)
181 _WriteMaybeQuoted(value->Name());
183 if (!value->RealName().IsEmpty()) {
184 _Write(" real-name ");
185 _WriteMaybeQuoted(value->RealName());
188 if (!value->Home().IsEmpty()) {
189 _Write(" home ");
190 _WriteMaybeQuoted(value->Home());
193 if (!value->Shell().IsEmpty()) {
194 _Write(" shell ");
195 _WriteMaybeQuoted(value->Shell());
198 if (!value->Groups().IsEmpty()) {
199 _Write(" groups ");
200 BString groups = value->Groups().Join(" ");
201 if (groups.IsEmpty()) {
202 if (fError == B_OK)
203 fError = B_NO_MEMORY;
204 return;
206 _Write(groups);
210 static inline bool _IsValueEmpty(const char* value)
212 return value[0] == '\0';
215 static inline bool _IsValueEmpty(const BPackageVersion& value)
217 return false;
220 template<typename List>
221 static inline bool _IsValueEmpty(const List& value)
223 return value.IsEmpty();
226 void _WriteMaybeQuoted(const char* data)
228 // check whether quoting is needed
229 bool needsQuoting = false;
230 bool needsEscaping = false;
231 for (const char* it = data; *it != '\0'; it++) {
232 if (isalnum(*it) || *it == '.' || *it == '-' || *it == '_'
233 || *it == ':' || *it == '+') {
234 continue;
237 needsQuoting = true;
239 if (*it == '\t' || *it == '\n' || *it == '"' || *it == '\\') {
240 needsEscaping = true;
241 break;
245 if (!needsQuoting) {
246 _Write(data);
247 return;
250 // we need quoting
251 _Write('"');
253 // escape the string, if necessary
254 if (needsEscaping) {
255 const char* start = data;
256 const char* end = data;
257 while (*end != '\0') {
258 char replacement[2];
259 switch (*end) {
260 case '\t':
261 replacement[1] = 't';
262 break;
263 case '\n':
264 replacement[1] = 'n';
265 break;
266 case '"':
267 case '\\':
268 replacement[1] = *end;
269 break;
270 default:
271 end++;
272 continue;
275 if (start < end)
276 _Write(start, end - start);
278 replacement[0] = '\\';
279 _Write(replacement, 2);
280 start = ++end;
283 if (start < end)
284 _Write(start, end - start);
285 } else
286 _Write(data);
288 _Write('"');
291 inline void _Write(char data)
293 _Write(&data, 1);
296 inline void _Write(const char* data)
298 _Write(data, strlen(data));
301 inline void _Write(const BString& data)
303 _Write(data, data.Length());
306 void _Write(const void* data, size_t size)
308 if (fError == B_OK) {
309 ssize_t bytesWritten = fData.Write(data, size);
310 if (bytesWritten < 0)
311 fError = bytesWritten;
315 private:
316 BMallocIO fData;
317 status_t fError;
318 BString fBasePackage;
322 } // namespace BPackageKit
325 #endif // PACKAGE_INFO_STRING_BUILDER_H