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