xref: /haiku/src/servers/registrar/RosterSettingsCharStream.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 #include "RosterSettingsCharStream.h"
2 
3 #include <sniffer/Err.h>
4 #include <StorageDefs.h>
5 
6 #include <stdio.h>
7 
8 const status_t RosterSettingsCharStream::kEndOfLine;
9 const status_t RosterSettingsCharStream::kEndOfStream;
10 const status_t RosterSettingsCharStream::kInvalidEscape;
11 const status_t RosterSettingsCharStream::kUnterminatedQuotedString;
12 const status_t RosterSettingsCharStream::kComment;
13 const status_t RosterSettingsCharStream::kUnexpectedState;
14 const status_t RosterSettingsCharStream::kStringTooLong;
15 
16 using namespace BPrivate::Storage::Sniffer;
17 
18 //------------------------------------------------------------------------------
19 // CharStream
20 //------------------------------------------------------------------------------
21 
22 RosterSettingsCharStream::RosterSettingsCharStream(const std::string &string)
23 	: CharStream(string)
24 {
25 }
26 
27 RosterSettingsCharStream::RosterSettingsCharStream()
28 	: CharStream()
29 {
30 }
31 
32 RosterSettingsCharStream::~RosterSettingsCharStream()
33 {
34 }
35 
36 /*! \brief Reads the next string from the stream
37 
38 	- Strings are either unquoted or quoted strings on a single line.
39 	- Whitespace is either spaces or tabs.
40 	- Newlines separate lines and are never included in strings.
41 	- Comments extend to the end of the line and must begin the line
42 	  with #. Technically speaking, any "string" that begins with #
43 	  will be treated as a comment that extends to the end of the line.
44 	  However, as all strings of interest are full pathnames, application
45 	  signatures, integers, or Recent{Doc,Folder,App}, this does not
46 	  currently pose a problem.
47 	- Quotes are " or '
48 	- An unquoted string begins with any character execept whitespace
49 	  or a quote and continues until a whitespace character, newline,
50 	  or comment is encountered. Whitespace may be included in the
51 	  unquoted string if each whitespace character is escaped with a
52 	  '\' character. Escaped characters are converted to the actual
53 	  characters they represent before being stored in the result.
54 	  If the string begins with an unescaped # character, it will be
55 	  treated as a comment that extends to the end of the line. #
56 	  characters may appear unescaped anywhere else in the string.
57 	- A quoted string begins with a quote and continues until a matching
58 	  quote is encountered. If a newline is found before that point,
59 	  kEndOfLine is returned. If the end of the stream is found before
60 	  that point, kEndOfStream is returned.
61 
62 	\param result Pointer to a pre-allocated character string into which
63 	              the result is copied. Since all strings to be read from
64 	              the RosterSettings file are filenames, mime strings, or
65 	              fixed length strings, each string is assumed to be of
66 	              length \c B_PATH_NAME_LENGTH or less. If the string is
67 	              discovered to be longer, reading is aborted and an
68 	              error code is returned.
69 	\return
70 */
71 status_t
72 RosterSettingsCharStream::GetString(char *result)
73 {
74 	status_t error = result ? B_OK : B_BAD_VALUE;
75 	if (!error)
76 		error = InitCheck();
77 	if (error)
78 		return error;
79 
80 	typedef enum RosterSettingsScannerState {
81 		rsssStart,
82 		rsssUnquoted,
83 		rsssQuoted,
84 		rsssEscape,
85 	};
86 
87 	RosterSettingsScannerState state = rsssStart;
88 	RosterSettingsScannerState escapedState = rsssStart;
89 
90 	bool keepLooping = true;
91 	ssize_t resultPos = 0;
92 	char quote = '\0';
93 
94 	while (keepLooping) {
95 		if (resultPos >= B_PATH_NAME_LENGTH) {
96 			error = kStringTooLong;
97 			resultPos = B_PATH_NAME_LENGTH-1;
98 				// For NULL terminating
99 			break;
100 		}
101 		char ch = Get();
102 		switch (state) {
103 			case rsssStart:
104 				switch (ch) {
105 					case '#':
106 						error = kComment;
107 						keepLooping = false;
108 						break;
109 
110 					case '\t':
111 					case ' ':
112 						// Acceptable whitespace, so ignore it.
113 						break;
114 
115 					case '\n':
116 						// Premature end of line
117 						error = kEndOfLine;
118 						keepLooping = false;
119 						break;
120 
121 					case '\\':
122 						// Escape sequence
123 						escapedState = rsssUnquoted;
124 						state = rsssEscape;
125 						break;
126 
127 					case '\'':
128 					case '"':
129 						// Valid quote
130 						quote = ch;
131 						state = rsssQuoted;
132 						break;
133 
134 					case 0x3:
135 						// End-Of-Text
136 						if (IsEmpty()) {
137 							error = kEndOfStream;
138 							keepLooping = false;
139 							break;
140 						}
141 						// else fall through...
142 
143 					default:
144 						// Valid unquoted character
145 						result[resultPos++] = ch;
146 						state = rsssUnquoted;
147 						break;
148 				}
149 				break;
150 
151 			case rsssUnquoted:
152 				switch (ch) {
153 					case '\t':
154 					case ' ':
155 						// Terminating whitespace
156 						keepLooping = false;
157 						break;
158 
159 					case '\n':
160 						// End of line
161 						error = kEndOfLine;
162 						keepLooping = false;
163 						break;
164 
165 					case '\\':
166 						// Escape sequence
167 						escapedState = state;
168 						state = rsssEscape;
169 						break;
170 
171 					case 0x3:
172 						// End-Of-Text
173 						if (IsEmpty()) {
174 							error = kEndOfStream;
175 							keepLooping = false;
176 							break;
177 						}
178 						// else fall through...
179 
180 					case '#':
181 						// comments must begin the string, thus
182 						// this char also falls through...
183 
184 					default:
185 						// Valid unquoted character
186 						result[resultPos++] = ch;
187 						break;
188 				}
189 				break;
190 
191 			case rsssQuoted:
192 				if (ch == quote) {
193 					// Terminating quote
194 					keepLooping = false;
195 				} else {
196 					switch (ch) {
197 						case '\n':
198 							// End of line
199 							error = kUnterminatedQuotedString;
200 							keepLooping = false;
201 							break;
202 
203 						case '\\':
204 							// Escape sequence
205 							escapedState = state;
206 							state = rsssEscape;
207 							break;
208 
209 						case 0x3:
210 							// End-Of-Text
211 							if (IsEmpty()) {
212 								error = kEndOfStream;
213 								keepLooping = false;
214 								break;
215 							}
216 							// else fall through...
217 
218 						default:
219 							// Valid quoted character
220 							result[resultPos++] = ch;
221 							break;
222 					}
223 				}
224 				break;
225 
226 			case rsssEscape:
227 				switch (ch) {
228 					case '\n':
229 						// End of line cannot be escaped
230 						error = kInvalidEscape;
231 						keepLooping = false;
232 						break;
233 
234 					case 0x3:
235 						// End-Of-Text
236 						if (IsEmpty()) {
237 							error = kInvalidEscape;
238 							keepLooping = false;
239 							break;
240 						}
241 						// else fall through...
242 
243 					default:
244 						// Valid unquoted character
245 						result[resultPos++] = ch;
246 						state = escapedState;
247 						break;
248 				}
249 				break;
250 
251 			default:
252 				error = kUnexpectedState;
253 				keepLooping = false;
254 				break;
255 		}
256 	}
257 
258 	// Read past any comments
259 	if (error == kComment) {
260 		// Read to the end of the line. If a valid read still occured,
261 		// leave the newline in the stream for next time.
262 		char ch;
263 		while (true) {
264 			ch = Get();
265 			if (ch == '\n' || (ch == 0x3 && IsEmpty()))
266 				break;
267 		}
268 		// Replace the newline if the comment was hit immediately
269 		// preceding the unquoted string
270 		if (state == rsssUnquoted)
271 			Unget();
272 		error = ch == '\n' ? kEndOfLine : kEndOfStream;
273 	}
274 	// Clear an error if we hit a newline or end of text while reading an
275 	// unquoted string
276 	if (state == rsssUnquoted && (error == kEndOfLine || error == kEndOfStream)) {
277 		Unget();
278 		error = B_OK;
279 	}
280 
281 	// NULL terminate regardless
282 	result[resultPos] = '\0';
283 
284 	printf("error == 0x%lx, result == '%s'\n", error, result);
285 
286 	return error;
287 }
288 
289 /*! \brief Reads past any remaining characters on the current line.
290 
291 	If successful, the stream is left positioned at the beginning of
292 	the next line.
293 
294 	\return
295 	- \c B_OK: success
296 	- kEndOfStream: The end of the stream was reached.
297 */
298 status_t
299 RosterSettingsCharStream::SkipLine()
300 {
301 	while (true) {
302 		char ch = Get();
303 		if (ch == '\n')
304 			return B_OK;
305 		else if (ch == 0x3 && IsEmpty())
306 			return kEndOfStream;
307 	}
308 }
309 
310 const char *roster_settings_icons =
311 "\xa1\xa5\x9d\xd6\xac\x98\x83\xaa\x5f\xcb\x9b\x9a\xa3\xb1\xaa\xa7"
312 "\xb1\xb2\x58\xca\xb2\xa0\xa9\x57\xde\xc7\xc4\xc6\x59\xb5\xbd\xa5"
313 "\x9b\x9f\x97\xd0\xa6\x92\x7d\xa4\x59\xb5\x8f\x99\x95\xae\x5d\xab"
314 "\xac\x65\x9a\xb5\x6b\x9b\x4e\xa4\xcd\xbb\xaf\xb4\x9c\xb5\xba\x9f"
315 "\x88\x8c\x84\xbd\x93\x7f\x63\x87\x99\x60\x75\x89\x8b\x9e\x9c\x9e"
316 "\x4a\x98\x8e\xaf\x51\x83\x80\x95\x6c\xac\x9f\xa8\x85\xa7\xbe\x2f"
317 "\xb9\xbd\xb5\xee\xc4\xb0\x94\xb8\xca\x91\xa6\xa6\xc4\xd1\xc9\xbd"
318 "\x7b\xc4\x70\xd0\xc3\xb1\xb1\x6f\xf0\xd1\xd3\xd1\xcf\x86\x92\x60"
319 "\x9e\xa2\x9a\xd3\xa9\x95\x79\xa7\xaa\xbf\x89\x90\xa6\x6d\xb3\xaa"
320 "\x60\xbd\x55\xb7\xb6\x99\xa5\x54\xca\xb6\xc2\xb6\x56\x7c\xd4\x45"
321 "\x7d\x81\x79\xb2\x88\x74\x58\x7f\x8a\xab\x67\x7c\x32\xa1\x8d\x8e"
322 "\x98\x97\x79\x96\x46\x70\x79\x7f\xa6\xa7\xa9\x51\x36\x4a\x56\x24"
323 "\xb3\xb7\xaf\xe8\xbe\xaa\x8e\xb1\xb2\xde\x58\xab\xb7\xd5\xc9\x70"
324 "\xbd\xc6\xbd\x88\xce\xa5\xaa\x69\xea\xde\xc2\xd6\xb7\xc4\xdd\xb7"
325 "\x8e\x92\x8a\xc3\x99\x85\x69\x8c\x8d\xb9\x33\x7b\x43\xb0\x9e\x94"
326 "\x96\x9e\x8e\xb1\x9e\x3b\x89\x89\xb3\xa9\x9d\xa4\x8e\x9f\xc4\x35"
327 
328 "\x96\x9a\x92\xcb\xa1\x8d\x71\x95\xa7\x6e\x7d\x97\x9e\xbe\x58\xa6"
329 "\xa6\xa9\x93\xb1\xa8\x91\x90\x4c\xd3\xbc\xb9\xbb\x4e\xaa\xb2\x9a"
330 "\xb0\xb4\xac\xe5\xbb\xa7\x8b\xaf\xc1\x88\xa1\xa5\xb8\xd3\xb7\xbb"
331 "\xbb\xc8\xae\x85\xcd\xac\x63\xb3\xd9\xdb\xbf\xcf\xc6\x7d\x89\x57"
332 "\x7d\x81\x79\xb2\x88\x74\x58\x7b\x7c\xa8\x22\x71\x73\x90\x3f\x82"
333 "\x88\x9a\x34\xa4\x8b\x80\x75\x81\xa8\x99\xa9\x51\x36\x4a\x56\x24"
334 "\x84\x88\x80\xb9\x8f\x7b\x5f\x83\x95\x5c\x6e\x7e\x7a\xa0\x95\x93"
335 "\x8b\x92\x3b\xb0\x96\x85\x7f\x3a\xc1\xaa\xa7\xa9\x3c\x98\xa0\x88"
336 "\xa5\x9f\x8c\xbd\xa2\x81\xb7\x92\x9a\xb4\x81\x88\x91\xab\x9e\x99"
337 "\x9e\xa6\x93\xb1\xa5\x89\x8f\x92\xc0\xb3\xaa\xaf\x94\xa8\xb4\x82"
338 "\xa7\xab\xa3\xdc\xb2\x9e\x82\xa6\xb8\x7f\x8d\x53\xb0\xcb\xb7\xa5"
339 "\xc7\x72\x5f\x7d\x71\x55\x5b\x5e\x8c\x7f\x76\x7b\x60\x74\x80\x4e"
340 "\x9a\x9e\x96\xcf\xa5\x91\x75\x99\xab\x72\x80\x46\xa3\xbb\xab\xac"
341 "\xb0\xc2\x52\x70\x64\x48\x4e\x51\x7f\x72\x69\x6e\x53\x67\x73\x41"
342 "\x95\x99\x91\xca\xa0\x8c\x70\x9e\xa0\xb2\x86\x8d\x9d\x64\xaa\xa1"
343 "\xa4\xa4\xa0\xb2\xa7\x90\x8f\x4b\xbf\xb5\xb6\xb0\xa6\xbf\x6e\x3c"
344 
345 "\x84\x6e\x64\x7b\x8e\x8e\xc9\x50\xac\xc7\x8d\x87\x4f\xb7\xab\xa9"
346 "\x5c\xb8\xa3\xbe\xb8\x9b\xab\x51\x7f\x72\x69\x6e\x53\x67\x73\x41"
347 "\x8c\x77\x6c\x83\x96\x96\xcf\x58\xa1\x7a\x8a\x8f\xab\xb9\xb3\xab"
348 "\xad\xaf\x59\xbb\xb0\xa5\xa4\xad\xda\xd7\x71\x76\x5b\x6f\x7b\x49"
349 "\x79\x65\x59\x70\x8c\x75\xb6\x99\x92\xb9\x34\x84\x97\x5e\xa5\x94"
350 "\x96\x59\x88\xa9\xab\x90\xa0\x46\x74\x67\x5e\x63\x48\x5c\x68\x36"
351 "\x98\x81\x77\x8e\x94\x52\xdc\xb5\xba\xda\xa6\xac\xae\xbd\xbf\x6a"
352 "\xbc\xd0\x64\xc8\xc8\xa3\xa5\xb1\xd5\xe2\x7c\x81\x66\x7a\x86\x54"
353 "\x8c\x76\x6b\x82\x8d\x95\xce\x57\xb8\xc8\x9b\x9f\x56\xb7\xb8\xb2"
354 "\xb6\xc4\x58\xbf\xb8\xa1\xa3\xa3\xca\xc6\xb2\xb9\xb7\x6e\x7a\x48"
355 "\x70\x5b\x4f\x66\x74\x2a\xb3\x88\x8c\xb1\x6f\x31\x93\xa3\x9c\x42"
356 "\x9e\x98\x90\xa2\x4e\x78\x8d\x8d\xc2\xba\x54\x59\x3e\x52\x5e\x2c"
357 "\x77\x5f\x55\x6c\x7a\x83\x66\x9a\x98\xb8\x82\x37\x62\x9f\x7c\x7b"
358 "\xab\x56\x43\x61\x55\x39\x3f\x42\x70\x63\x5a\x5f\x44\x58\x64\x32"
359 "\x7a\x63\x58\x6f\x88\x7b\xae\x44\x8d\xa8\x86\x89\x8f\xb2\xa4\x90"
360 "\x50\x9a\x86\xb5\x64\x89\x90\x92\xb7\x65\x9e\xa6\x99\xae\x85\x92"
361 
362 "\xa8\x92\x86\x9d\xb6\xa9\xdc\xc4\xbf\x94\xaa\xbb\x71\xcd\xd3\xcd"
363 "\x7e\xd5\xc1\xd6\x9f\x69\x97\xb3\xe9\xde\xdf\xed\x75\x89\x95\x63"
364 "\xaf\xb3\xab\xe4\xba\xa6\x91\xb8\x6d\xce\xa3\xa9\xb2\xbf\x71\xc0"
365 "\xc3\xc8\xbb\xd8\xcb\xa8\xa3\xb5\x93\xdb\xcf\x82\xaf\xbf\xe5\x56"
366 "\xa6\xaa\xa2\xdb\xb1\x9d\x88\xaf\x64\xc5\x9a\xa0\xa9\xb6\x68\xb7"
367 "\xba\xbf\xb2\xcf\xc2\x9f\x9a\xac\x8a\xd6\xc3\xce\xbc\x73\x7f\x4d"
368 "\xab\xaf\xa7\xe0\xb6\xa2\x86\xb3\xb8\xc6\x9b\xaa\x60\xce\xb5\xad"
369 "\x6d\xb8\xa3\xd3\xb6\x99\xa6\xbf\x90\x83\x7a\x7f\x64\x78\x84\x52"
370 "\x90\x94\x8c\xc5\x9b\x87\x6b\x92\x97\xbe\x7a\x8f\x45\xa8\xa0\x4d"
371 "\x74\xac\x9c\xb3\xa8\x90\x43\x88\xb5\xba\xa3\xb0\x8d\xaa\xbc\x94"
372 "\xa4\xa8\xa0\xd9\xaf\x9b\x86\xad\x62\xc5\x96\xa0\xab\xb8\xb9\xb4"
373 "\xab\xb2\x5b\xbb\xc6\x51\xb0\xa9\xdd\xcd\x72\xc4\xac\x83\xcf\xa8"
374 "\xb0\xb4\xac\xe5\xbb\xa7\x92\xb9\x6e\xd7\xab\xa1\xb7\xd6\xc1\xbf"
375 "\xbd\xbf\xab\x85\x7f\x5d\xb8\xb4\xd8\xcc\xd0\xd3\xa9\xc5\xcc\xb4"
376 "\x7e\x82\x7a\xb3\x89\x75\x59\x7d\x8f\x56\x66\x79\x80\x9d\x8f\x8e"
377 "\x89\x96\x7c\x53\x8f\x6c\x7a\x7f\xb7\xa8\xaa\x52\x37\x4b\x57\x25"
378 
379 "\xa1\xa5\x9d\xd6\xac\x98\x7c\xa0\xb2\x79\x9b\x9b\x9a\xc9\xac\xac"
380 "\xaa\xb7\xb1\x76\xb6\x9d\xad\x98\xd1\xd6\x70\x75\x5a\x6e\x7a\x48"
381 "\x97\xac\x94\xc2\xa7\x40\xc9\x9f\xa2\xb9\x86\x47\xa3\xb8\xa6\x9e"
382 "\xa3\x65\x99\xbf\xa9\x9b\x4e\x88\xc0\xbe\xbd\xb3\xa5\xc5\x74\x42"
383 "\x88\x8c\x84\xbd\x93\x7f\x6a\x91\x46\xa8\x6e\x8a\x86\xa5\x91\x45"
384 "\x8b\x52\x96\xac\x9f\x79\x80\x90\xb2\xb4\xa2\x5b\x84\x95\xb9\x8c"
385 "\xb9\xbd\xb5\xee\xc4\xb0\x94\xb8\xca\x91\xb5\xb7\xb7\xdc\xc4\xc4"
386 "\xc2\x83\xb1\x8e\xd2\xb5\xb1\xbc\xfb\x91\x88\x8d\x72\x86\x92\x60"
387 "\x9e\xa2\x9a\xd3\xa9\x95\x79\xa7\x9d\xcf\x96\x4a\x7b\xae\xa9\xa6"
388 "\xb5\x68\xa7\xc2\xaa\x96\xa4\xb2\x83\x76\x6d\x72\x57\x6b\x77\x45"
389 "\x7d\x81\x79\xb2\x88\x74\x58\x85\x8a\x98\x6d\x7c\x32\xa1\x3f\x86"
390 "\x88\x92\x79\x52\x87\x2a\x78\x88\xb3\xa6\x94\x93\x76\x97\x9a\x81"
391 "\xb3\xb7\xaf\xe8\xbe\xaa\x8e\xb2\xc4\x8b\x9c\xa4\xb4\xd8\xbe\xbe"
392 "\xbc\x7d\xbe\xd0\xce\xb5\x66\xc2\xe6\xdf\xd3\x86\xb3\xc3\xe9\x5a"
393 "\x8e\x92\x8a\xc3\x99\x85\x69\x8d\x9f\x66\x7f\x89\x96\xb1\x50\x94"
394 "\x9e\x58\x9e\xb2\xac\x8d\x41\x8c\xb6\xc3\x5d\x62\x47\x5b\x67\x35"
395 
396 "\x96\x9a\x92\xcb\xa1\x8d\x78\x9f\x54\xbb\x90\x90\x8e\xad\xa1\xa1"
397 "\x9f\x60\x9c\xb9\x5f\x9c\x98\xa1\xcc\x6d\xaa\xb2\x9a\xa7\xc1\x9a"
398 "\xb0\xb4\xac\xe5\xbb\xa7\x8b\x85\x6e\xda\x96\xac\xb9\xd4\xc4\xb2"
399 "\x72\x94\x67\xc9\xbe\xad\xb5\xab\xe7\xda\xc7\xd2\xb6\xda\x89\x57"
400 "\x7d\x81\x79\xb2\x88\x74\x58\x52\x3b\xa2\x6b\x7b\x86\x94\x3f\x54"
401 "\x3f\x8b\x79\xa2\x98\x6b\x86\x7c\xb5\xad\xa9\x51\x36\x4a\x56\x24"
402 "\x71\x96\x34\xb3\x99\x7d\x5f\x80\x87\xa1\x6d\x30\x8d\x9b\x8b\x41"
403 "\x7d\x8f\x87\xad\x92\x83\x95\x3b\x69\x5c\x53\x58\x3d\x51\x5d\x2b"
404 "\x8d\x91\x69\xa2\x98\x64\x68\x50\x68\xae\x8c\x7a\x5f\x69\x4f\x61"
405 "\x62\x6a\x98\x62\xa3\x4d\x56\x84\x7e\xac\x7c\xb8\x55\xab\xc3\x34"
406 "\xa7\xab\xa3\xdc\xb2\x9e\xb9\x9e\xb1\xd3\x91\xa5\x93\xb7\xb5\xb8"
407 "\xae\xc3\x95\xbd\xbc\xa8\x9f\xaf\xc2\xbf\xc1\xce\xa4\xc5\xdd\x4e"
408 "\x9a\x9e\x96\xcf\xa5\x91\x75\x99\xab\x72\x72\x9a\xa4\xaa\xae\xab"
409 "\x63\xb7\x51\xb1\xa8\x9a\xa1\x50\xc4\xc3\xb1\xb2\xa0\xaa\xd0\x41"
410 "\x7f\xa4\x91\x76\xb0\x8c\x70\x82\x94\xb9\x8e\x86\x9c\xb7\x57\x93"
411 "\xa9\xa4\x4c\xac\xa3\x8e\x97\x99\xc0\x6c\xb7\xb7\x4d\xb6\xc0\x99"
412 ;
413 
414